# HG changeset patch # User lana # Date 1429291486 25200 # Node ID d729bb3d4ba92351fb727d3ee89c4f32b37cecad # Parent 1bdcfecae7b4cba7a7a009eae4b4f29c2f307e67# Parent f3b242bc61369704d8d169b814672cbce39fcd50 Merge diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/CompileDemos.gmk --- a/jdk/make/CompileDemos.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/CompileDemos.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -45,7 +45,7 @@ DEMO_CLOSED_SHARE_SRC := $(JDK_TOPDIR)/src/closed/demo/share DEMO_SOLARIS_SRC := $(JDK_TOPDIR)/src/demo/solaris DEMO_OS_TYPE_SRC := $(JDK_TOPDIR)/src/demo/$(OPENJDK_TARGET_OS_TYPE) -VERSION_INFO_RESOURCE := $(JDK_TOPDIR)/src/java.base/windows/native/common/version.rc +GLOBAL_VERSION_INFO_RESOURCE := $(JDK_TOPDIR)/src/java.base/windows/native/common/version.rc ################################################################################################## @@ -230,11 +230,8 @@ $$(wildcard $$(patsubst %, $(DEMO_SHARE_SRC)/jvmti/%/README.txt, $2)) \ $$(wildcard $$(patsubst %, $(DEMO_SHARE_SRC)/jvmti/%/sample.makefile.txt, $2)) BUILD_DEMO_JVMTI_$1_EXTRA_INC := $$(addprefix -I, $$(BUILD_DEMO_JVMTI_$1_EXTRA_SRC)) - BUILD_DEMO_JVMTI_$1_LANG := C - ifneq (, $4) - BUILD_DEMO_JVMTI_$1_LANG := $4 - endif ifeq (C++, $4) + BUILD_DEMO_JVMTI_$1_TOOLCHAIN := TOOLCHAIN_LINK_CXX $1_EXTRA_CXX := $(LDFLAGS_CXX_JDK) $(LIBCXX) endif @@ -254,7 +251,7 @@ # Remove the -incremental:no setting to get .ilk-files like in the old build. $$(eval $$(call SetupNativeCompilation,BUILD_DEMO_JVMTI_$1, \ SRC := $(DEMO_SHARE_SRC)/jvmti/$1 $$(BUILD_DEMO_JVMTI_$1_EXTRA_SRC), \ - LANG := $$(BUILD_DEMO_JVMTI_$1_LANG), \ + TOOLCHAIN := $$(BUILD_DEMO_JVMTI_$1_TOOLCHAIN), \ OPTIMIZATION := LOW, \ CXXFLAGS := $$($1_CXXFLAGS), \ DISABLED_WARNINGS_gcc := $(10), \ @@ -267,7 +264,7 @@ LDFLAGS_SUFFIX_windows := $6, \ LDFLAGS_SUFFIX_solaris := $7 -lc, \ LDFLAGS_SUFFIX_linux := $8, \ - VERSIONINFO_RESOURCE := $(VERSION_INFO_RESOURCE), \ + VERSIONINFO_RESOURCE := $(GLOBAL_VERSION_INFO_RESOURCE), \ RC_FLAGS := $$(RC_FLAGS) \ -D "JDK_FNAME=$1.dll" \ -D "JDK_INTERNAL_NAME=$1" \ @@ -398,7 +395,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBPOLLER, \ SRC := $(DEMO_SOLARIS_SRC)/jni/Poller, \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(SHARED_LIBRARY_FLAGS) \ -I$(SUPPORT_OUTPUTDIR)/demo/classes/jni/Poller, \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/Tools.gmk --- a/jdk/make/Tools.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/Tools.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -163,9 +163,7 @@ ifeq ($(OPENJDK_TARGET_OS), solaris) $(eval $(call SetupNativeCompilation,ADD_GNU_DEBUGLINK, \ SRC := $(JDK_TOPDIR)/make/src/native/add_gnu_debuglink, \ - LANG := C, \ - CC := $(BUILD_CC), \ - LDEXE := $(BUILD_LD), \ + TOOLCHAIN := TOOLCHAIN_BUILD, \ LDFLAGS := -lelf, \ OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/add_gnu_debuglink, \ OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \ @@ -173,9 +171,7 @@ $(eval $(call SetupNativeCompilation,FIX_EMPTY_SEC_HDR_FLAGS, \ SRC := $(JDK_TOPDIR)/make/src/native/fix_empty_sec_hdr_flags, \ - LANG := C, \ - CC := $(BUILD_CC), \ - LDEXE := $(BUILD_LD), \ + TOOLCHAIN := TOOLCHAIN_BUILD, \ LDFLAGS := -lelf, \ OBJECT_DIR := $(BUILDTOOLS_OUTPUTDIR)/objs/fix_empty_sec_hdr_flags, \ OUTPUT_DIR := $(BUILDTOOLS_OUTPUTDIR)/bin, \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/copy/Copy-java.base.gmk --- a/jdk/make/copy/Copy-java.base.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/copy/Copy-java.base.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -170,9 +170,6 @@ ifeq ($(OPENJDK_TARGET_OS), windows) POLICY_SRC_LIST += $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/conf/security/java.policy - ifndef OPENJDK - POLICY_SRC_LIST += $(JDK_TOPDIR)/src/closed/java.base/$(OPENJDK_TARGET_OS)/conf/security/java.policy - endif endif POLICY_SRC_LIST += $(POLICY_SRC) diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/copy/Copy-jdk.accessibility.gmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/copy/Copy-jdk.accessibility.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,47 @@ +# +# Copyright (c) 2104, 2015, 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. +# + +include CopyCommon.gmk + +################################################################################ + +ifeq ($(OPENJDK_TARGET_OS), windows) + TARGETS += $(INCLUDE_DST_OS_DIR)/bridge/AccessBridgeCallbacks.h \ + $(INCLUDE_DST_OS_DIR)/bridge/AccessBridgeCalls.h \ + $(INCLUDE_DST_OS_DIR)/bridge/AccessBridgePackages.h \ + $(INCLUDE_DST_OS_DIR)/bridge/AccessBridgeCalls.c \ + $(CONF_DST_DIR)/accessibility.properties + + $(INCLUDE_DST_OS_DIR)/bridge/%: \ + $(JDK_TOPDIR)/src/jdk.accessibility/windows/native/include/bridge/% + $(install-file) + + $(CONF_DST_DIR)/accessibility.properties: \ + $(JDK_TOPDIR)/src/jdk.accessibility/windows/conf/accessibility.properties + $(install-file) + +endif + +################################################################################ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/data/swingbeaninfo/SwingBeanInfo.template --- a/jdk/make/data/swingbeaninfo/SwingBeanInfo.template Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/data/swingbeaninfo/SwingBeanInfo.template Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -92,25 +92,38 @@ /** * @return an icon of the specified kind for @(BeanClassName) */ - public Image getIcon(int kind) { + public Image getIcon(final int kind) { Image i; switch (kind){ case ICON_COLOR_32x32: - i = loadImage("beaninfo/images/@(BeanClassName)Color32.gif"); - return ((i == null) ? loadImage("beaninfo/images/JComponentColor32.gif") : i); + i = loadStandardImage("beaninfo/images/@(BeanClassName)Color32.gif"); + return ((i == null) ? loadStandardImage("beaninfo/images/JComponentColor32.gif") : i); case ICON_COLOR_16x16: - i = loadImage("beaninfo/images/@(BeanClassName)Color16.gif"); - return ((i == null) ? loadImage("beaninfo/images/JComponentColor16.gif") : i); + i = loadStandardImage("beaninfo/images/@(BeanClassName)Color16.gif"); + return ((i == null) ? loadStandardImage("beaninfo/images/JComponentColor16.gif") : i); case ICON_MONO_32x32: - i = loadImage("beaninfo/images/@(BeanClassName)Mono32.gif"); - return ((i == null) ? loadImage("beaninfo/images/JComponentMono32.gif") : i); + i = loadStandardImage("beaninfo/images/@(BeanClassName)Mono32.gif"); + return ((i == null) ? loadStandardImage("beaninfo/images/JComponentMono32.gif") : i); case ICON_MONO_16x16: - i = loadImage("beaninfo/images/@(BeanClassName)Mono16.gif"); - return ((i == null) ? loadImage("beaninfo/images/JComponentMono16.gif") : i); + i = loadStandardImage("beaninfo/images/@(BeanClassName)Mono16.gif"); + return ((i == null) ? loadStandardImage("beaninfo/images/JComponentMono16.gif") : i); default: return super.getIcon(kind); } } + + /** + * This is a utility method to help in loading standard icon images. + * + * @param resourceName A pathname relative to the directory holding the + * class file of the current class + * @return an image object. May be null if the load failed. + * @see java.beans.SimpleBeanInfo#loadImage(String) + */ + private Image loadStandardImage(final String resourceName) { + return java.security.AccessController.doPrivileged( + (java.security.PrivilegedAction) () -> loadImage(resourceName)); + } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/gensrc/GensrcMisc.gmk --- a/jdk/make/gensrc/GensrcMisc.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/gensrc/GensrcMisc.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -63,9 +63,7 @@ $(eval $(call SetupNativeCompilation,BUILD_GENSRC_SOR_EXE, \ SRC := $(GENSRC_SOR_SRC), \ INCLUDE_FILES := $(GENSRC_SOR_SRC_FILE), \ - LANG := C, \ - CC := $(BUILD_CC), \ - LDEXE := $(BUILD_LD), \ + TOOLCHAIN := TOOLCHAIN_BUILD, \ OBJECT_DIR := $(GENSRC_SOR_BIN), \ OUTPUT_DIR := $(GENSRC_SOR_BIN), \ PROGRAM := genSocketOptionRegistry)) @@ -101,9 +99,7 @@ $(eval $(call SetupNativeCompilation,BUILD_GENSRC_UC_EXE, \ SRC := $(GENSRC_UC_SRC), \ INCLUDE_FILES := $(GENSRC_UC_SRC_FILE), \ - LANG := C, \ - CC := $(BUILD_CC), \ - LDEXE := $(BUILD_CC), \ + TOOLCHAIN := TOOLCHAIN_BUILD, \ CFLAGS := $(filter -D%, $(CFLAGS_JDKEXE)), \ OBJECT_DIR := $(GENSRC_UC_BIN), \ OUTPUT_DIR := $(GENSRC_UC_BIN), \ @@ -142,9 +138,7 @@ $(eval $(call SetupNativeCompilation,BUILD_GENSRC_SOL_EXE, \ SRC := $(GENSRC_SOL_SRC), \ INCLUDE_FILES := $(GENSRC_SOL_SRC_FILE), \ - LANG := C, \ - CC := $(BUILD_CC), \ - LDEXE := $(BUILD_CC), \ + TOOLCHAIN := TOOLCHAIN_BUILD, \ OBJECT_DIR := $(GENSRC_SOL_BIN), \ OUTPUT_DIR := $(GENSRC_SOL_BIN), \ PROGRAM := genSolarisConstants)) diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/launcher/Launcher-java.base.gmk --- a/jdk/make/launcher/Launcher-java.base.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/launcher/Launcher-java.base.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -103,7 +103,6 @@ $(eval $(call SetupNativeCompilation,BUILD_JEXEC, \ SRC := $(BUILD_JEXEC_SRC), \ INCLUDE_FILES := jexec.c, \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKEXE) \ $(BUILD_JEXEC_INC), \ @@ -144,7 +143,6 @@ $(eval $(call SetupNativeCompilation,BUILD_JSPAWNHELPER, \ SRC := $(BUILD_JSPAWNHELPER_SRC), \ INCLUDE_FILES := jspawnhelper.c, \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKEXE) $(JSPAWNHELPER_CFLAGS), \ LDFLAGS := $(LDFLAGS_JDKEXE) $(LINK_JSPAWNHELPER_FLAGS), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/launcher/Launcher-jdk.accessibility.gmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/launcher/Launcher-jdk.accessibility.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,61 @@ +# +# Copyright (c) 2014, 2015, 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. +# + +include LauncherCommon.gmk + +################################################################################ +# jabswitch + +ifeq ($(OPENJDK_TARGET_OS), windows) + + JABSWITCH_SRC := $(JDK_TOPDIR)/src/jdk.accessibility/windows/native/jabswitch + ACCESSBRIDGE_SRC := $(JDK_TOPDIR)/src/jdk.accessibility/windows/native/common + + $(eval $(call SetupNativeCompilation,BUILD_JABSWITCH, \ + SRC := $(JABSWITCH_SRC), \ + INCLUDE_FILES := jabswitch.cpp, \ + CFLAGS := $(filter-out -Zc:wchar_t-, $(CFLAGS_JDKEXE)) -Zc:wchar_t \ + -analyze- -Od -Gd -D_WINDOWS \ + -D_UNICODE -DUNICODE -RTC1 -EHsc, \ + DISABLED_WARNINGS_microsoft := 4267, \ + LDFLAGS := $(LDFLAGS_JDKEXE) \ + Advapi32.lib Version.lib User32.lib, \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jabswitch, \ + OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \ + PROGRAM := jabswitch, \ + DEBUG_SYMBOLS := true, \ + VERSIONINFO_RESOURCE := $(ACCESSBRIDGE_SRC)/AccessBridgeStatusWindow.RC, \ + RC_FLAGS := $(RC_FLAGS) \ + -D "JDK_FNAME=jabswitch.exe" \ + -D "JDK_INTERNAL_NAME=jabswitch" \ + -D "JDK_FTYPE=0x01L", \ + MANIFEST := $(JABSWITCH_SRC)/jabswitch.manifest, \ + MANIFEST_VERSION := $(JDK_VERSION_FOR_MANIFEST), \ + )) + + TARGETS += $(BUILD_JABSWITCH) +endif + +################################################################################ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/launcher/Launcher-jdk.pack200.gmk --- a/jdk/make/launcher/Launcher-jdk.pack200.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/launcher/Launcher-jdk.pack200.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -56,23 +56,28 @@ endif -UNPACKEXE_LANG := C ifeq ($(OPENJDK_TARGET_OS), solaris) - UNPACKEXE_LANG := C++ + UNPACKEXE_TOOLCHAIN := TOOLCHAIN_LINK_CXX endif +UNPACK_MAPFILE_DIR := $(JDK_TOPDIR)/make/mapfiles/libunpack +UNPACK_MAPFILE_PLATFORM_FILE := \ + $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200-$(OPENJDK_TARGET_OS)-$(OPENJDK_TARGET_CPU_ARCH) + # The linker on older SuSE distros (e.g. on SLES 10) complains with: # "Invalid version tag `SUNWprivate_1.1'. Only anonymous version tag is allowed in executable." # if feeded with a version script which contains named tags. ifeq ($(USING_BROKEN_SUSE_LD), yes) - UNPACK_MAPFILE = $(JDK_TOPDIR)/make/mapfiles/libunpack/mapfile-vers-unpack200.anonymous + UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200.anonymous +else ifneq ($(wildcard $(UNPACK_MAPFILE_PLATFORM_FILE)), ) + UNPACK_MAPFILE := $(UNPACK_MAPFILE_PLATFORM_FILE) else - UNPACK_MAPFILE = $(JDK_TOPDIR)/make/mapfiles/libunpack/mapfile-vers-unpack200 + UNPACK_MAPFILE := $(UNPACK_MAPFILE_DIR)/mapfile-vers-unpack200 endif $(eval $(call SetupNativeCompilation,BUILD_UNPACKEXE, \ SRC := $(UNPACKEXE_SRC), \ - LANG := $(UNPACKEXE_LANG), \ + TOOLCHAIN := $(UNPACKEXE_TOOLCHAIN), \ OPTIMIZATION := LOW, \ CFLAGS := $(UNPACKEXE_CFLAGS) $(CXXFLAGS_JDKEXE) -DFULL, \ CFLAGS_release := -DPRODUCT, \ @@ -96,7 +101,9 @@ -D "JDK_INTERNAL_NAME=unpack200" \ -D "JDK_FTYPE=0x1L", \ DEBUG_SYMBOLS := true, \ - MANIFEST := $(JDK_TOPDIR)/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest)) + MANIFEST := $(JDK_TOPDIR)/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest, \ + MANIFEST_VERSION := $(JDK_VERSION_FOR_MANIFEST), \ +)) ifneq ($(USE_EXTERNAL_LIBZ), true) diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/launcher/LauncherCommon.gmk --- a/jdk/make/launcher/LauncherCommon.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/launcher/LauncherCommon.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2015, 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 @@ -161,7 +161,6 @@ $(call SetupNativeCompilation,BUILD_LAUNCHER_$1, \ SRC := $(LAUNCHER_SRC), \ INCLUDE_FILES := main.c, \ - LANG := C, \ OPTIMIZATION := $$($1_OPTIMIZATION_ARG), \ CFLAGS := $$($1_CFLAGS) \ $(LAUNCHER_CFLAGS) \ @@ -199,7 +198,9 @@ -D "JDK_FTYPE=0x1L" \ $7, \ MANIFEST := $(JAVA_MANIFEST), \ - CODESIGN := $$($1_CODESIGN)) + MANIFEST_VERSION := $(JDK_VERSION_FOR_MANIFEST), \ + CODESIGN := $$($1_CODESIGN), \ + ) TARGETS += $$(BUILD_LAUNCHER_$1) diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Awt2dLibraries.gmk --- a/jdk/make/lib/Awt2dLibraries.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Awt2dLibraries.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -51,7 +51,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(BUILD_LIBMLIB_SRC), \ EXCLUDE_FILES := mlib_c_ImageBlendTable.c, \ - LANG := C, \ OPTIMIZATION := HIGHEST, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(BUILD_LIBMLIB_CFLAGS), \ @@ -124,7 +123,6 @@ LIBRARY := mlib_image_v, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBMLIB_IMAGE_V_SRC), \ - LANG := C, \ EXCLUDE_FILES := $(BUILD_LIBMLIB_IMAGE_V_EXFILES), \ OPTIMIZATION := HIGHEST, \ CFLAGS := -xarch=sparcvis \ @@ -204,8 +202,6 @@ LIBAWT_CFLAGS += -DMLIB_NO_LIBSUNMATH endif -LIBAWT_LANG := C - ifeq ($(OPENJDK_TARGET_OS), windows) LIBAWT_DIRS += $(JDK_TOPDIR)/src/java.desktop/share/native/common/font \ $(JDK_TOPDIR)/src/java.desktop/share/native/common/java2d/opengl \ @@ -222,7 +218,6 @@ awt/image/cvutils/img_colors.c \ # - LIBAWT_LANG := C++ LIBAWT_CFLAGS += -EHsc -DUNICODE -D_UNICODE ifeq ($(OPENJDK_TARGET_CPU_BITS), 64) LIBAWT_CFLAGS += -DMLIB_OS64BIT @@ -247,7 +242,6 @@ SRC := $(LIBAWT_DIRS), \ EXCLUDES := $(LIBAWT_EXCLUDES), \ EXCLUDE_FILES := $(LIBAWT_EXFILES), \ - LANG := $(LIBAWT_LANG), \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_CFLAGS), \ DISABLED_WARNINGS_gcc := sign-compare unused-result maybe-uninitialized \ @@ -355,7 +349,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBAWT_XAWT_DIRS), \ EXCLUDES := $(LIBAWT_XAWT_EXCLUDES), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBAWT_XAWT_CFLAGS) \ $(X_CFLAGS), \ @@ -413,7 +406,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBLCMS_SRC), \ INCLUDE_FILES := $(BUILD_LIBLCMS_INCLUDE_FILES), \ - LANG := C, \ OPTIMIZATION := HIGHEST, \ CFLAGS := $(filter-out -xc99=%none, $(CFLAGS_JDKLIB)) \ $(SHARED_LIBRARY_FLAGS) $(LIBLCMS_CPPFLAGS) \ @@ -496,7 +488,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJAVAJPEG_SRC), \ INCLUDE_FILES := $(BUILD_LIBJAVAJPEG_INCLUDE_FILES), \ - LANG := C, \ OPTIMIZATION := HIGHEST, \ CFLAGS := $(CFLAGS_JDKLIB) $(addprefix -I, $(LIBJAVAJPEG_SRC)) \ $(LIBJAVA_HEADER_FLAGS) \ @@ -564,7 +555,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBAWT_HEADLESS_DIRS), \ EXCLUDES := $(LIBAWT_HEADLESS_EXCLUDES), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ -DHEADLESS=true \ @@ -651,7 +641,7 @@ SRC := $(LIBFONTMANAGER_SRC), \ EXCLUDE_FILES := $(LIBFONTMANAGER_EXCLUDE_FILES) \ AccelGlyphCache.c, \ - LANG := C++, \ + TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBFONTMANAGER_CFLAGS), \ CXXFLAGS := $(CXXFLAGS_JDKLIB) $(LIBFONTMANAGER_CFLAGS), \ OPTIMIZATION := $(LIBFONTMANAGER_OPTIMIZATION), \ @@ -712,7 +702,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJAWT_SRC), \ INCLUDE_FILES := $(LIBJAWT_INCLUDE_FILES), \ - LANG := C++, \ OPTIMIZATION := LOW, \ CFLAGS := $(CXXFLAGS_JDKLIB) \ -EHsc -DUNICODE -D_UNICODE \ @@ -771,7 +760,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJAWT_SRC), \ INCLUDE_FILES := $(JAWT_FILES), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(LIBJAWT_CFLAGS), \ @@ -889,7 +877,6 @@ SRC := $(LIBSPLASHSCREEN_DIRS), \ EXCLUDE_FILES := imageioJPEG.c jpegdecoder.c pngtest.c, \ EXCLUDES := $(LIBSPLASHSCREEN_EXCLUDES), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(LIBSPLASHSCREEN_CFLAGS) $(CFLAGS_JDKLIB) \ $(GIFLIB_CFLAGS) $(LIBJPEG_CFLAGS) $(PNG_CFLAGS), \ @@ -958,7 +945,6 @@ LIBRARY := awt_lwawt, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBAWT_LWAWT_DIRS), \ - LANG := C, \ INCLUDE_FILES := $(LIBAWT_LWAWT_FILES), \ EXCLUDE_FILES := $(LIBAWT_LWAWT_EXFILES), \ EXCLUDES := $(LIBAWT_LWAWT_EXCLUDES), \ @@ -1008,7 +994,6 @@ LIBRARY := osxui, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(JDK_TOPDIR)/src/java.desktop/macosx/native/libosxui, \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ -I$(JDK_TOPDIR)/src/java.desktop/macosx/native/libosxui \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/CoreLibraries.gmk --- a/jdk/make/lib/CoreLibraries.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/CoreLibraries.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -43,7 +43,6 @@ STATIC_LIBRARY := fdlibm, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE), \ SRC := $(LIBFDLIBM_SRC), \ - LANG := C, \ OPTIMIZATION := $(BUILD_LIBFDLIBM_OPTIMIZATION), \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBFDLIBM_CFLAGS), \ CFLAGS_windows_debug := -DLOGGING, \ @@ -62,7 +61,6 @@ LIBRARY := fdlibm, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libfdlibm, \ SRC := $(LIBFDLIBM_SRC), \ - LANG := C, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBFDLIBM_CFLAGS), \ LDFLAGS := -nostdlib -r -arch x86_64, \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libfdlibm, \ @@ -93,7 +91,6 @@ LIBRARY := verify, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(JDK_TOPDIR)/src/java.base/share/native/libverify, \ - LANG := C, \ OPTIMIZATION := $(LIBVERIFY_OPTIMIZATION), \ CFLAGS := $(CFLAGS_JDKLIB), \ DISABLED_WARNINGS_microsoft := 4244 4267, \ @@ -146,7 +143,6 @@ LIBRARY := java, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJAVA_SRC_DIRS), \ - LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(LIBJAVA_CFLAGS), \ @@ -206,7 +202,6 @@ $(eval $(call SetupNativeCompilation,BUILD_LIBZIP, \ LIBRARY := zip, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ - LANG := C, \ OPTIMIZATION := LOW, \ SRC := $(JDK_TOPDIR)/src/java.base/share/native/libzip, \ EXCLUDES := $(LIBZIP_EXCLUDES), \ @@ -314,7 +309,6 @@ SRC := $(LIBJLI_SRC_DIRS), \ EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \ EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \ - LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(LIBJLI_CFLAGS), \ DISABLED_WARNINGS_solstudio := E_ASM_DISABLES_OPTIMIZATION, \ @@ -363,7 +357,6 @@ SRC := $(LIBJLI_SRC_DIRS), \ EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \ EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \ - LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS), \ ARFLAGS := $(ARFLAGS), \ @@ -383,7 +376,6 @@ SRC := $(LIBJLI_SRC_DIRS), \ EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \ EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \ - LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBJLI_CFLAGS), \ LDFLAGS := -nostdlib -r, \ @@ -403,7 +395,6 @@ SRC := $(LIBJLI_SRC_DIRS), \ EXCLUDE_FILES := $(LIBJLI_EXCLUDE_FILES), \ EXTRA_FILES := $(LIBJLI_EXTRA_FILES), \ - LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(STATIC_LIBRARY_FLAGS) $(LIBJLI_CFLAGS), \ ARFLAGS := $(ARFLAGS), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-java.instrument.gmk --- a/jdk/make/lib/Lib-java.instrument.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-java.instrument.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -57,7 +57,6 @@ LIBRARY := instrument, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBINSTRUMENT_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(LIBINSTRUMENT_CFLAGS) $(CFLAGS_WARNINGS_ARE_ERRORS), \ CFLAGS_debug := -DJPLIS_LOGGING, \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-java.management.gmk --- a/jdk/make/lib/Lib-java.management.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-java.management.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -72,7 +72,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(BUILD_LIBMANAGEMENT_SRC), \ EXCLUDE_FILES := $(BUILD_LIBMANAGEMENT_EXCLUDES), \ - LANG := C, \ OPTIMIZATION := $(LIBMANAGEMENT_OPTIMIZATION), \ CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) $(BUILD_LIBMANAGEMENT_CFLAGS), \ MAPFILE := $(LIBMANAGEMENT_MAPFILE), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-java.prefs.gmk --- a/jdk/make/lib/Lib-java.prefs.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-java.prefs.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -37,7 +37,6 @@ LIBRARY := prefs, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBPREF_SRC_DIRS), \ - LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(CFLAGS_JDKLIB) $(addprefix -I, $(LIBPREF_SRC_DIRS)) \ $(LIBJAVA_HEADER_FLAGS), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-java.security.jgss.gmk --- a/jdk/make/lib/Lib-java.security.jgss.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-java.security.jgss.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -36,7 +36,6 @@ LIBRARY := j2gss, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJ2GSS_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(addprefix -I, $(LIBJ2GSS_SRC)) \ $(LIBJAVA_HEADER_FLAGS) \ @@ -79,7 +78,6 @@ LIBRARY := $(BUILD_LIBKRB5_NAME), \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(BUILD_LIBKRB5_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(addprefix -I, $(BUILD_LIBKRB5_SRC)) \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-java.smartcardio.gmk --- a/jdk/make/lib/Lib-java.smartcardio.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-java.smartcardio.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -37,7 +37,6 @@ LIBRARY := j2pcsc, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJ2PCSC_SRC), \ - LANG := C, \ CFLAGS_unix := -D__sun_jdk, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(LIBJ2PCSC_CPPFLAGS), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.accessibility.gmk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/lib/Lib-jdk.accessibility.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,135 @@ +# +# Copyright (c) 2014, 2015, 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. +# + +include LibCommon.gmk + +################################################################################ + +ifeq ($(OPENJDK_TARGET_OS), windows) + + ROOT_SRCDIR := $(JDK_TOPDIR)/src/jdk.accessibility/windows/native + JAVA_AB_SRCDIR := $(ROOT_SRCDIR)/libjavaaccessbridge $(ROOT_SRCDIR)/common + WIN_AB_SRCDIR := $(ROOT_SRCDIR)/libwindowsaccessbridge $(ROOT_SRCDIR)/common + SYSINFO_SRCDIR := $(ROOT_SRCDIR)/libjabsysinfo + ACCESSBRIDGE_CFLAGS := -I$(SUPPORT_OUTPUTDIR)/headers/jdk.accessibility \ + -I$(JDK_TOPDIR)/src/java.desktop/windows/native/include \ + -I$(JDK_TOPDIR)/src/java.desktop/share/native/include + + define SetupJavaDLL + # Parameter 1 Suffix + # Parameter 2 ACCESSBRIDGE_ARCH_ suffix + + $(call SetupNativeCompilation,BUILD_JAVAACCESSBRIDGE$1, \ + LIBRARY = javaaccessbridge$1, \ + OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ + SRC := $(JAVA_AB_SRCDIR), \ + OPTIMIZATION := LOW, \ + CFLAGS := $(CFLAGS_JDKLIB) $(ACCESSBRIDGE_CFLAGS) \ + $(addprefix -I,$(JAVA_AB_SRCDIR)) \ + -I$(JDK_TOPDIR)/src/jdk.accessibility/windows/native/include/bridge \ + -DACCESSBRIDGE_ARCH_$2, \ + LDFLAGS := $(LDFLAGS_JDKLIB) kernel32.lib user32.lib gdi32.lib \ + winspool.lib comdlg32.lib advapi32.lib shell32.lib \ + $(SUPPORT_OUTPUTDIR)/native/java.desktop/libjawt/jawt.lib \ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib \ + -subsystem:windows, \ + VERSIONINFO_RESOURCE := $(ROOT_SRCDIR)/common/AccessBridgeStatusWindow.rc, \ + RC_FLAGS := $(RC_FLAGS) \ + -D "JDK_FNAME=javaaccessbridge$1.dll" \ + -D "JDK_INTERNAL_NAME=javaaccessbridge$1" \ + -D "JDK_FTYPE=0x02L", \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjavaaccessbridge$1, \ + DEBUG_SYMBOLS := true) + + $$(BUILD_JAVAACCESSBRIDGE$1): $(SUPPORT_OUTPUTDIR)/native/java.desktop/libjawt/jawt.lib + + TARGETS += $$(BUILD_JAVAACCESSBRIDGE$1) + endef + + define SetupWinDLL + # Parameter 1 Suffix + # Parameter 2 ACCESSBRIDGE_ARCH_ suffix + $(call SetupNativeCompilation,BUILD_WINDOWSACCESSBRIDGE$1, \ + LIBRARY = windowsaccessbridge$1, \ + OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ + SRC := $(WIN_AB_SRCDIR), \ + OPTIMIZATION := LOW, \ + CFLAGS := $(filter-out -MD, $(CFLAGS_JDKLIB)) -MT $(ACCESSBRIDGE_CFLAGS) \ + $(addprefix -I,$(WIN_AB_SRCDIR)) \ + -I$(JDK_TOPDIR)/src/jdk.accessibility/windows/native/include/bridge \ + -DACCESSBRIDGE_ARCH_$2, \ + LDFLAGS := $(LDFLAGS_JDKLIB) kernel32.lib user32.lib gdi32.lib \ + winspool.lib comdlg32.lib advapi32.lib shell32.lib \ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib \ + -subsystem:windows \ + -def:$(ROOT_SRCDIR)/libwindowsaccessbridge/WinAccessBridge.DEF, \ + VERSIONINFO_RESOURCE := $(ROOT_SRCDIR)/common/AccessBridgeStatusWindow.rc, \ + RC_FLAGS := $(RC_FLAGS) \ + -D "JDK_FNAME=windowsaccessbridge$1.dll" \ + -D "JDK_INTERNAL_NAME=windowsaccessbridge$1" \ + -D "JDK_FTYPE=0x02L", \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libwindowsaccessbridge$1, \ + DEBUG_SYMBOLS := true) + + TARGETS += $$(BUILD_WINDOWSACCESSBRIDGE$1) + + endef + + define SetupAccessBridgeSysInfo + + $(call SetupNativeCompilation,BUILD_ACCESSBRIDGESYSINFO, \ + LIBRARY = jabsysinfo, \ + OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ + SRC := $(SYSINFO_SRCDIR), \ + OPTIMIZATION := LOW, \ + CFLAGS := $(CFLAGS_JDKLIB) $(ACCESSBRIDGE_CFLAGS), \ + LDFLAGS := $(LDFLAGS_JDKLIB) \ + -subsystem:windows -machine:I386, \ + VERSIONINFO_RESOURCE := $(ROOT_SRCDIR)/common/AccessBridgeStatusWindow.rc, \ + RC_FLAGS := $(RC_FLAGS) \ + -D "JDK_FNAME=jabsysinfo.dll" \ + -D "JDK_INTERNAL_NAME=jabsysinfo" \ + -D "JDK_FTYPE=0x02L", \ + OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/lib/libjabsysinfo, \ + DEBUG_SYMBOLS := true) + + TARGETS += $$(BUILD_ACCESSBRIDGESYSINFO) + + endef + + ifeq ($(OPENJDK_TARGET_CPU_BITS), 32) + $(eval $(call SetupAccessBridgeSysInfo)) + $(eval $(call SetupJavaDLL,-32,32)) + $(eval $(call SetupJavaDLL,,LEGACY)) + $(eval $(call SetupWinDLL,-32,32)) + $(eval $(call SetupWinDLL,,LEGACY)) + else + $(eval $(call SetupJavaDLL,,64)) + $(eval $(call SetupWinDLL,-64,64)) + endif + +endif + +################################################################################ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.attach.gmk --- a/jdk/make/lib/Lib-jdk.attach.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.attach.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -32,7 +32,6 @@ LIBRARY := attach, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(call FindSrcDirsForLib, jdk.attach, attach), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) \ -I$(SUPPORT_OUTPUTDIR)/headers/jdk.attach \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.crypto.ec.gmk --- a/jdk/make/lib/Lib-jdk.crypto.ec.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.crypto.ec.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -47,7 +47,7 @@ LIBRARY := sunec, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBSUNEC_SRC), \ - LANG := C++, \ + TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ OPTIMIZATION := LOW, \ CFLAGS := $(filter-out $(ECC_JNI_SOLSPARC_FILTER), $(CFLAGS_JDKLIB)) \ $(BUILD_LIBSUNEC_FLAGS) \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.crypto.mscapi.gmk --- a/jdk/make/lib/Lib-jdk.crypto.mscapi.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.crypto.mscapi.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -35,7 +35,6 @@ LIBRARY := sunmscapi, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBSUNMSCAPI_SRC), \ - LANG := C++, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ -I$(LIBSUNMSCAPI_SRC), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.crypto.pkcs11.gmk --- a/jdk/make/lib/Lib-jdk.crypto.pkcs11.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.crypto.pkcs11.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -34,7 +34,6 @@ LIBRARY := j2pkcs11, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJ2PKCS11_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(addprefix -I, $(LIBJ2PKCS11_SRC)) \ $(LIBJAVA_HEADER_FLAGS) \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.crypto.ucrypto.gmk --- a/jdk/make/lib/Lib-jdk.crypto.ucrypto.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.crypto.ucrypto.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -35,7 +35,6 @@ LIBRARY := j2ucrypto, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJ2UCRYPTO_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(addprefix -I, $(LIBJ2UCRYPTO_SRC)), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.deploy.osx.gmk --- a/jdk/make/lib/Lib-jdk.deploy.osx.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.deploy.osx.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -35,7 +35,6 @@ LIBRARY := AppleScriptEngine, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBAPPLESCRIPTENGINE_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ -I$(LIBAPPLESCRIPTENGINE_SRC) \ @@ -68,7 +67,6 @@ LIBRARY := osx, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBOSX_DIRS), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(LIBOSX_CFLAGS), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.hprof.agent.gmk --- a/jdk/make/lib/Lib-jdk.hprof.agent.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.hprof.agent.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -45,7 +45,6 @@ LIBRARY := hprof, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(BUILD_LIBHPROF_SRC), \ - LANG := C, \ OPTIMIZATION := $(LIBHPROF_OPTIMIZATION), \ CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) \ $(BUILD_LIBHPROF_CFLAGS), \ @@ -75,7 +74,6 @@ LIBRARY := java_crw_demo, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJAVA_CRW_DEMO_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) \ $(addprefix -I, $(LIBJAVA_CRW_DEMO_SRC)), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.jdi.gmk --- a/jdk/make/lib/Lib-jdk.jdi.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.jdi.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -43,7 +43,6 @@ LIBRARY := dt_shmem, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBDT_SHMEM_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) -DUSE_MMAP \ $(LIBDT_SHMEM_CPPFLAGS), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.jdwp.agent.gmk --- a/jdk/make/lib/Lib-jdk.jdwp.agent.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.jdwp.agent.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -40,7 +40,6 @@ LIBRARY := dt_socket, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBDT_SOCKET_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_CFLAGS_WARNINGS_ARE_ERRORS) -DUSE_MMAP \ $(LIBDT_SOCKET_CPPFLAGS), \ @@ -77,7 +76,6 @@ LIBRARY := jdwp, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJDWP_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(CFLAGS_WARNINGS_ARE_ERRORS) -DJDWP_LOGGING \ $(LIBJDWP_CPPFLAGS) \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.pack200.gmk --- a/jdk/make/lib/Lib-jdk.pack200.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.pack200.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -32,7 +32,7 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(JDK_TOPDIR)/src/jdk.pack200/share/native/libunpack \ $(JDK_TOPDIR)/src/jdk.pack200/share/native/common-unpack, \ - LANG := C++, \ + TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ OPTIMIZATION := LOW, \ CFLAGS := $(CXXFLAGS_JDKLIB) \ -DNO_ZLIB -DUNPACK_JNI -DFULL \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.sctp.gmk --- a/jdk/make/lib/Lib-jdk.sctp.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.sctp.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -41,7 +41,6 @@ LIBRARY := sctp, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(JDK_TOPDIR)/src/jdk.sctp/$(OPENJDK_TARGET_OS_TYPE)/native/libsctp, \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ -I $(JDK_TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libnio/ch \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/Lib-jdk.security.auth.gmk --- a/jdk/make/lib/Lib-jdk.security.auth.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/Lib-jdk.security.auth.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -42,7 +42,6 @@ LIBRARY := $(LIBJAAS_NAME), \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(call FindSrcDirsForLib, jdk.security.auth, jaas), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/jdk.security.auth, \ MAPFILE := $(LIBJAAS_MAPFILE), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/NetworkingLibraries.gmk --- a/jdk/make/lib/NetworkingLibraries.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/NetworkingLibraries.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -29,7 +29,6 @@ LIBRARY := net, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBNET_SRC_DIRS), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) -I$(SUPPORT_OUTPUTDIR)/headers/java.base \ $(LIBJAVA_HEADER_FLAGS) $(addprefix -I, $(LIBNET_SRC_DIRS)), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/NioLibraries.gmk --- a/jdk/make/lib/NioLibraries.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/NioLibraries.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -65,7 +65,6 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(BUILD_LIBNIO_SRC), \ EXCLUDE_FILES := $(BUILD_LIBNIO_EXFILES), \ - LANG := C, \ OPTIMIZATION := HIGH, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(BUILD_LIBNIO_CFLAGS), \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/PlatformLibraries.gmk --- a/jdk/make/lib/PlatformLibraries.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/PlatformLibraries.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -33,7 +33,6 @@ LIBRARY := osxapp, \ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBOSXAPP_SRC), \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(addprefix -I, $(LIBOSXAPP_SRC)) \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/lib/SoundLibraries.gmk --- a/jdk/make/lib/SoundLibraries.gmk Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/lib/SoundLibraries.gmk Fri Apr 17 10:24:46 2015 -0700 @@ -35,8 +35,6 @@ LIBJSOUND_SRC_FILES := Utilities.c Platform.c -LIBJSOUND_LANG := C - EXTRA_SOUND_JNI_LIBS := LIBJSOUND_MIDIFILES := \ @@ -81,7 +79,7 @@ endif # OPENJDK_TARGET_OS aix ifeq ($(OPENJDK_TARGET_OS), macosx) - LIBJSOUND_LANG := C++ + LIBJSOUND_TOOLCHAIN := TOOLCHAIN_LINK_CXX LIBJSOUND_CFLAGS += -DX_PLATFORM=X_MACOSX \ -DUSE_PORTS=TRUE \ -DUSE_DAUDIO=TRUE \ @@ -124,7 +122,7 @@ OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \ SRC := $(LIBJSOUND_SRC_DIRS), \ INCLUDE_FILES := $(LIBJSOUND_SRC_FILES), \ - LANG := $(LIBJSOUND_LANG), \ + TOOLCHAIN := $(LIBJSOUND_TOOLCHAIN), \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(LIBJSOUND_CFLAGS), \ @@ -169,7 +167,6 @@ PLATFORM_API_LinuxOS_ALSA_MidiOut.c \ PLATFORM_API_LinuxOS_ALSA_MidiUtils.c \ PLATFORM_API_LinuxOS_ALSA_Ports.c, \ - LANG := C, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) $(ALSA_CFLAGS) \ $(LIBJSOUND_CFLAGS) \ @@ -201,7 +198,6 @@ SRC := $(LIBJSOUND_SRC_DIRS), \ INCLUDE_FILES := Utilities.c $(LIBJSOUND_DAUDIOFILES) \ PLATFORM_API_WinOS_DirectSound.cpp, \ - LANG := C++, \ OPTIMIZATION := LOW, \ CFLAGS := $(CFLAGS_JDKLIB) \ $(LIBJSOUND_CFLAGS) \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/mapfiles/launchers/mapfile-x86_64 --- a/jdk/make/mapfiles/launchers/mapfile-x86_64 Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/mapfiles/launchers/mapfile-x86_64 Fri Apr 17 10:24:46 2015 -0700 @@ -34,6 +34,14 @@ _environ; __environ_lock; + # These are needed by the c runtime in SS12u4 + ___Argv; + __xargv; + __xargc; + _start; + __longdouble_used; + _lib_version; + local: *; }; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/mapfiles/libunpack/mapfile-vers-unpack200-solaris-sparc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/mapfiles/libunpack/mapfile-vers-unpack200-solaris-sparc Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,41 @@ +# +# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# Define library interface. + +SUNWprivate_1.1 { + global: + # These are needed by the c runtime in SS12u4 + _environ; + __environ_lock; + ___Argv; + __xargv; + __xargc; + _start; + _lib_version; + + local: + *; +}; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/mapfiles/libunpack/mapfile-vers-unpack200-solaris-x86 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/make/mapfiles/libunpack/mapfile-vers-unpack200-solaris-x86 Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,42 @@ +# +# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# This code is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# Define library interface. + +SUNWprivate_1.1 { + global: + # These are needed by the c runtime in SS12u4 + _environ; + __environ_lock; + ___Argv; + __xargv; + __xargc; + _start; + __longdouble_used; + _lib_version; + + local: + *; +}; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/make/src/classes/build/tools/module/ext.modules --- a/jdk/make/src/classes/build/tools/module/ext.modules Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/make/src/classes/build/tools/module/ext.modules Fri Apr 17 10:24:46 2015 -0700 @@ -4,7 +4,7 @@ java.transaction java.xml.bind java.xml.ws -jdk.accessbridge +jdk.accessibility jdk.crypto.ec jdk.crypto.mscapi jdk.crypto.pkcs11 diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java --- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -350,7 +350,7 @@ switch (mode) { case MODE_SIGN: data = padding.pad(buffer, 0, bufOfs); - return RSACore.rsa(data, privateKey); + return RSACore.rsa(data, privateKey, true); case MODE_VERIFY: byte[] verifyBuffer = RSACore.convert(buffer, 0, bufOfs); data = RSACore.rsa(verifyBuffer, publicKey); @@ -360,7 +360,7 @@ return RSACore.rsa(data, publicKey); case MODE_DECRYPT: byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); - data = RSACore.rsa(decryptBuffer, privateKey); + data = RSACore.rsa(decryptBuffer, privateKey, false); return padding.unpad(data); default: throw new AssertionError("Internal error"); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java --- a/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/ref/Finalizer.java Fri Apr 17 10:24:46 2015 -0700 @@ -28,6 +28,7 @@ import java.security.PrivilegedAction; import java.security.AccessController; import sun.misc.JavaLangAccess; +import sun.misc.ManagedLocalsThread; import sun.misc.SharedSecrets; import sun.misc.VM; @@ -126,7 +127,7 @@ for (ThreadGroup tgn = tg; tgn != null; tg = tgn, tgn = tg.getParent()); - Thread sft = new Thread(tg, proc, "Secondary finalizer"); + Thread sft = new ManagedLocalsThread(tg, proc, "Secondary finalizer"); sft.start(); try { sft.join(); @@ -185,7 +186,7 @@ }}}); } - private static class FinalizerThread extends Thread { + private static class FinalizerThread extends ManagedLocalsThread { private volatile boolean running; FinalizerThread(ThreadGroup g) { super(g, "Finalizer"); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/java/lang/ref/Reference.java --- a/jdk/src/java.base/share/classes/java/lang/ref/Reference.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/lang/ref/Reference.java Fri Apr 17 10:24:46 2015 -0700 @@ -27,6 +27,7 @@ import sun.misc.Cleaner; import sun.misc.JavaLangRefAccess; +import sun.misc.ManagedLocalsThread; import sun.misc.SharedSecrets; /** @@ -126,7 +127,7 @@ /* High-priority thread to enqueue pending References */ - private static class ReferenceHandler extends Thread { + private static class ReferenceHandler extends ManagedLocalsThread { private static void ensureClassInitialized(Class clazz) { try { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java --- a/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java Fri Apr 17 10:24:46 2015 -0700 @@ -70,6 +70,7 @@ import static java.time.temporal.ChronoField.OFFSET_SECONDS; import static java.time.temporal.ChronoField.SECOND_OF_MINUTE; import static java.time.temporal.ChronoField.YEAR; +import static java.time.temporal.ChronoField.ERA; import java.lang.ref.SoftReference; import java.math.BigDecimal; @@ -84,6 +85,7 @@ import java.time.ZoneOffset; import java.time.chrono.ChronoLocalDate; import java.time.chrono.Chronology; +import java.time.chrono.Era; import java.time.chrono.IsoChronology; import java.time.format.DateTimeTextProvider.LocaleStore; import java.time.temporal.ChronoField; @@ -3131,6 +3133,16 @@ return context.setParsedField(field, entry.getValue(), position, position + itText.length()); } } + if (field == ERA && !context.isStrict()) { + // parse the possible era name from era.toString() + List eras = chrono.eras(); + for (Era era : eras) { + String name = era.toString(); + if (context.subSequenceEquals(name, 0, parseText, position, name.length())) { + return context.setParsedField(field, era.getValue(), position, position + name.length()); + } + } + } if (context.isStrict()) { return ~position; } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/misc/GC.java --- a/jdk/src/java.base/share/classes/sun/misc/GC.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/misc/GC.java Fri Apr 17 10:24:46 2015 -0700 @@ -82,8 +82,7 @@ */ public static native long maxObjectInspectionAge(); - - private static class Daemon extends Thread { + private static class Daemon extends ManagedLocalsThread { public void run() { for (;;) { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/misc/InnocuousThread.java --- a/jdk/src/java.base/share/classes/sun/misc/InnocuousThread.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/misc/InnocuousThread.java Fri Apr 17 10:24:46 2015 -0700 @@ -26,32 +26,37 @@ package sun.misc; import java.security.AccessControlContext; +import java.security.AccessController; import java.security.ProtectionDomain; +import java.security.PrivilegedAction; +import java.util.concurrent.atomic.AtomicInteger; /** * A thread that has no permissions, is not a member of any user-defined * ThreadGroup and supports the ability to erase ThreadLocals. - * - * @implNote Based on the implementation of InnocuousForkJoinWorkerThread. */ -public final class InnocuousThread extends Thread { +public final class InnocuousThread extends ManagedLocalsThread { private static final Unsafe UNSAFE; - private static final ThreadGroup THREADGROUP; + private static final ThreadGroup INNOCUOUSTHREADGROUP; private static final AccessControlContext ACC; - private static final long THREADLOCALS; - private static final long INHERITABLETHREADLOCALS; private static final long INHERITEDACCESSCONTROLCONTEXT; + private static final long CONTEXTCLASSLOADER; + + private static final AtomicInteger threadNumber = new AtomicInteger(1); public InnocuousThread(Runnable target) { - super(THREADGROUP, target, "anInnocuousThread"); - UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC); - eraseThreadLocals(); + this(INNOCUOUSTHREADGROUP, target, + "InnocuousThread-" + threadNumber.getAndIncrement()); } - @Override - public ClassLoader getContextClassLoader() { - // always report system class loader - return ClassLoader.getSystemClassLoader(); + public InnocuousThread(Runnable target, String name) { + this(INNOCUOUSTHREADGROUP, target, name); + } + + public InnocuousThread(ThreadGroup group, Runnable target, String name) { + super(group, target, name); + UNSAFE.putOrderedObject(this, INHERITEDACCESSCONTROLCONTEXT, ACC); + UNSAFE.putOrderedObject(this, CONTEXTCLASSLOADER, ClassLoader.getSystemClassLoader()); } @Override @@ -61,7 +66,11 @@ @Override public void setContextClassLoader(ClassLoader cl) { - throw new SecurityException("setContextClassLoader"); + // Allow clearing of the TCCL to remove the reference to the system classloader. + if (cl == null) + super.setContextClassLoader(null); + else + throw new SecurityException("setContextClassLoader"); } // ensure run method is run only once @@ -75,14 +84,6 @@ } } - /** - * Drops all thread locals (and inherited thread locals). - */ - public void eraseThreadLocals() { - UNSAFE.putObject(this, THREADLOCALS, null); - UNSAFE.putObject(this, INHERITABLETHREADLOCALS, null); - } - // Use Unsafe to access Thread group and ThreadGroup parent fields static { try { @@ -95,12 +96,10 @@ Class tk = Thread.class; Class gk = ThreadGroup.class; - THREADLOCALS = UNSAFE.objectFieldOffset - (tk.getDeclaredField("threadLocals")); - INHERITABLETHREADLOCALS = UNSAFE.objectFieldOffset - (tk.getDeclaredField("inheritableThreadLocals")); INHERITEDACCESSCONTROLCONTEXT = UNSAFE.objectFieldOffset (tk.getDeclaredField("inheritedAccessControlContext")); + CONTEXTCLASSLOADER = UNSAFE.objectFieldOffset + (tk.getDeclaredField("contextClassLoader")); long tg = UNSAFE.objectFieldOffset(tk.getDeclaredField("group")); long gp = UNSAFE.objectFieldOffset(gk.getDeclaredField("parent")); @@ -113,7 +112,10 @@ break; group = parent; } - THREADGROUP = new ThreadGroup(group, "InnocuousThreadGroup"); + final ThreadGroup root = group; + INNOCUOUSTHREADGROUP = AccessController.doPrivileged( + (PrivilegedAction) () -> + { return new ThreadGroup(root, "InnocuousThreadGroup"); }); } catch (Exception e) { throw new Error(e); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/misc/ManagedLocalsThread.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/sun/misc/ManagedLocalsThread.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. 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.misc; + +/** + * A thread that has it's thread locals, and inheritable thread + * locals erased on construction. + */ +public class ManagedLocalsThread extends Thread { + private static final Unsafe UNSAFE; + private static final long THREAD_LOCALS; + private static final long INHERITABLE_THREAD_LOCALS; + + public ManagedLocalsThread() { + eraseThreadLocals(); + } + + public ManagedLocalsThread(Runnable target) { + super(target); + eraseThreadLocals(); + } + + public ManagedLocalsThread(String name) { + super(name); + eraseThreadLocals(); + } + + public ManagedLocalsThread(Runnable target, String name) { + super(target, name); + eraseThreadLocals(); + } + + public ManagedLocalsThread(ThreadGroup group, String name) { + super(group, name); + eraseThreadLocals(); + } + + public ManagedLocalsThread(ThreadGroup group, Runnable target, String name) { + super(group, target, name); + eraseThreadLocals(); + } + + /** + * Drops all thread locals (and inherited thread locals). + */ + public final void eraseThreadLocals() { + UNSAFE.putObject(this, THREAD_LOCALS, null); + UNSAFE.putObject(this, INHERITABLE_THREAD_LOCALS, null); + } + + static { + UNSAFE = Unsafe.getUnsafe(); + Class t = Thread.class; + try { + THREAD_LOCALS = UNSAFE.objectFieldOffset + (t.getDeclaredField("threadLocals")); + INHERITABLE_THREAD_LOCALS = UNSAFE.objectFieldOffset + (t.getDeclaredField("inheritableThreadLocals")); + } catch (Exception e) { + throw new Error(e); + } + } +} + diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/misc/RequestProcessor.java --- a/jdk/src/java.base/share/classes/sun/misc/RequestProcessor.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/misc/RequestProcessor.java Fri Apr 17 10:24:46 2015 -0700 @@ -77,7 +77,7 @@ */ public static synchronized void startProcessing() { if (dispatcher == null) { - dispatcher = new Thread(new RequestProcessor(), "Request Processor"); + dispatcher = new ManagedLocalsThread(new RequestProcessor(), "Request Processor"); dispatcher.setPriority(Thread.NORM_PRIORITY + 2); dispatcher.start(); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/misc/Signal.java --- a/jdk/src/java.base/share/classes/sun/misc/Signal.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/misc/Signal.java Fri Apr 17 10:24:46 2015 -0700 @@ -213,7 +213,7 @@ } }; if (handler != null) { - new Thread(runnable, sig + " handler").start(); + new ManagedLocalsThread(runnable, sig + " handler").start(); } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/net/NetworkServer.java --- a/jdk/src/java.base/share/classes/sun/net/NetworkServer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/net/NetworkServer.java Fri Apr 17 10:24:46 2015 -0700 @@ -27,6 +27,7 @@ import java.io.*; import java.net.Socket; import java.net.ServerSocket; +import sun.misc.ManagedLocalsThread; /** * This is the base class for network servers. To define a new type @@ -72,7 +73,7 @@ NetworkServer n = (NetworkServer)clone(); n.serverSocket = null; n.clientSocket = ns; - new Thread(n).start(); + new ManagedLocalsThread(n).start(); } catch(Exception e) { System.out.print("Server failure\n"); e.printStackTrace(); @@ -107,7 +108,7 @@ for each new connection. */ final public void startServer(int port) throws IOException { serverSocket = new ServerSocket(port, 50); - serverInstance = new Thread(this); + serverInstance = new ManagedLocalsThread(this); serverInstance.start(); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java --- a/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java Fri Apr 17 10:24:46 2015 -0700 @@ -27,8 +27,9 @@ import java.net.URL; import java.io.*; import java.util.StringTokenizer; +import sun.misc.ManagedLocalsThread; -class MimeLauncher extends Thread { +class MimeLauncher extends ManagedLocalsThread { java.net.URLConnection uc; MimeEntry m; String genericTempFileTemplate; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java --- a/jdk/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java Fri Apr 17 10:24:46 2015 -0700 @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.net.URL; +import sun.misc.InnocuousThread; /** * A class that implements a cache of idle Http connections for keep-alive @@ -95,15 +96,7 @@ java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { - // We want to create the Keep-Alive-Timer in the - // system threadgroup - ThreadGroup grp = Thread.currentThread().getThreadGroup(); - ThreadGroup parent = null; - while ((parent = grp.getParent()) != null) { - grp = parent; - } - - keepAliveTimer = new Thread(grp, cache, "Keep-Alive-Timer"); + keepAliveTimer = new InnocuousThread(cache, "Keep-Alive-Timer"); keepAliveTimer.setDaemon(true); keepAliveTimer.setPriority(Thread.MAX_PRIORITY - 2); // Set the context class loader to null in order to avoid diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/net/www/http/KeepAliveStream.java --- a/jdk/src/java.base/share/classes/sun/net/www/http/KeepAliveStream.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/net/www/http/KeepAliveStream.java Fri Apr 17 10:24:46 2015 -0700 @@ -26,6 +26,8 @@ package sun.net.www.http; import java.io.*; + +import sun.misc.InnocuousThread; import sun.net.ProgressSource; import sun.net.www.MeteredStream; @@ -171,15 +173,7 @@ java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { - // We want to create the Keep-Alive-SocketCleaner in the - // system threadgroup - ThreadGroup grp = Thread.currentThread().getThreadGroup(); - ThreadGroup parent = null; - while ((parent = grp.getParent()) != null) { - grp = parent; - } - - cleanerThread = new Thread(grp, queue, "Keep-Alive-SocketCleaner"); + cleanerThread = new InnocuousThread(queue, "Keep-Alive-SocketCleaner"); cleanerThread.setDaemon(true); cleanerThread.setPriority(Thread.MAX_PRIORITY - 2); // Set the context class loader to null in order to avoid diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java --- a/jdk/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/nio/fs/AbstractPoller.java Fri Apr 17 10:24:46 2015 -0700 @@ -30,6 +30,7 @@ import java.security.PrivilegedAction; import java.io.IOException; import java.util.*; +import sun.misc.ManagedLocalsThread; /** * Base implementation of background poller thread used in watch service @@ -59,7 +60,7 @@ AccessController.doPrivileged(new PrivilegedAction() { @Override public Object run() { - Thread thr = new Thread(thisRunnable); + Thread thr = new ManagedLocalsThread(thisRunnable); thr.setDaemon(true); thr.start(); return null; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/nio/fs/Cancellable.java --- a/jdk/src/java.base/share/classes/sun/nio/fs/Cancellable.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/nio/fs/Cancellable.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,6 +25,7 @@ package sun.nio.fs; +import sun.misc.ManagedLocalsThread; import sun.misc.Unsafe; import java.util.concurrent.ExecutionException; @@ -117,7 +118,7 @@ * thread by writing into the memory location that it polls cooperatively. */ static void runInterruptibly(Cancellable task) throws ExecutionException { - Thread t = new Thread(task); + Thread t = new ManagedLocalsThread(task); t.start(); boolean cancelledByInterrupt = false; while (t.isAlive()) { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java --- a/jdk/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/nio/fs/PollingWatchService.java Fri Apr 17 10:24:46 2015 -0700 @@ -35,6 +35,7 @@ import java.util.*; import java.util.concurrent.*; import com.sun.nio.file.SensitivityWatchEventModifier; +import sun.misc.ManagedLocalsThread; /** * Simple WatchService implementation that uses periodic tasks to poll @@ -58,7 +59,7 @@ .newSingleThreadScheduledExecutor(new ThreadFactory() { @Override public Thread newThread(Runnable r) { - Thread t = new Thread(r); + Thread t = new ManagedLocalsThread(r); t.setDaemon(true); return t; }}); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java --- a/jdk/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java Fri Apr 17 10:24:46 2015 -0700 @@ -716,6 +716,11 @@ entry.protectedPrivKey = key.clone(); if (chain != null) { + // validate cert-chain + if ((chain.length > 1) && (!validateChain(chain))) { + throw new KeyStoreException("Certificate chain is " + + "not valid"); + } entry.chain = chain.clone(); certificateCount += chain.length; @@ -1490,7 +1495,12 @@ if (!(issuerDN.equals(subjectDN))) return false; } - return true; + + // Check for loops in the chain. If there are repeated certs, + // the Set of certs in the chain will contain fewer certs than + // the chain + Set set = new HashSet<>(Arrays.asList(certChain)); + return set.size() == certChain.length; } @@ -2070,7 +2080,24 @@ ArrayList chain = new ArrayList(); X509Certificate cert = findMatchedCertificate(entry); + + mainloop: while (cert != null) { + // Check for loops in the certificate chain + if (!chain.isEmpty()) { + for (X509Certificate chainCert : chain) { + if (cert.equals(chainCert)) { + if (debug != null) { + debug.println("Loop detected in " + + "certificate chain. Skip adding " + + "repeated cert to chain. Subject: " + + cert.getSubjectX500Principal() + .toString()); + } + break mainloop; + } + } + } chain.add(cert); X500Principal issuerDN = cert.getIssuerX500Principal(); if (issuerDN.equals(cert.getSubjectX500Principal())) { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/provider/SeedGenerator.java --- a/jdk/src/java.base/share/classes/sun/security/provider/SeedGenerator.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/SeedGenerator.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, 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 @@ -75,6 +75,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Random; +import sun.misc.ManagedLocalsThread; import sun.security.util.Debug; abstract class SeedGenerator { @@ -304,7 +305,7 @@ } finalsg[0] = new ThreadGroup (group, "SeedGenerator ThreadGroup"); - Thread newT = new Thread(finalsg[0], + Thread newT = new ManagedLocalsThread(finalsg[0], ThreadedSeedGenerator.this, "SeedGenerator Thread"); newT.setPriority(Thread.MIN_PRIORITY); @@ -341,7 +342,7 @@ // Start some noisy threads try { BogusThread bt = new BogusThread(); - Thread t = new Thread + Thread t = new ManagedLocalsThread (seedGroup, bt, "SeedGenerator Thread"); t.start(); } catch (Exception e) { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java --- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java Fri Apr 17 10:24:46 2015 -0700 @@ -551,10 +551,10 @@ // set interim reasons mask to the intersection of // reasons in the DP and onlySomeReasons in the IDP boolean[] idpReasonFlags = reasons.getFlags(); - for (int i = 0; i < idpReasonFlags.length; i++) { - if (idpReasonFlags[i] && pointReasonFlags[i]) { - interimReasonsMask[i] = true; - } + for (int i = 0; i < interimReasonsMask.length; i++) { + interimReasonsMask[i] = + (i < idpReasonFlags.length && idpReasonFlags[i]) && + (i < pointReasonFlags.length && pointReasonFlags[i]); } } else { // set interim reasons mask to the value of @@ -568,7 +568,6 @@ interimReasonsMask = pointReasonFlags.clone(); } else { // set interim reasons mask to the special value all-reasons - interimReasonsMask = new boolean[9]; Arrays.fill(interimReasonsMask, true); } } @@ -577,7 +576,9 @@ // not included in the reasons mask boolean oneOrMore = false; for (int i = 0; i < interimReasonsMask.length && !oneOrMore; i++) { - if (!reasonsMask[i] && interimReasonsMask[i]) { + if (interimReasonsMask[i] && + !(i < reasonsMask.length && reasonsMask[i])) + { oneOrMore = true; } } @@ -703,11 +704,11 @@ } // update reasonsMask - for (int i = 0; i < interimReasonsMask.length; i++) { - if (!reasonsMask[i] && interimReasonsMask[i]) { - reasonsMask[i] = true; - } + for (int i = 0; i < reasonsMask.length; i++) { + reasonsMask[i] = reasonsMask[i] || + (i < interimReasonsMask.length && interimReasonsMask[i]); } + return true; } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/rsa/RSACore.java --- a/jdk/src/java.base/share/classes/sun/security/rsa/RSACore.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/rsa/RSACore.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -102,12 +102,24 @@ /** * Perform an RSA private key operation. Uses CRT if the key is a - * CRT key. + * CRT key with additional verification check after the signature + * is computed. */ + @Deprecated public static byte[] rsa(byte[] msg, RSAPrivateKey key) throws BadPaddingException { + return rsa(msg, key, true); + } + + /** + * Perform an RSA private key operation. Uses CRT if the key is a + * CRT key. Set 'verify' to true if this function is used for + * generating a signature. + */ + public static byte[] rsa(byte[] msg, RSAPrivateKey key, boolean verify) + throws BadPaddingException { if (key instanceof RSAPrivateCrtKey) { - return crtCrypt(msg, (RSAPrivateCrtKey)key); + return crtCrypt(msg, (RSAPrivateCrtKey)key, verify); } else { return priCrypt(msg, key.getModulus(), key.getPrivateExponent()); } @@ -148,10 +160,11 @@ * RSA private key operations with CRT. Algorithm and variable naming * are taken from PKCS#1 v2.1, section 5.1.2. */ - private static byte[] crtCrypt(byte[] msg, RSAPrivateCrtKey key) - throws BadPaddingException { + private static byte[] crtCrypt(byte[] msg, RSAPrivateCrtKey key, + boolean verify) throws BadPaddingException { BigInteger n = key.getModulus(); - BigInteger c = parseMsg(msg, n); + BigInteger c0 = parseMsg(msg, n); + BigInteger c = c0; BigInteger p = key.getPrimeP(); BigInteger q = key.getPrimeQ(); BigInteger dP = key.getPrimeExponentP(); @@ -184,6 +197,9 @@ if (ENABLE_BLINDING) { m = m.multiply(brp.v).mod(n); } + if (verify && !c0.equals(m.modPow(e, n))) { + throw new BadPaddingException("RSA private key operation failed"); + } return toByteArray(m, getByteLength(n)); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/rsa/RSASignature.java --- a/jdk/src/java.base/share/classes/sun/security/rsa/RSASignature.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/rsa/RSASignature.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2015, 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 @@ -173,7 +173,7 @@ try { byte[] encoded = encodeSignature(digestOID, digest); byte[] padded = padding.pad(encoded); - byte[] encrypted = RSACore.rsa(padded, privateKey); + byte[] encrypted = RSACore.rsa(padded, privateKey, true); return encrypted; } catch (GeneralSecurityException e) { throw new SignatureException("Could not sign data", e); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientHandshaker.java Fri Apr 17 10:24:46 2015 -0700 @@ -293,7 +293,7 @@ case K_ECDH_RSA: throw new SSLProtocolException( "Protocol violation: server sent a server key exchange" - + "message for key exchange " + keyExchange); + + " message for key exchange " + keyExchange); case K_KRB5: case K_KRB5_EXPORT: throw new SSLProtocolException( diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java --- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java Fri Apr 17 10:24:46 2015 -0700 @@ -39,6 +39,7 @@ import javax.crypto.BadPaddingException; import javax.net.ssl.*; +import sun.misc.ManagedLocalsThread; /** * Implementation of an SSL socket. This is a normal connection type @@ -1078,8 +1079,10 @@ HandshakeCompletedEvent event = new HandshakeCompletedEvent(this, sess); - Thread t = new NotifyHandshakeThread( - handshakeListeners.entrySet(), event); + Thread t = new ManagedLocalsThread( + new NotifyHandshake( + handshakeListeners.entrySet(), event), + "HandshakeCompletedNotify-Thread"); t.start(); } } @@ -2575,17 +2578,16 @@ // events. This ensures that the notifications don't block the // protocol state machine. // - private static class NotifyHandshakeThread extends Thread { + private static class NotifyHandshake implements Runnable { private Set> targets; // who gets notified private HandshakeCompletedEvent event; // the notification - NotifyHandshakeThread( + NotifyHandshake( Set> entrySet, HandshakeCompletedEvent e) { - super("HandshakeCompletedNotify-Thread"); targets = new HashSet<>(entrySet); // clone the entry set event = e; } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/validator/EndEntityChecker.java --- a/jdk/src/java.base/share/classes/sun/security/validator/EndEntityChecker.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/validator/EndEntityChecker.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, 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 @@ -132,26 +132,33 @@ return new EndEntityChecker(type, variant); } - void check(X509Certificate cert, Object parameter) - throws CertificateException { + void check(X509Certificate cert, Object parameter, + boolean checkUnresolvedCritExts) throws CertificateException { if (variant.equals(Validator.VAR_GENERIC)) { - // no checks - return; - } else if (variant.equals(Validator.VAR_TLS_SERVER)) { - checkTLSServer(cert, (String)parameter); + return; // no checks + } + + Set exts = getCriticalExtensions(cert); + if (variant.equals(Validator.VAR_TLS_SERVER)) { + checkTLSServer(cert, (String)parameter, exts); } else if (variant.equals(Validator.VAR_TLS_CLIENT)) { - checkTLSClient(cert); + checkTLSClient(cert, exts); } else if (variant.equals(Validator.VAR_CODE_SIGNING)) { - checkCodeSigning(cert); + checkCodeSigning(cert, exts); } else if (variant.equals(Validator.VAR_JCE_SIGNING)) { - checkCodeSigning(cert); + checkCodeSigning(cert, exts); } else if (variant.equals(Validator.VAR_PLUGIN_CODE_SIGNING)) { - checkCodeSigning(cert); + checkCodeSigning(cert, exts); } else if (variant.equals(Validator.VAR_TSA_SERVER)) { - checkTSAServer(cert); + checkTSAServer(cert, exts); } else { throw new CertificateException("Unknown variant: " + variant); } + + // if neither VAR_GENERIC variant nor unknown variant + if (checkUnresolvedCritExts) { + checkRemainingExtensions(exts); + } } /** @@ -219,10 +226,8 @@ * authentication. * @throws CertificateException if not. */ - private void checkTLSClient(X509Certificate cert) + private void checkTLSClient(X509Certificate cert, Set exts) throws CertificateException { - Set exts = getCriticalExtensions(cert); - if (checkKeyUsage(cert, KU_SIGNATURE) == false) { throw new ValidatorException ("KeyUsage does not allow digital signatures", @@ -245,8 +250,6 @@ exts.remove(SimpleValidator.OID_KEY_USAGE); exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE); - - checkRemainingExtensions(exts); } /** @@ -255,10 +258,8 @@ * specification for details. * @throws CertificateException if not. */ - private void checkTLSServer(X509Certificate cert, String parameter) - throws CertificateException { - Set exts = getCriticalExtensions(cert); - + private void checkTLSServer(X509Certificate cert, String parameter, + Set exts) throws CertificateException { if (KU_SERVER_ENCRYPTION.contains(parameter)) { if (checkKeyUsage(cert, KU_KEY_ENCIPHERMENT) == false) { throw new ValidatorException @@ -303,18 +304,14 @@ exts.remove(SimpleValidator.OID_KEY_USAGE); exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); exts.remove(SimpleValidator.OID_NETSCAPE_CERT_TYPE); - - checkRemainingExtensions(exts); } /** * Check whether this certificate can be used for code signing. * @throws CertificateException if not. */ - private void checkCodeSigning(X509Certificate cert) + private void checkCodeSigning(X509Certificate cert, Set exts) throws CertificateException { - Set exts = getCriticalExtensions(cert); - if (checkKeyUsage(cert, KU_SIGNATURE) == false) { throw new ValidatorException ("KeyUsage does not allow digital signatures", @@ -341,8 +338,6 @@ // remove extensions we checked exts.remove(SimpleValidator.OID_KEY_USAGE); exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); - - checkRemainingExtensions(exts); } /** @@ -350,10 +345,8 @@ * server (see RFC 3161, section 2.3). * @throws CertificateException if not. */ - private void checkTSAServer(X509Certificate cert) + private void checkTSAServer(X509Certificate cert, Set exts) throws CertificateException { - Set exts = getCriticalExtensions(cert); - if (checkKeyUsage(cert, KU_SIGNATURE) == false) { throw new ValidatorException ("KeyUsage does not allow digital signatures", @@ -376,7 +369,5 @@ // remove extensions we checked exts.remove(SimpleValidator.OID_KEY_USAGE); exts.remove(SimpleValidator.OID_EXTENDED_KEY_USAGE); - - checkRemainingExtensions(exts); } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/validator/Validator.java --- a/jdk/src/java.base/share/classes/sun/security/validator/Validator.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/validator/Validator.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2015, 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 @@ -143,6 +143,7 @@ */ public final static String VAR_PLUGIN_CODE_SIGNING = "plugin code signing"; + private final String type; final EndEntityChecker endEntityChecker; final String variant; @@ -154,6 +155,7 @@ volatile Date validationDate; Validator(String type, String variant) { + this.type = type; this.variant = variant; endEntityChecker = EndEntityChecker.getInstance(type, variant); } @@ -261,7 +263,16 @@ // omit EE extension check if EE cert is also trust anchor if (chain.length > 1) { - endEntityChecker.check(chain[0], parameter); + // EndEntityChecker does not need to check unresolved critical + // extensions when validating with a TYPE_PKIX Validator. + // A TYPE_PKIX Validator will already have run checks on all + // certs' extensions, including checks by any PKIXCertPathCheckers + // included in the PKIXParameters, so the extra checks would be + // redundant. + boolean checkUnresolvedCritExts = + (type == TYPE_PKIX) ? false : true; + endEntityChecker.check(chain[0], parameter, + checkUnresolvedCritExts); } return chain; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/x509/KeyUsageExtension.java --- a/jdk/src/java.base/share/classes/sun/security/x509/KeyUsageExtension.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/x509/KeyUsageExtension.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -83,7 +83,8 @@ * @param position the position in the bit string to check. */ private boolean isSet(int position) { - return bitString[position]; + return (position < bitString.length) && + bitString[position]; } /** @@ -275,41 +276,40 @@ * Returns a printable representation of the KeyUsage. */ public String toString() { - String s = super.toString() + "KeyUsage [\n"; + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + sb.append("KeyUsage [\n"); - try { - if (isSet(0)) { - s += " DigitalSignature\n"; - } - if (isSet(1)) { - s += " Non_repudiation\n"; - } - if (isSet(2)) { - s += " Key_Encipherment\n"; - } - if (isSet(3)) { - s += " Data_Encipherment\n"; - } - if (isSet(4)) { - s += " Key_Agreement\n"; - } - if (isSet(5)) { - s += " Key_CertSign\n"; - } - if (isSet(6)) { - s += " Crl_Sign\n"; - } - if (isSet(7)) { - s += " Encipher_Only\n"; - } - if (isSet(8)) { - s += " Decipher_Only\n"; - } - } catch (ArrayIndexOutOfBoundsException ex) {} + if (isSet(0)) { + sb.append(" DigitalSignature\n"); + } + if (isSet(1)) { + sb.append(" Non_repudiation\n"); + } + if (isSet(2)) { + sb.append(" Key_Encipherment\n"); + } + if (isSet(3)) { + sb.append(" Data_Encipherment\n"); + } + if (isSet(4)) { + sb.append(" Key_Agreement\n"); + } + if (isSet(5)) { + sb.append(" Key_CertSign\n"); + } + if (isSet(6)) { + sb.append(" Crl_Sign\n"); + } + if (isSet(7)) { + sb.append(" Encipher_Only\n"); + } + if (isSet(8)) { + sb.append(" Decipher_Only\n"); + } + sb.append("]\n"); - s += "]\n"; - - return (s); + return sb.toString(); } /** diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/x509/NetscapeCertTypeExtension.java --- a/jdk/src/java.base/share/classes/sun/security/x509/NetscapeCertTypeExtension.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/x509/NetscapeCertTypeExtension.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -136,7 +136,8 @@ * @param position the position in the bit string to check. */ private boolean isSet(int position) { - return bitString[position]; + return (position < bitString.length) && + bitString[position]; } /** @@ -236,27 +237,34 @@ * Returns a printable representation of the NetscapeCertType. */ public String toString() { - String s = super.toString() + "NetscapeCertType [\n"; + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + sb.append("NetscapeCertType [\n"); - try { - if (isSet(getPosition(SSL_CLIENT))) - s += " SSL client\n"; - if (isSet(getPosition(SSL_SERVER))) - s += " SSL server\n"; - if (isSet(getPosition(S_MIME))) - s += " S/MIME\n"; - if (isSet(getPosition(OBJECT_SIGNING))) - s += " Object Signing\n"; - if (isSet(getPosition(SSL_CA))) - s += " SSL CA\n"; - if (isSet(getPosition(S_MIME_CA))) - s += " S/MIME CA\n"; - if (isSet(getPosition(OBJECT_SIGNING_CA))) - s += " Object Signing CA" ; - } catch (Exception e) { } + if (isSet(0)) { + sb.append(" SSL client\n"); + } + if (isSet(1)) { + sb.append(" SSL server\n"); + } + if (isSet(2)) { + sb.append(" S/MIME\n"); + } + if (isSet(3)) { + sb.append(" Object Signing\n"); + } + if (isSet(5)) { + sb.append(" SSL CA\n"); + } + if (isSet(6)) { + sb.append(" S/MIME CA\n"); + } + if (isSet(7)) { + sb.append(" Object Signing CA"); + } - s += "]\n"; - return (s); + sb.append("]\n"); + return sb.toString(); } /** diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/security/x509/ReasonFlags.java --- a/jdk/src/java.base/share/classes/sun/security/x509/ReasonFlags.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/security/x509/ReasonFlags.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -99,7 +99,8 @@ * @param position the position in the bit string to check. */ private boolean isSet(int position) { - return bitString[position]; + return (position < bitString.length) && + bitString[position]; } /** @@ -199,23 +200,38 @@ * Returns a printable representation of the ReasonFlags. */ public String toString() { - String s = "Reason Flags [\n"; + StringBuilder sb = new StringBuilder("Reason Flags [\n"); - try { - if (isSet(0)) s += " Unused\n"; - if (isSet(1)) s += " Key Compromise\n"; - if (isSet(2)) s += " CA Compromise\n"; - if (isSet(3)) s += " Affiliation_Changed\n"; - if (isSet(4)) s += " Superseded\n"; - if (isSet(5)) s += " Cessation Of Operation\n"; - if (isSet(6)) s += " Certificate Hold\n"; - if (isSet(7)) s += " Privilege Withdrawn\n"; - if (isSet(8)) s += " AA Compromise\n"; - } catch (ArrayIndexOutOfBoundsException ex) {} + if (isSet(0)) { + sb.append(" Unused\n"); + } + if (isSet(1)) { + sb.append(" Key Compromise\n"); + } + if (isSet(2)) { + sb.append(" CA Compromise\n"); + } + if (isSet(3)) { + sb.append(" Affiliation_Changed\n"); + } + if (isSet(4)) { + sb.append(" Superseded\n"); + } + if (isSet(5)) { + sb.append(" Cessation Of Operation\n"); + } + if (isSet(6)) { + sb.append(" Certificate Hold\n"); + } + if (isSet(7)) { + sb.append(" Privilege Withdrawn\n"); + } + if (isSet(8)) { + sb.append(" AA Compromise\n"); + } + sb.append("]\n"); - s += "]\n"; - - return (s); + return sb.toString(); } /** diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java Fri Apr 17 10:24:46 2015 -0700 @@ -47,6 +47,7 @@ import java.util.LinkedHashSet; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.ResourceBundle; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -250,17 +251,17 @@ return (String) localeName; } - String[] getTimeZoneNames(String key, int size) { + String[] getTimeZoneNames(String key) { String[] names = null; - String cacheKey = TIME_ZONE_NAMES + size + '.' + key; + String cacheKey = TIME_ZONE_NAMES + '.' + key; removeEmptyReferences(); ResourceReference data = cache.get(cacheKey); - if (data == null || ((names = (String[]) data.get()) == null)) { + if (Objects.isNull(data) || Objects.isNull((names = (String[]) data.get()))) { TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale); if (tznb.containsKey(key)) { - names = tznb.getStringArray(key, size); + names = tznb.getStringArray(key); cache.put(cacheKey, new ResourceReference(cacheKey, (Object) names, referenceQueue)); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameProviderImpl.java Fri Apr 17 10:24:46 2015 -0700 @@ -26,6 +26,7 @@ package sun.util.locale.provider; import java.util.Locale; +import java.util.Objects; import java.util.Set; import java.util.TimeZone; import java.util.spi.TimeZoneNameProvider; @@ -95,8 +96,9 @@ */ @Override public String getDisplayName(String id, boolean daylight, int style, Locale locale) { - String[] names = getDisplayNameArray(id, 5, locale); - if (names != null) { + String[] names = getDisplayNameArray(id, locale); + if (Objects.nonNull(names)) { + assert names.length >= 7; int index = daylight ? 3 : 1; if (style == TimeZone.SHORT) { index++; @@ -108,18 +110,18 @@ @Override public String getGenericDisplayName(String id, int style, Locale locale) { - String[] names = getDisplayNameArray(id, 7, locale); - if (names != null && names.length >= 7) { + String[] names = getDisplayNameArray(id, locale); + if (Objects.nonNull(names)) { + assert names.length >= 7; return names[(style == TimeZone.LONG) ? 5 : 6]; } return null; } - private String[] getDisplayNameArray(String id, int n, Locale locale) { - if (id == null || locale == null) { - throw new NullPointerException(); - } - return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getTimeZoneNames(id, n); + private String[] getDisplayNameArray(String id, Locale locale) { + Objects.requireNonNull(id); + Objects.requireNonNull(locale); + return LocaleProviderAdapter.forType(type).getLocaleResources(locale).getTimeZoneNames(id); } /** diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java --- a/jdk/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/TimeZoneNameUtility.java Fri Apr 17 10:24:46 2015 -0700 @@ -30,6 +30,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.TimeZoneNameProvider; @@ -100,9 +101,9 @@ * Retrieve display names for a time zone ID. */ public static String[] retrieveDisplayNames(String id, Locale locale) { - if (id == null || locale == null) { - throw new NullPointerException(); - } + Objects.requireNonNull(id); + Objects.requireNonNull(locale); + return retrieveDisplayNamesImpl(id, locale); } @@ -115,9 +116,12 @@ * @return the requested generic time zone display name, or null if not found. */ public static String retrieveGenericDisplayName(String id, int style, Locale locale) { - LocaleServiceProviderPool pool = - LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class); - return pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale, "generic", style, id); + String[] names = retrieveDisplayNamesImpl(id, locale); + if (Objects.nonNull(names)) { + return names[6 - style]; + } else { + return null; + } } /** @@ -130,140 +134,53 @@ * @return the requested time zone name, or null if not found. */ public static String retrieveDisplayName(String id, boolean daylight, int style, Locale locale) { - LocaleServiceProviderPool pool = - LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class); - return pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale, daylight ? "dst" : "std", style, id); + String[] names = retrieveDisplayNamesImpl(id, locale); + if (Objects.nonNull(names)) { + return names[(daylight ? 4 : 2) - style]; + } else { + return null; + } } private static String[] retrieveDisplayNamesImpl(String id, Locale locale) { LocaleServiceProviderPool pool = LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class); + String[] names; + Map perLocale = null; SoftReference> ref = cachedDisplayNames.get(id); - if (ref != null) { - Map perLocale = ref.get(); - if (perLocale != null) { - String[] names = perLocale.get(locale); - if (names != null) { + if (Objects.nonNull(ref)) { + perLocale = ref.get(); + if (Objects.nonNull(perLocale)) { + names = perLocale.get(locale); + if (Objects.nonNull(names)) { return names; } - names = pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id); - if (names != null) { - perLocale.put(locale, names); - } - return names; } } - String[] names = pool.getLocalizedObject(TimeZoneNameArrayGetter.INSTANCE, locale, id); - if (names != null) { - Map perLocale = new ConcurrentHashMap<>(); - perLocale.put(locale, names); - ref = new SoftReference<>(perLocale); - cachedDisplayNames.put(id, ref); + // build names array + names = new String[7]; + names[0] = id; + for (int i = 1; i <= 6; i ++) { + names[i] = pool.getLocalizedObject(TimeZoneNameGetter.INSTANCE, locale, + i<5 ? (i<3 ? "std" : "dst") : "generic", i%2, id); } + + if (Objects.isNull(perLocale)) { + perLocale = new ConcurrentHashMap<>(); + } + perLocale.put(locale, names); + ref = new SoftReference<>(perLocale); + cachedDisplayNames.put(id, ref); return names; } + /** * Obtains a localized time zone strings from a TimeZoneNameProvider * implementation. */ - private static class TimeZoneNameArrayGetter - implements LocaleServiceProviderPool.LocalizedObjectGetter{ - private static final TimeZoneNameArrayGetter INSTANCE = - new TimeZoneNameArrayGetter(); - - @Override - public String[] getObject(TimeZoneNameProvider timeZoneNameProvider, - Locale locale, - String requestID, - Object... params) { - assert params.length == 0; - - // First, try to get names with the request ID - String[] names = buildZoneStrings(timeZoneNameProvider, locale, requestID); - - if (names == null) { - Map aliases = ZoneInfo.getAliasTable(); - - if (aliases != null) { - // Check whether this id is an alias, if so, - // look for the standard id. - String canonicalID = aliases.get(requestID); - if (canonicalID != null) { - names = buildZoneStrings(timeZoneNameProvider, locale, canonicalID); - } - if (names == null) { - // There may be a case that a standard id has become an - // alias. so, check the aliases backward. - names = examineAliases(timeZoneNameProvider, locale, - canonicalID == null ? requestID : canonicalID, aliases); - } - } - } - - if (names != null) { - names[0] = requestID; - } - - return names; - } - - private static String[] examineAliases(TimeZoneNameProvider tznp, Locale locale, - String id, - Map aliases) { - if (aliases.containsValue(id)) { - for (Map.Entry entry : aliases.entrySet()) { - if (entry.getValue().equals(id)) { - String alias = entry.getKey(); - String[] names = buildZoneStrings(tznp, locale, alias); - if (names != null) { - return names; - } - names = examineAliases(tznp, locale, alias, aliases); - if (names != null) { - return names; - } - } - } - } - - return null; - } - - private static String[] buildZoneStrings(TimeZoneNameProvider tznp, - Locale locale, String id) { - String[] names = new String[5]; - - for (int i = 1; i <= 4; i ++) { - names[i] = tznp.getDisplayName(id, i>=3, i%2, locale); - - if (names[i] == null) { - switch (i) { - case 1: - // this id seems not localized by this provider - return null; - case 2: - case 4: - // If the display name for SHORT is not supplied, - // copy the LONG name. - names[i] = names[i-1]; - break; - case 3: - // If the display name for DST is not supplied, - // copy the "standard" name. - names[3] = names[1]; - break; - } - } - } - - return names; - } - } - private static class TimeZoneNameGetter implements LocaleServiceProviderPool.LocalizedObjectGetter { @@ -299,18 +216,16 @@ private static String examineAliases(TimeZoneNameProvider tznp, Locale locale, String requestID, String tzid, int style, Map aliases) { - if (aliases.containsValue(tzid)) { - for (Map.Entry entry : aliases.entrySet()) { - if (entry.getValue().equals(tzid)) { - String alias = entry.getKey(); - String name = getName(tznp, locale, requestID, style, alias); - if (name != null) { - return name; - } - name = examineAliases(tznp, locale, requestID, alias, style, aliases); - if (name != null) { - return name; - } + for (Map.Entry entry : aliases.entrySet()) { + if (entry.getValue().equals(tzid)) { + String alias = entry.getKey(); + String name = getName(tznp, locale, requestID, style, alias); + if (name != null) { + return name; + } + name = examineAliases(tznp, locale, requestID, alias, style, aliases); + if (name != null) { + return name; } } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java --- a/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/util/resources/TimeZoneNamesBundle.java Fri Apr 17 10:24:46 2015 -0700 @@ -44,6 +44,7 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.MissingResourceException; +import java.util.Objects; import java.util.Set; /** @@ -61,26 +62,6 @@ public abstract class TimeZoneNamesBundle extends OpenListResourceBundle { /** - * Returns a String array containing time zone names. The String array has - * at most size elements. - * - * @param key the time zone ID for which names are obtained - * @param size the requested size of array for names - * @return a String array containing names - */ - public String[] getStringArray(String key, int size) { - String[] names = handleGetObject(key, size); - if ((names == null || names.length != size) && parent != null) { - names = ((TimeZoneNamesBundle)parent).getStringArray(key, size); - } - if (names == null) { - throw new MissingResourceException("no time zone names", getClass().getName(), key); - } - return names; - - } - - /** * Maps time zone IDs to locale-specific names. * The value returned is an array of five strings: *
    @@ -89,6 +70,8 @@ *
  • The short name of the time zone in standard time (localized). *
  • The long name of the time zone in daylight savings time (localized). *
  • The short name of the time zone in daylight savings time (localized). + *
  • The long name of the time zone in generic form (localized). + *
  • The short name of the time zone in generic form (localized). *
* The localized names come from the subclasses's * getContents implementations, while the time zone @@ -96,16 +79,12 @@ */ @Override public Object handleGetObject(String key) { - return handleGetObject(key, 5); - } - - private String[] handleGetObject(String key, int n) { String[] contents = (String[]) super.handleGetObject(key); - if (contents == null) { + if (Objects.isNull(contents)) { return null; } - int clen = Math.min(n - 1, contents.length); - String[] tmpobj = new String[clen+1]; + int clen = contents.length; + String[] tmpobj = new String[7]; tmpobj[0] = key; System.arraycopy(contents, 0, tmpobj, 1, clen); return tmpobj; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/classes/sun/util/resources/en/TimeZoneNames_en_IE.java --- a/jdk/src/java.base/share/classes/sun/util/resources/en/TimeZoneNames_en_IE.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/classes/sun/util/resources/en/TimeZoneNames_en_IE.java Fri Apr 17 10:24:46 2015 -0700 @@ -47,7 +47,8 @@ protected final Object[][] getContents() { return new Object[][] { {"Europe/London", new String[] {"Greenwich Mean Time", "GMT", - "Irish Summer Time", "IST" /*Dublin*/}}, + "Irish Summer Time", "IST", /*Dublin*/ + "Irish Time", "IT" /*Dublin*/}}, }; } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/share/conf/security/java.security --- a/jdk/src/java.base/share/conf/security/java.security Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/share/conf/security/java.security Fri Apr 17 10:24:46 2015 -0700 @@ -533,4 +533,4 @@ # # Example: # jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048 -jdk.tls.disabledAlgorithms=SSLv3 +jdk.tls.disabledAlgorithms=SSLv3, RC4 diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java --- a/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java Fri Apr 17 10:24:46 2015 -0700 @@ -40,6 +40,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; +import sun.misc.ManagedLocalsThread; /** * A multi-threaded implementation of Selector for Windows. @@ -403,7 +404,7 @@ } // Represents a helper thread used for select. - private final class SelectThread extends Thread { + private final class SelectThread extends ManagedLocalsThread { private final int index; // index of this thread final SubSelector subSelector; private long lastRun = 0; // last run number diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/windows/conf/security/java.policy --- a/jdk/src/java.base/windows/conf/security/java.policy Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/windows/conf/security/java.policy Fri Apr 17 10:24:46 2015 -0700 @@ -6,3 +6,7 @@ permission java.security.SecurityPermission "clearProviderProperties.SunMSCAPI"; permission java.security.SecurityPermission "removeProviderProperty.SunMSCAPI"; }; + +grant codeBase "jrt:/jdk.accessibility" { + permission java.security.AllPermission; +}; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.base/windows/native/launcher/java.manifest --- a/jdk/src/java.base/windows/native/launcher/java.manifest Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.base/windows/native/launcher/java.manifest Fri Apr 17 10:24:46 2015 -0700 @@ -4,12 +4,12 @@ xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" > -Java(TM) SE PROGRAM process +Java(TM) SE process = 6; + if (dtzi.TimeZoneKeyName[0] != 0) { + if (dtzi.DynamicDaylightTimeDisabled) { + customZoneName(dtzi.Bias, winZoneName); + return VALUE_GMTOFFSET; + } + wcstombs(winZoneName, dtzi.TimeZoneKeyName, MAX_ZONE_CHAR); + return VALUE_KEY; + } - ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0, - KEY_READ, (PHKEY)&hKey); - if (ret == ERROR_SUCCESS) { - DWORD val; - DWORD bufSize; + /* + * If TimeZoneKeyName is not available, check whether StandardName + * is available to fall back to the older API GetTimeZoneInformation. + * If not, directly read the value from registry keys. + */ + if (dtzi.StandardName[0] == 0) { + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0, + KEY_READ, (PHKEY)&hKey); + if (ret != ERROR_SUCCESS) { + goto err; + } /* * Determine if auto-daylight time adjustment is turned off. */ - valueType = 0; bufSize = sizeof(val); - ret = RegQueryValueExA(hKey, "DisableAutoDaylightTimeSet", - NULL, &valueType, (LPBYTE) &val, &bufSize); + ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL, + &valueType, (LPBYTE) &val, &bufSize); + if (ret != ERROR_SUCCESS) { + goto err; + } /* - * Vista uses the different key name. + * Return a custom time zone name if auto-daylight time adjustment + * is disabled. */ + if (val == 1) { + customZoneName(dtzi.Bias, winZoneName); + (void) RegCloseKey(hKey); + return VALUE_GMTOFFSET; + } + + bufSize = MAX_ZONE_CHAR; + ret = RegQueryValueExA(hKey, "TimeZoneKeyName", NULL, + &valueType, (LPBYTE) winZoneName, &bufSize); if (ret != ERROR_SUCCESS) { - bufSize = sizeof(val); - ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", - NULL, &valueType, (LPBYTE) &val, &bufSize); + goto err; + } + (void) RegCloseKey(hKey); + return VALUE_KEY; + } else { + /* + * Fall back to GetTimeZoneInformation + */ + TIME_ZONE_INFORMATION tzi; + HANDLE hSubKey = NULL; + DWORD nSubKeys, i; + ULONG valueType; + TCHAR subKeyName[MAX_ZONE_CHAR]; + TCHAR szValue[MAX_ZONE_CHAR]; + WCHAR stdNameInReg[MAX_ZONE_CHAR]; + TziValue tempTzi; + WCHAR *stdNamePtr = tzi.StandardName; + DWORD valueSize; + int onlyMapID; + + timeType = GetTimeZoneInformation(&tzi); + if (timeType == TIME_ZONE_ID_INVALID) { + goto err; } + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_CURRENT_TZ_KEY, 0, + KEY_READ, (PHKEY)&hKey); if (ret == ERROR_SUCCESS) { - int daylightSavingsUpdateDisabledOther = val == 1 && tzi.DaylightDate.wMonth != 0; - int daylightSavingsUpdateDisabledVista = val == 1; - int daylightSavingsUpdateDisabled = isVista ? daylightSavingsUpdateDisabledVista : daylightSavingsUpdateDisabledOther; + /* + * Determine if auto-daylight time adjustment is turned off. + */ + bufSize = sizeof(val); + ret = RegQueryValueExA(hKey, "DynamicDaylightTimeDisabled", NULL, + &valueType, (LPBYTE) &val, &bufSize); + if (ret == ERROR_SUCCESS) { + if (val == 1 && tzi.DaylightDate.wMonth != 0) { + (void) RegCloseKey(hKey); + customZoneName(tzi.Bias, winZoneName); + return VALUE_GMTOFFSET; + } + } - if (daylightSavingsUpdateDisabled) { - (void) RegCloseKey(hKey); - customZoneName(tzi.Bias, winZoneName); - return VALUE_GMTOFFSET; + /* + * Win32 problem: If the length of the standard time name is equal + * to (or probably longer than) 32 in the registry, + * GetTimeZoneInformation() on NT returns a null string as its + * standard time name. We need to work around this problem by + * getting the same information from the TimeZoneInformation + * registry. + */ + if (tzi.StandardName[0] == 0) { + bufSize = sizeof(stdNameInReg); + ret = getValueInRegistry(hKey, STANDARD_NAME, &valueType, + (LPBYTE) stdNameInReg, &bufSize); + if (ret != ERROR_SUCCESS) { + goto err; + } + stdNamePtr = stdNameInReg; + } + (void) RegCloseKey(hKey); + } + + /* + * Open the "Time Zones" registry. + */ + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey); + if (ret != ERROR_SUCCESS) { + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey); + /* + * If both failed, then give up. + */ + if (ret != ERROR_SUCCESS) { + return VALUE_UNKNOWN; } } /* - * Vista has the key for the current "Time Zones" entry. - */ - if (isVista) { - valueType = 0; - bufSize = MAX_ZONE_CHAR; - ret = RegQueryValueExA(hKey, "TimeZoneKeyName", NULL, - &valueType, (LPBYTE) winZoneName, &bufSize); - if (ret != ERROR_SUCCESS) { - goto err; - } - (void) RegCloseKey(hKey); - return VALUE_KEY; - } - - /* - * Win32 problem: If the length of the standard time name is equal - * to (or probably longer than) 32 in the registry, - * GetTimeZoneInformation() on NT returns a null string as its - * standard time name. We need to work around this problem by - * getting the same information from the TimeZoneInformation - * registry. The function on Win98 seems to return its key name. - * We can't do anything in that case. + * Get the number of subkeys of the "Time Zones" registry for + * enumeration. */ - if (tzi.StandardName[0] == 0) { - bufSize = sizeof(stdNameInReg); - ret = getValueInRegistry(hKey, STANDARD_NAME, &valueType, - (LPBYTE) stdNameInReg, &bufSize); - if (ret != ERROR_SUCCESS) { - goto err; - } - stdNamePtr = stdNameInReg; - } - (void) RegCloseKey(hKey); - } - - /* - * Open the "Time Zones" registry. - */ - ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, NT_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey); - if (ret != ERROR_SUCCESS) { - ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, WIN_TZ_KEY, 0, KEY_READ, (PHKEY)&hKey); - /* - * If both failed, then give up. - */ - if (ret != ERROR_SUCCESS) { - return VALUE_UNKNOWN; - } - } - - /* - * Get the number of subkeys of the "Time Zones" registry for - * enumeration. - */ - ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, &nSubKeys, - NULL, NULL, NULL, NULL, NULL, NULL, NULL); - if (ret != ERROR_SUCCESS) { - goto err; - } - - /* - * Compare to the "Std" value of each subkey and find the entry that - * matches the current control panel setting. - */ - onlyMapID = 0; - for (i = 0; i < nSubKeys; ++i) { - DWORD size = sizeof(subKeyName); - ret = RegEnumKeyEx(hKey, i, subKeyName, &size, NULL, NULL, NULL, NULL); - if (ret != ERROR_SUCCESS) { - goto err; - } - ret = RegOpenKeyEx(hKey, subKeyName, 0, KEY_READ, (PHKEY)&hSubKey); + ret = RegQueryInfoKey(hKey, NULL, NULL, NULL, &nSubKeys, + NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (ret != ERROR_SUCCESS) { goto err; } - size = sizeof(szValue); - ret = getValueInRegistry(hSubKey, STD_NAME, &valueType, - szValue, &size); - if (ret != ERROR_SUCCESS) { - /* - * NT 4.0 SP3 fails here since it doesn't have the "Std" - * entry in the Time Zones registry. - */ - RegCloseKey(hSubKey); - onlyMapID = 1; - ret = RegOpenKeyExW(hKey, stdNamePtr, 0, KEY_READ, (PHKEY)&hSubKey); + /* + * Compare to the "Std" value of each subkey and find the entry that + * matches the current control panel setting. + */ + onlyMapID = 0; + for (i = 0; i < nSubKeys; ++i) { + DWORD size = sizeof(subKeyName); + ret = RegEnumKeyEx(hKey, i, subKeyName, &size, NULL, NULL, NULL, NULL); + if (ret != ERROR_SUCCESS) { + goto err; + } + ret = RegOpenKeyEx(hKey, subKeyName, 0, KEY_READ, (PHKEY)&hSubKey); if (ret != ERROR_SUCCESS) { goto err; } - break; - } - if (wcscmp((WCHAR *)szValue, stdNamePtr) == 0) { - /* - * Some localized Win32 platforms use a same name to - * different time zones. So, we can't rely only on the name - * here. We need to check GMT offsets and transition dates - * to make sure it's the registry of the current time - * zone. - */ - DWORD tziValueSize = sizeof(tempTzi); - ret = RegQueryValueEx(hSubKey, "TZI", NULL, &valueType, - (unsigned char *) &tempTzi, &tziValueSize); - if (ret == ERROR_SUCCESS) { - if ((tzi.Bias != tempTzi.bias) || - (memcmp((const void *) &tzi.StandardDate, - (const void *) &tempTzi.stdDate, - sizeof(SYSTEMTIME)) != 0)) { - goto out; + size = sizeof(szValue); + ret = getValueInRegistry(hSubKey, STD_NAME, &valueType, + szValue, &size); + if (ret != ERROR_SUCCESS) { + /* + * NT 4.0 SP3 fails here since it doesn't have the "Std" + * entry in the Time Zones registry. + */ + RegCloseKey(hSubKey); + onlyMapID = 1; + ret = RegOpenKeyExW(hKey, stdNamePtr, 0, KEY_READ, (PHKEY)&hSubKey); + if (ret != ERROR_SUCCESS) { + goto err; } + break; + } - if (tzi.DaylightBias != 0) { - if ((tzi.DaylightBias != tempTzi.dstBias) || - (memcmp((const void *) &tzi.DaylightDate, - (const void *) &tempTzi.dstDate, + if (wcscmp((WCHAR *)szValue, stdNamePtr) == 0) { + /* + * Some localized Win32 platforms use a same name to + * different time zones. So, we can't rely only on the name + * here. We need to check GMT offsets and transition dates + * to make sure it's the registry of the current time + * zone. + */ + DWORD tziValueSize = sizeof(tempTzi); + ret = RegQueryValueEx(hSubKey, "TZI", NULL, &valueType, + (unsigned char *) &tempTzi, &tziValueSize); + if (ret == ERROR_SUCCESS) { + if ((tzi.Bias != tempTzi.bias) || + (memcmp((const void *) &tzi.StandardDate, + (const void *) &tempTzi.stdDate, sizeof(SYSTEMTIME)) != 0)) { goto out; } + + if (tzi.DaylightBias != 0) { + if ((tzi.DaylightBias != tempTzi.dstBias) || + (memcmp((const void *) &tzi.DaylightDate, + (const void *) &tempTzi.dstDate, + sizeof(SYSTEMTIME)) != 0)) { + goto out; + } + } } - } - - /* - * found matched record, terminate search - */ - strcpy(winZoneName, subKeyName); - break; - } - out: - (void) RegCloseKey(hSubKey); - } - /* - * Get the "MapID" value of the registry to be able to eliminate - * duplicated key names later. - */ - valueSize = MAX_MAPID_LENGTH; - ret = RegQueryValueExA(hSubKey, "MapID", NULL, &valueType, winMapID, &valueSize); - (void) RegCloseKey(hSubKey); - (void) RegCloseKey(hKey); + /* + * found matched record, terminate search + */ + strcpy(winZoneName, subKeyName); + break; + } + out: + (void) RegCloseKey(hSubKey); + } - if (ret != ERROR_SUCCESS) { /* - * Vista doesn't have mapID. VALUE_UNKNOWN should be returned - * only for Windows NT. + * Get the "MapID" value of the registry to be able to eliminate + * duplicated key names later. */ - if (onlyMapID == 1) { - return VALUE_UNKNOWN; + valueSize = MAX_MAPID_LENGTH; + ret = RegQueryValueExA(hSubKey, "MapID", NULL, &valueType, winMapID, &valueSize); + (void) RegCloseKey(hSubKey); + (void) RegCloseKey(hKey); + + if (ret != ERROR_SUCCESS) { + /* + * Vista doesn't have mapID. VALUE_UNKNOWN should be returned + * only for Windows NT. + */ + if (onlyMapID == 1) { + return VALUE_UNKNOWN; + } } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaFileSystemModel.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,15 +25,16 @@ package com.apple.laf; + import java.beans.*; import java.io.File; import java.util.*; - import javax.swing.*; import javax.swing.event.ListDataEvent; import javax.swing.filechooser.FileSystemView; import javax.swing.table.AbstractTableModel; +import sun.misc.ManagedLocalsThread; /** * NavServices-like implementation of a file Table * @@ -42,7 +43,7 @@ @SuppressWarnings("serial") // Superclass is not serializable across versions class AquaFileSystemModel extends AbstractTableModel implements PropertyChangeListener { private final JTable fFileList; - private LoadFilesThread loadThread = null; + private FilesLoader filesLoader = null; private Vector files = null; JFileChooser filechooser = null; @@ -141,9 +142,9 @@ public void runWhenDone(final Runnable runnable){ synchronized (fileCacheLock) { - if (loadThread != null) { - if (loadThread.isAlive()) { - loadThread.queuedTasks.add(runnable); + if (filesLoader != null) { + if (filesLoader.loadThread.isAlive()) { + filesLoader.queuedTasks.add(runnable); return; } } @@ -160,9 +161,9 @@ return; } - if (loadThread != null) { + if (filesLoader != null) { // interrupt - loadThread.interrupt(); + filesLoader.loadThread.interrupt(); } fetchID++; @@ -173,8 +174,7 @@ fileCache = new Vector(50); } - loadThread = new LoadFilesThread(currentDirectory, fetchID); - loadThread.start(); + filesLoader = new FilesLoader(currentDirectory, fetchID); } public int getColumnCount() { @@ -373,17 +373,25 @@ } } - class LoadFilesThread extends Thread { - Vector queuedTasks = new Vector(); + class FilesLoader implements Runnable { + Vector queuedTasks = new Vector<>(); File currentDirectory = null; int fid; + Thread loadThread; - public LoadFilesThread(final File currentDirectory, final int fid) { - super("Aqua L&F File Loading Thread"); + public FilesLoader(final File currentDirectory, final int fid) { this.currentDirectory = currentDirectory; this.fid = fid; + String name = "Aqua L&F File Loading Thread"; + if (System.getSecurityManager() == null) { + this.loadThread = new Thread(FilesLoader.this, name); + } else { + this.loadThread = new ManagedLocalsThread(FilesLoader.this, name); + } + this.loadThread.start(); } + @Override public void run() { final Vector runnables = new Vector(10); final FileSystemView fileSystem = filechooser.getFileSystemView(); @@ -415,7 +423,7 @@ runnables.addElement(runnable); SwingUtilities.invokeLater(runnable); chunk = new Vector(10); - if (isInterrupted()) { + if (loadThread.isInterrupted()) { // interrupted, cancel all runnables cancelRunnables(runnables); return; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollPaneUI.java --- a/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollPaneUI.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/com/apple/laf/AquaScrollPaneUI.java Fri Apr 17 10:24:46 2015 -0700 @@ -29,6 +29,7 @@ import javax.swing.*; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicScrollPaneUI; public class AquaScrollPaneUI extends javax.swing.plaf.basic.BasicScrollPaneUI { public static ComponentUI createUI(final JComponent x) { @@ -39,28 +40,9 @@ return new XYMouseWheelHandler(); } - // This is a grody hack to trick BasicScrollPaneUI into scrolling horizontally - // when we notice that the shift key is down. This should be removed when AWT/Swing - // becomes aware of multi-axis scroll wheels. - protected class XYMouseWheelHandler extends javax.swing.plaf.basic.BasicScrollPaneUI.MouseWheelHandler { + protected class XYMouseWheelHandler extends BasicScrollPaneUI.MouseWheelHandler { public void mouseWheelMoved(final MouseWheelEvent e) { - JScrollBar vScrollBar = null; - boolean wasVisible = false; - - if (e.isShiftDown()) { - vScrollBar = scrollpane.getVerticalScrollBar(); - if (vScrollBar != null) { - wasVisible = vScrollBar.isVisible(); - vScrollBar.setVisible(false); - } - } - super.mouseWheelMoved(e); - - if (wasVisible) { - vScrollBar.setVisible(true); - } - // Consume the event even when the scrollBar is invisible // see #7124320 e.consume(); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java --- a/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFontManager.java Fri Apr 17 10:24:46 2015 -0700 @@ -42,6 +42,7 @@ import sun.awt.HeadlessToolkit; import sun.awt.util.ThreadGroupUtils; import sun.lwawt.macosx.*; +import sun.misc.InnocuousThread; public final class CFontManager extends SunFontManager { private static Hashtable genericFonts = new Hashtable(); @@ -211,14 +212,18 @@ }); } }; - AccessController.doPrivileged( - (PrivilegedAction) () -> { - /* 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. - */ - ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - fileCloser = new Thread(rootTG, fileCloserRunnable); + AccessController.doPrivileged((PrivilegedAction) () -> { + if (System.getSecurityManager() == null) { + /* 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. + */ + ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); + fileCloser = new Thread(rootTG, fileCloserRunnable); + } else { + /* InnocuousThread is a member of a correct TG by default */ + fileCloser = new InnocuousThread(fileCloserRunnable); + } fileCloser.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(fileCloser); return null; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/lwawt/LWCheckboxPeer.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWCheckboxPeer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWCheckboxPeer.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2015, 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 @@ -132,7 +132,9 @@ @Override public void setState(final boolean state) { synchronized (getDelegateLock()) { + getDelegate().getCurrentButton().removeItemListener(this); getDelegate().setSelected(state); + getDelegate().getCurrentButton().addItemListener(this); } repaintPeer(); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWToolkit.java Fri Apr 17 10:24:46 2015 -0700 @@ -35,6 +35,7 @@ import java.util.*; import sun.awt.*; +import sun.misc.InnocuousThread; import sun.print.*; import sun.awt.util.ThreadGroupUtils; @@ -71,22 +72,32 @@ */ protected final void init() { AWTAutoShutdown.notifyToolkitThreadBusy(); - - ThreadGroup rootTG = AccessController.doPrivileged( - (PrivilegedAction) ThreadGroupUtils::getRootThreadGroup); - - Runtime.getRuntime().addShutdownHook( - new Thread(rootTG, () -> { + AccessController.doPrivileged((PrivilegedAction) () -> { + Runnable shutdownRunnable = () -> { shutdown(); waitForRunState(STATE_CLEANUP); - }) - ); + }; + Thread shutdown; + if (System.getSecurityManager() == null) { + shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); + } else { + shutdown = new InnocuousThread(shutdownRunnable); + } + shutdown.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(shutdown); - Thread toolkitThread = new Thread(rootTG, this, "AWT-LW"); - toolkitThread.setDaemon(true); - toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); - toolkitThread.start(); - + String name = "AWT-LW"; + Thread toolkitThread; + if (System.getSecurityManager() == null) { + toolkitThread = new Thread(ThreadGroupUtils.getRootThreadGroup(), LWToolkit.this, name); + } else { + toolkitThread = new InnocuousThread(LWToolkit.this, name); + } + toolkitThread.setDaemon(true); + toolkitThread.setPriority(Thread.NORM_PRIORITY + 1); + toolkitThread.start(); + return null; + }); waitForRunState(STATE_MESSAGELOOP); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/LWWindowPeer.java Fri Apr 17 10:24:46 2015 -0700 @@ -1296,6 +1296,12 @@ } KeyboardFocusManagerPeer kfmPeer = LWKeyboardFocusManagerPeer.getInstance(); + + if (!becomesFocused && kfmPeer.getCurrentFocusedWindow() != getTarget()) { + // late window focus lost event - ingoring + return; + } + kfmPeer.setCurrentFocusedWindow(becomesFocused ? getTarget() : null); int eventID = becomesFocused ? WindowEvent.WINDOW_GAINED_FOCUS : WindowEvent.WINDOW_LOST_FOCUS; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CClipboard.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CClipboard.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CClipboard.java Fri Apr 17 10:24:46 2015 -0700 @@ -57,6 +57,18 @@ } @Override + public synchronized Transferable getContents(Object requestor) { + checkPasteboardAndNotify(); + return super.getContents(requestor); + } + + @Override + protected synchronized Transferable getContextContents() { + checkPasteboardAndNotify(); + return super.getContextContents(); + } + + @Override protected void setContentsNative(Transferable contents) { FlavorTable flavorMap = getDefaultFlavorTable(); // Don't use delayed Clipboard rendering for the Transferable's data. @@ -116,13 +128,20 @@ private native void declareTypes(long[] formats, SunClipboard newOwner); private native void setData(byte[] data, long format); + void checkPasteboardAndNotify() { + if (checkPasteboardWithoutNotification()) { + notifyChanged(); + lostOwnershipNow(null); + } + } + /** * Invokes native check whether a change count on the general pasteboard is different * than when we set it. The different count value means the current owner lost * pasteboard ownership and someone else put data on the clipboard. * @since 1.7 */ - native void checkPasteboard(); + native boolean checkPasteboardWithoutNotification(); /*** Native Callbacks ***/ private void notifyLostOwnership() { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDragSourceContextPeer.java Fri Apr 17 10:24:46 2015 -0700 @@ -31,7 +31,6 @@ import java.awt.dnd.*; import java.awt.event.*; import java.awt.image.*; -import java.awt.peer.*; import javax.swing.*; import javax.swing.text.*; @@ -44,6 +43,7 @@ import sun.lwawt.LWComponentPeer; import sun.lwawt.LWWindowPeer; import sun.lwawt.PlatformWindow; +import sun.misc.ManagedLocalsThread; public final class CDragSourceContextPeer extends SunDragSourceContextPeer { @@ -164,28 +164,29 @@ // are posted during dragging by native event handlers. try { - Thread dragThread = new Thread() { - public void run() { - final long nativeDragSource = getNativeContext(); - try { - doDragging(nativeDragSource); - } catch (Exception e) { - e.printStackTrace(); - } finally { - releaseNativeDragSource(nativeDragSource); - fDragImage = null; - if (fDragCImage != null) { - fDragCImage.dispose(); - fDragCImage = null; - } + Runnable dragRunnable = () -> { + final long nativeDragSource = getNativeContext(); + try { + doDragging(nativeDragSource); + } catch (Exception e) { + e.printStackTrace(); + } finally { + releaseNativeDragSource(nativeDragSource); + fDragImage = null; + if (fDragCImage != null) { + fDragCImage.dispose(); + fDragCImage = null; } } }; - + Thread dragThread; + if (System.getSecurityManager() == null) { + dragThread = new Thread(dragRunnable); + } else { + dragThread = new ManagedLocalsThread(dragRunnable); + } dragThread.start(); - } - - catch (Exception e) { + } catch (Exception e) { final long nativeDragSource = getNativeContext(); setNativeContext(0); releaseNativeDragSource(nativeDragSource); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CEmbeddedFrame.java Fri Apr 17 10:24:46 2015 -0700 @@ -123,7 +123,7 @@ // it won't be invoced if focuse is moved to a html element // on the same page. CClipboard clipboard = (CClipboard) Toolkit.getDefaultToolkit().getSystemClipboard(); - clipboard.checkPasteboard(); + clipboard.checkPasteboardAndNotify(); } if (parentWindowActive) { responder.handleWindowFocusEvent(focused, null); @@ -164,7 +164,7 @@ } // ignore focus "lost" native request as it may mistakenly // deactivate active window (see 8001161) - if (globalFocusedWindow == this && parentWindowActive) { + if (globalFocusedWindow == this) { responder.handleWindowFocusEvent(parentWindowActive, null); } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CFileDialog.java Fri Apr 17 10:24:46 2015 -0700 @@ -37,6 +37,7 @@ import sun.awt.CausedFocusEvent.Cause; import sun.awt.AWTAccessor; import sun.java2d.pipe.Region; +import sun.misc.ManagedLocalsThread; import sun.security.action.GetBooleanAction; class CFileDialog implements FileDialogPeer { @@ -119,7 +120,11 @@ if (visible) { // Java2 Dialog class requires peer to run code in a separate thread // and handles keeping the call modal - new Thread(new Task()).start(); // invokes my 'run' method, below... + if (System.getSecurityManager() == null) { + new Thread(new Task()).start(); + } else { + new ManagedLocalsThread(new Task()).start(); + } } // We hide ourself before "show" returns - setVisible(false) // doesn't apply diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterDialogPeer.java Fri Apr 17 10:24:46 2015 -0700 @@ -29,6 +29,7 @@ import java.awt.dnd.*; import sun.lwawt.*; +import sun.misc.ManagedLocalsThread; public class CPrinterDialogPeer extends LWWindowPeer { static { @@ -53,13 +54,16 @@ public void setVisible(boolean visible) { if (visible) { - new Thread(new Runnable() { - public void run() { - CPrinterDialog printerDialog = (CPrinterDialog)fTarget; - printerDialog.setRetVal(printerDialog.showDialog()); - printerDialog.setVisible(false); - } - }).start(); + Runnable task = () -> { + CPrinterDialog printerDialog = (CPrinterDialog)fTarget; + printerDialog.setRetVal(printerDialog.showDialog()); + printerDialog.setVisible(false); + }; + if (System.getSecurityManager() == null) { + new Thread(task).start(); + } else { + new ManagedLocalsThread(task).start(); + } } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java --- a/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/classes/sun/lwawt/macosx/CPrinterJob.java Fri Apr 17 10:24:46 2015 -0700 @@ -39,6 +39,7 @@ import javax.print.attribute.standard.PageRanges; import sun.java2d.*; +import sun.misc.ManagedLocalsThread; import sun.print.*; public final class CPrinterJob extends RasterPrinterJob { @@ -731,9 +732,12 @@ // upcall from native private static void detachPrintLoop(final long target, final long arg) { - new Thread() { public void run() { - _safePrintLoop(target, arg); - }}.start(); + Runnable task = () -> _safePrintLoop(target, arg); + if (System.getSecurityManager() == null) { + new Thread(task).start(); + } else { + new ManagedLocalsThread(task).start(); + } } private static native void _safePrintLoop(long target, long arg); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CClipboard.m --- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CClipboard.m Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/awt/CClipboard.m Fri Apr 17 10:24:46 2015 -0700 @@ -107,6 +107,19 @@ } } +- (BOOL) checkPasteboardWithoutNotification:(id)application { + AWT_ASSERT_APPKIT_THREAD; + + NSInteger newChangeCount = [[NSPasteboard generalPasteboard] changeCount]; + + if (self.changeCount != newChangeCount) { + self.changeCount = newChangeCount; + return YES; + } else { + return NO; + } +} + @end /* @@ -260,21 +273,20 @@ return returnValue; } -/* - * Class: sun_lwawt_macosx_CClipboard - * Method: checkPasteboard - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CClipboard_checkPasteboard -(JNIEnv *env, jobject inObject ) -{ -JNF_COCOA_ENTER(env); - - [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ - [[CClipboard sharedClipboard] checkPasteboard:nil]; - }]; - -JNF_COCOA_EXIT(env); -} - - +/* + * Class: sun_lwawt_macosx_CClipboard + * Method: checkPasteboard + * Signature: ()V + */ +JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CClipboard_checkPasteboardWithoutNotification +(JNIEnv *env, jobject inObject) +{ + __block BOOL ret = NO; + JNF_COCOA_ENTER(env); + [ThreadUtilities performOnMainThreadWaiting:YES block:^(){ + ret = [[CClipboard sharedClipboard] checkPasteboardWithoutNotification:nil]; + }]; + + JNF_COCOA_EXIT(env); + return ret; +} \ No newline at end of file diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java --- a/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,7 +25,12 @@ package com.sun.imageio.stream; +import sun.awt.util.ThreadGroupUtils; +import sun.misc.InnocuousThread; + import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Set; import java.util.WeakHashMap; import javax.imageio.stream.ImageInputStream; @@ -81,27 +86,25 @@ } }; - java.security.AccessController.doPrivileged( - new java.security.PrivilegedAction() { - public Object 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. - */ - ThreadGroup tg = - Thread.currentThread().getThreadGroup(); - for (ThreadGroup tgn = tg; - tgn != null; - tg = tgn, tgn = tg.getParent()); - streamCloser = new Thread(tg, streamCloserRunnable); - /* Set context class loader to null in order to avoid - * keeping a strong reference to an application classloader. - */ - streamCloser.setContextClassLoader(null); - Runtime.getRuntime().addShutdownHook(streamCloser); - return null; - } - }); + AccessController.doPrivileged((PrivilegedAction) () -> { + if (System.getSecurityManager() == null) { + /* 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. + */ + ThreadGroup tg = ThreadGroupUtils.getRootThreadGroup(); + streamCloser = new Thread(tg, streamCloserRunnable); + } else { + /* InnocuousThread is a member of a correct TG by default */ + streamCloser = new InnocuousThread(streamCloserRunnable); + } + /* Set context class loader to null in order to avoid + * keeping a strong reference to an application classloader. + */ + streamCloser.setContextClassLoader(null); + Runtime.getRuntime().addShutdownHook(streamCloser); + return null; + }); } } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsDesktopManager.java Fri Apr 17 10:24:46 2015 -0700 @@ -68,7 +68,7 @@ if (currentFrame != null && f != currentFrame) { // If the current frame is maximized, transfer that // attribute to the frame being activated. - if (currentFrame.isMaximum() && + if (!currentFrame.isClosed() && currentFrame.isMaximum() && (f.getClientProperty("JInternalFrame.frameType") != "optionDialog") ) { //Special case. If key binding was used to select next diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java Fri Apr 17 10:24:46 2015 -0700 @@ -64,6 +64,7 @@ import sun.awt.OSInfo; import sun.awt.shell.ShellFolder; import sun.font.FontUtilities; +import sun.misc.ManagedLocalsThread; import sun.security.action.GetPropertyAction; import sun.swing.DefaultLayoutStyle; @@ -2037,7 +2038,11 @@ if (audioRunnable != null) { // Runnable appears to block until completed playing, hence // start up another thread to handle playing. - new Thread(audioRunnable).start(); + if (System.getSecurityManager() == null) { + new Thread(audioRunnable).start(); + } else { + new ManagedLocalsThread(audioRunnable).start(); + } } } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java --- a/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/com/sun/java/swing/plaf/windows/WindowsRootPaneUI.java Fri Apr 17 10:24:46 2015 -0700 @@ -197,6 +197,10 @@ root = null; winAncestor = null; } else { + if (WindowsLookAndFeel.isMnemonicHidden() && ev.isAltDown()) { + WindowsLookAndFeel.setMnemonicHidden(false); + WindowsGraphicsUtils.repaintMnemonicsInWindow(winAncestor); + } altKeyPressed = false; } return false; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/JSSecurityManager.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,6 +25,9 @@ package com.sun.media.sound; +import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; + import java.io.BufferedInputStream; import java.io.InputStream; import java.io.File; @@ -144,7 +147,13 @@ final String threadName, final boolean isDaemon, final int priority, final boolean doStart) { - Thread thread = new Thread(runnable); + Thread thread; + if (System.getSecurityManager() == null) { + thread = new Thread(runnable); + } else { + thread = new ManagedLocalsThread(runnable); + } + if (threadName != null) { thread.setName(threadName); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftAudioPusher.java Fri Apr 17 10:24:46 2015 -0700 @@ -24,6 +24,8 @@ */ package com.sun.media.sound; +import sun.misc.ManagedLocalsThread; + import java.io.IOException; import javax.sound.sampled.AudioInputStream; @@ -53,7 +55,11 @@ if (active) return; active = true; - audiothread = new Thread(this); + if (System.getSecurityManager() == null) { + audiothread = new Thread(this); + } else { + audiothread = new ManagedLocalsThread(this); + } audiothread.setDaemon(true); audiothread.setPriority(Thread.MAX_PRIORITY); audiothread.start(); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftJitterCorrector.java Fri Apr 17 10:24:46 2015 -0700 @@ -24,13 +24,14 @@ */ package com.sun.media.sound; +import sun.misc.ManagedLocalsThread; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; -import javax.sound.sampled.AudioFormat; -import javax.sound.sampled.AudioInputStream; - /** * A jitter corrector to be used with SoftAudioPusher. * @@ -215,7 +216,11 @@ } }; - thread = new Thread(runnable); + if (System.getSecurityManager() == null) { + thread = new Thread(runnable); + } else { + thread = new ManagedLocalsThread(runnable); + } thread.setDaemon(true); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java --- a/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/com/sun/media/sound/SoftSynthesizer.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,6 +25,8 @@ package com.sun.media.sound; +import sun.misc.ManagedLocalsThread; + import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; @@ -139,7 +141,11 @@ pusher = null; jitter_stream = null; sourceDataLine = null; - new Thread(runnable).start(); + if (System.getSecurityManager() == null) { + new Thread(runnable).start(); + } else { + new ManagedLocalsThread(runnable).start(); + } } return len; } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java --- a/jdk/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/AWTEventMulticaster.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, 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 @@ -1088,6 +1088,7 @@ * contains only the specified listener. If no such listeners are chained, * this method returns an empty array. * + * @param the listener type * @param l the specified java.util.EventListener * @param listenerType the type of listeners requested; this parameter * should specify an interface that descends from diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/Component.java --- a/jdk/src/java.desktop/share/classes/java/awt/Component.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java Fri Apr 17 10:24:46 2015 -0700 @@ -4316,9 +4316,12 @@ */ protected boolean validatedContents; // = false /** - * Size of the back buffers + * Width of the back buffers */ protected int width; + /** + * Height of the back buffers + */ protected int height; /** @@ -6013,6 +6016,7 @@ * * If no such listeners exist, this method returns an empty array. * + * @param the type of the listeners * @param listenerType the type of listeners requested; this parameter * should specify an interface that descends from * java.util.EventListener diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java --- a/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/EventDispatchThread.java Fri Apr 17 10:24:46 2015 -0700 @@ -30,6 +30,8 @@ import java.awt.event.WindowEvent; import java.util.ArrayList; + +import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; import sun.awt.dnd.SunDragSourceContextPeer; @@ -53,7 +55,7 @@ * * @since 1.1 */ -class EventDispatchThread extends Thread { +class EventDispatchThread extends ManagedLocalsThread { private static final PlatformLogger eventLog = PlatformLogger.getLogger("java.awt.event.EventDispatchThread"); @@ -65,7 +67,7 @@ private ArrayList eventFilters = new ArrayList(); EventDispatchThread(ThreadGroup group, String name, EventQueue queue) { - super(group, name); + super(group, null, name); setEventQueue(queue); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/GridBagLayout.java --- a/jdk/src/java.desktop/share/classes/java/awt/GridBagLayout.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/GridBagLayout.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, 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 @@ -353,7 +353,7 @@ * } * } *
- *

+ * * @author Doug Stein * @author Bill Spitzak (orignial NeWS & OLIT implementation) * @see java.awt.GridBagConstraints @@ -770,7 +770,7 @@ * components. The value should be a number between 0 and 1 * where 0 represents alignment along the origin, 1 is aligned * the furthest away from the origin, 0.5 is centered, etc. - *

+ * * @return the value 0.5f to indicate centered */ public float getLayoutAlignmentX(Container parent) { @@ -783,7 +783,7 @@ * components. The value should be a number between 0 and 1 * where 0 represents alignment along the origin, 1 is aligned * the furthest away from the origin, 0.5 is centered, etc. - *

+ * * @return the value 0.5f to indicate centered */ public float getLayoutAlignmentY(Container parent) { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java --- a/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/MenuComponent.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, 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 @@ -328,6 +328,7 @@ * Its use is discouraged, and it may not be supported * in the future. * @param evt the event which is to take place + * @return unconditionally returns false * @deprecated As of JDK version 1.1, replaced by {@link * #dispatchEvent(AWTEvent) dispatchEvent}. */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/MenuContainer.java --- a/jdk/src/java.desktop/share/classes/java/awt/MenuContainer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/MenuContainer.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, 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 @@ -50,6 +50,7 @@ * Posts an event to the listeners. * * @param evt the event to dispatch + * @return the results of posting the event * @deprecated As of JDK version 1.1 * replaced by dispatchEvent(AWTEvent). */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/MenuItem.java --- a/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/MenuItem.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, 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 @@ -595,6 +595,7 @@ * * If no such listeners exist, this method returns an empty array. * + * @param the type of the listeners * @param listenerType the type of listeners requested; this parameter * should specify an interface that descends from * java.util.EventListener diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/Toolkit.java --- a/jdk/src/java.desktop/share/classes/java/awt/Toolkit.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/Toolkit.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, 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 @@ -1766,6 +1766,7 @@ * * subclasses should override this to provide their own implementation * + * @param the type of DragGestureRecognizer to create * @param abstractRecognizerClass The abstract class of the required recognizer * @param ds The DragSource * @param c The Component target for the DragGestureRecognizer @@ -1867,7 +1868,9 @@ } /** - * an opportunity to lazily evaluate desktop property values. + * An opportunity to lazily evaluate desktop property values. + * @return the desktop property or null + * @param name the name */ protected Object lazilyLoadDesktopProperty(String name) { return null; @@ -1947,8 +1950,14 @@ return desktopPropsSupport.getPropertyChangeListeners(propertyName); } + /** + * The desktop properties. + */ protected final Map desktopProperties = new HashMap(); + /** + * The desktop properties change support. + */ protected final PropertyChangeSupport desktopPropsSupport = Toolkit.createPropertyChangeSupport(this); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/Window.java --- a/jdk/src/java.desktop/share/classes/java/awt/Window.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/Window.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2015, 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 @@ -2789,6 +2789,7 @@ /** * @deprecated As of J2SE 1.4, replaced by * {@link Component#applyComponentOrientation Component.applyComponentOrientation}. + * @param rb the resource bundle */ @Deprecated public void applyResourceBundle(ResourceBundle rb) { @@ -2798,6 +2799,7 @@ /** * @deprecated As of J2SE 1.4, replaced by * {@link Component#applyComponentOrientation Component.applyComponentOrientation}. + * @param rbName the resource name */ @Deprecated public void applyResourceBundle(String rbName) { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/classes/java/awt/doc-files/Modality.html --- a/jdk/src/java.desktop/share/classes/java/awt/doc-files/Modality.html Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/classes/java/awt/doc-files/Modality.html Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ RGB case. * @@ -1426,23 +1462,23 @@ * png_set_background, along with the bit depth, then the code has a record * of exactly what color space the background is currently in. */ - if (png_ptr->transformations & PNG_BACKGROUND_EXPAND) + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0) { /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if - * the file was greyscale the background value is gray. + * the file was grayscale the background value is gray. */ - if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; } - else if (png_ptr->transformations & PNG_COMPOSE) + else if ((png_ptr->transformations & PNG_COMPOSE) != 0) { /* PNG_COMPOSE: png_set_background was called with need_expand false, * so the color is in the color space of the output or png_set_alpha_mode * was called and the color is black. Ignore RGB_TO_GRAY because that * happens before GRAY_TO_RGB. */ - if (png_ptr->transformations & PNG_GRAY_TO_RGB) + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) { if (png_ptr->background.red == png_ptr->background.green && png_ptr->background.red == png_ptr->background.blue) @@ -1452,7 +1488,8 @@ } } } -#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED (etc) */ +#endif /* READ_EXPAND && READ_BACKGROUND */ +#endif /* READ_GRAY_TO_RGB */ /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations * can be performed directly on the palette, and some (such as rgb to gray) @@ -1473,10 +1510,10 @@ #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ defined(PNG_READ_EXPAND_16_SUPPORTED) - if ((png_ptr->transformations & PNG_EXPAND_16) && - (png_ptr->transformations & PNG_COMPOSE) && - !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - png_ptr->bit_depth != 16) + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth != 16) { /* TODO: fix this. Because the expand_16 operation is after the compose * handling the background color must be 8, not 16, bits deep, but the @@ -1488,14 +1525,36 @@ * NOTE: this discards the low 16 bits of the user supplied background * color, but until expand_16 works properly there is no choice! */ -# define CHOP(x) (x)=((png_uint_16)(((png_uint_32)(x)*255+32895) >> 16)) +# define CHOP(x) (x)=((png_uint_16)PNG_DIV257(x)) CHOP(png_ptr->background.red); CHOP(png_ptr->background.green); CHOP(png_ptr->background.blue); CHOP(png_ptr->background.gray); # undef CHOP } -#endif /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */ +#endif /* READ_BACKGROUND && READ_EXPAND_16 */ + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \ + defined(PNG_READ_STRIP_16_TO_8_SUPPORTED)) + if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && + png_ptr->bit_depth == 16) + { + /* On the other hand, if a 16-bit file is to be reduced to 8-bits per + * component this will also happen after PNG_COMPOSE and so the background + * color must be pre-expanded here. + * + * TODO: fix this too. + */ + png_ptr->background.red = (png_uint_16)(png_ptr->background.red * 257); + png_ptr->background.green = + (png_uint_16)(png_ptr->background.green * 257); + png_ptr->background.blue = (png_uint_16)(png_ptr->background.blue * 257); + png_ptr->background.gray = (png_uint_16)(png_ptr->background.gray * 257); + } +#endif /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the * background support (see the comments in scripts/pnglibconf.dfa), this @@ -1524,27 +1583,36 @@ * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the * tables. */ - if ((png_ptr->transformations & PNG_GAMMA) - || ((png_ptr->transformations & PNG_RGB_TO_GRAY) - && (png_gamma_significant(png_ptr->gamma) || - png_gamma_significant(png_ptr->screen_gamma))) - || ((png_ptr->transformations & PNG_COMPOSE) - && (png_gamma_significant(png_ptr->gamma) - || png_gamma_significant(png_ptr->screen_gamma) + if ((png_ptr->transformations & PNG_GAMMA) != 0 || + ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 && + (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0)) || + ((png_ptr->transformations & PNG_COMPOSE) != 0 && + (png_gamma_significant(png_ptr->colorspace.gamma) != 0 || + png_gamma_significant(png_ptr->screen_gamma) != 0 # ifdef PNG_READ_BACKGROUND_SUPPORTED - || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE - && png_gamma_significant(png_ptr->background_gamma)) + || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE && + png_gamma_significant(png_ptr->background_gamma) != 0) # endif - )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) - && png_gamma_significant(png_ptr->screen_gamma)) - ) + )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + png_gamma_significant(png_ptr->screen_gamma) != 0)) { png_build_gamma_table(png_ptr, png_ptr->bit_depth); #ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_COMPOSE) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + /* Issue a warning about this combination: because RGB_TO_GRAY is + * optimized to do the gamma transform if present yet do_background has + * to do the same thing if both options are set a + * double-gamma-correction happens. This is true in all versions of + * libpng to date. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + png_warning(png_ptr, + "libpng does not support gamma+background+rgb_to_gray"); + + if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0) { /* We don't get to here unless there is a tRNS chunk with non-opaque * entries - see the checking code at the start of this function. @@ -1576,8 +1644,8 @@ break; case PNG_BACKGROUND_GAMMA_FILE: - g = png_reciprocal(png_ptr->gamma); - gs = png_reciprocal2(png_ptr->gamma, + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, png_ptr->screen_gamma); break; @@ -1592,7 +1660,7 @@ break; } - if (png_gamma_significant(gs)) + if (png_gamma_significant(gs) != 0) { back.red = png_gamma_8bit_correct(png_ptr->background.red, gs); @@ -1609,7 +1677,7 @@ back.blue = (png_byte)png_ptr->background.blue; } - if (png_gamma_significant(g)) + if (png_gamma_significant(g) != 0) { back_1.red = png_gamma_8bit_correct(png_ptr->background.red, g); @@ -1663,7 +1731,7 @@ /* Prevent the transformations being done again. * - * NOTE: this is highly dubious; it zaps the transformations in + * NOTE: this is highly dubious; it removes the transformations in * place. This seems inconsistent with the general treatment of the * transformations elsewhere. */ @@ -1673,8 +1741,9 @@ /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ else /* color_type != PNG_COLOR_TYPE_PALETTE */ { - png_fixed_point g = PNG_FP_1; - png_fixed_point gs = PNG_FP_1; + int gs_sig, g_sig; + png_fixed_point g = PNG_FP_1; /* Correction to linear */ + png_fixed_point gs = PNG_FP_1; /* Correction to screen */ switch (png_ptr->background_gamma_type) { @@ -1684,8 +1753,9 @@ break; case PNG_BACKGROUND_GAMMA_FILE: - g = png_reciprocal(png_ptr->gamma); - gs = png_reciprocal2(png_ptr->gamma, png_ptr->screen_gamma); + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); break; case PNG_BACKGROUND_GAMMA_UNIQUE: @@ -1698,34 +1768,45 @@ png_error(png_ptr, "invalid background gamma type"); } - png_ptr->background_1.gray = png_gamma_correct(png_ptr, - png_ptr->background.gray, g); - - png_ptr->background.gray = png_gamma_correct(png_ptr, - png_ptr->background.gray, gs); + g_sig = png_gamma_significant(g); + gs_sig = png_gamma_significant(gs); + + if (g_sig != 0) + png_ptr->background_1.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, g); + + if (gs_sig != 0) + png_ptr->background.gray = png_gamma_correct(png_ptr, + png_ptr->background.gray, gs); if ((png_ptr->background.red != png_ptr->background.green) || (png_ptr->background.red != png_ptr->background.blue) || (png_ptr->background.red != png_ptr->background.gray)) { /* RGB or RGBA with color background */ - png_ptr->background_1.red = png_gamma_correct(png_ptr, - png_ptr->background.red, g); - - png_ptr->background_1.green = png_gamma_correct(png_ptr, - png_ptr->background.green, g); - - png_ptr->background_1.blue = png_gamma_correct(png_ptr, - png_ptr->background.blue, g); - - png_ptr->background.red = png_gamma_correct(png_ptr, - png_ptr->background.red, gs); - - png_ptr->background.green = png_gamma_correct(png_ptr, - png_ptr->background.green, gs); - - png_ptr->background.blue = png_gamma_correct(png_ptr, - png_ptr->background.blue, gs); + if (g_sig != 0) + { + png_ptr->background_1.red = png_gamma_correct(png_ptr, + png_ptr->background.red, g); + + png_ptr->background_1.green = png_gamma_correct(png_ptr, + png_ptr->background.green, g); + + png_ptr->background_1.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, g); + } + + if (gs_sig != 0) + { + png_ptr->background.red = png_gamma_correct(png_ptr, + png_ptr->background.red, gs); + + png_ptr->background.green = png_gamma_correct(png_ptr, + png_ptr->background.green, gs); + + png_ptr->background.blue = png_gamma_correct(png_ptr, + png_ptr->background.blue, gs); + } } else @@ -1737,20 +1818,29 @@ png_ptr->background.red = png_ptr->background.green = png_ptr->background.blue = png_ptr->background.gray; } + + /* The background is now in screen gamma: */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_SCREEN; } /* color_type != PNG_COLOR_TYPE_PALETTE */ }/* png_ptr->transformations & PNG_BACKGROUND */ else /* Transformation does not include PNG_BACKGROUND */ -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#endif /* READ_BACKGROUND */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* RGB_TO_GRAY needs to have non-gamma-corrected values! */ + && ((png_ptr->transformations & PNG_EXPAND) == 0 || + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) +#endif + ) { png_colorp palette = png_ptr->palette; int num_palette = png_ptr->num_palette; int i; - /*NOTE: there are other transformations that should probably be in here - * too. + /* NOTE: there are other transformations that should probably be in + * here too. */ for (i = 0; i < num_palette; i++) { @@ -1766,11 +1856,11 @@ #ifdef PNG_READ_BACKGROUND_SUPPORTED else #endif -#endif /* PNG_READ_GAMMA_SUPPORTED */ +#endif /* READ_GAMMA */ #ifdef PNG_READ_BACKGROUND_SUPPORTED /* No GAMMA transformation (see the hanging else 4 lines above) */ - if ((png_ptr->transformations & PNG_COMPOSE) && + if ((png_ptr->transformations & PNG_COMPOSE) != 0 && (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { int i; @@ -1805,35 +1895,53 @@ png_ptr->transformations &= ~PNG_COMPOSE; } -#endif /* PNG_READ_BACKGROUND_SUPPORTED */ +#endif /* READ_BACKGROUND */ #ifdef PNG_READ_SHIFT_SUPPORTED - if ((png_ptr->transformations & PNG_SHIFT) && + if ((png_ptr->transformations & PNG_SHIFT) != 0 && + (png_ptr->transformations & PNG_EXPAND) == 0 && (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { - png_uint_16 i; - png_uint_16 istop = png_ptr->num_palette; - int sr = 8 - png_ptr->sig_bit.red; - int sg = 8 - png_ptr->sig_bit.green; - int sb = 8 - png_ptr->sig_bit.blue; - - if (sr < 0 || sr > 8) - sr = 0; - - if (sg < 0 || sg > 8) - sg = 0; - - if (sb < 0 || sb > 8) - sb = 0; - - for (i = 0; i < istop; i++) - { - png_ptr->palette[i].red >>= sr; - png_ptr->palette[i].green >>= sg; - png_ptr->palette[i].blue >>= sb; - } + int i; + int istop = png_ptr->num_palette; + int shift = 8 - png_ptr->sig_bit.red; + + png_ptr->transformations &= ~PNG_SHIFT; + + /* significant bits can be in the range 1 to 7 for a meaninful result, if + * the number of significant bits is 0 then no shift is done (this is an + * error condition which is silently ignored.) + */ + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].red; + + component >>= shift; + png_ptr->palette[i].red = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.green; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].green; + + component >>= shift; + png_ptr->palette[i].green = (png_byte)component; + } + + shift = 8 - png_ptr->sig_bit.blue; + if (shift > 0 && shift < 8) + for (i=0; ipalette[i].blue; + + component >>= shift; + png_ptr->palette[i].blue = (png_byte)component; + } } -#endif /* PNG_READ_SHIFT_SUPPORTED */ +#endif /* READ_SHIFT */ } /* Modify the info structure to reflect the transformations. The @@ -1841,12 +1949,12 @@ * assuming the transformations result in valid PNG data. */ void /* PRIVATE */ -png_read_transform_info(png_structp png_ptr, png_infop info_ptr) +png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_read_transform_info"); #ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) + if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { @@ -1868,9 +1976,9 @@ } else { - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) { - if (png_ptr->transformations & PNG_EXPAND_tRNS) + if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0) info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; } if (info_ptr->bit_depth < 8) @@ -1886,7 +1994,7 @@ /* The following is almost certainly wrong unless the background value is in * the screen space! */ - if (png_ptr->transformations & PNG_COMPOSE) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) info_ptr->background = png_ptr->background; #endif @@ -1895,20 +2003,24 @@ * however it seems that the code in png_init_read_transformations, which has * been called before this from png_read_update_info->png_read_start_row * sometimes does the gamma transform and cancels the flag. + * + * TODO: this looks wrong; the info_ptr should end up with a gamma equal to + * the screen_gamma value. The following probably results in weirdness if + * the info_ptr is used by the app after the rows have been read. */ - info_ptr->gamma = png_ptr->gamma; + info_ptr->colorspace.gamma = png_ptr->colorspace.gamma; #endif if (info_ptr->bit_depth == 16) { # ifdef PNG_READ_16BIT_SUPPORTED # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_SCALE_16_TO_8) + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) info_ptr->bit_depth = 8; # endif # ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_16_TO_8) + if ((png_ptr->transformations & PNG_16_TO_8) != 0) info_ptr->bit_depth = 8; # endif @@ -1926,7 +2038,7 @@ info_ptr->bit_depth = 8; # else -# if PNG_READ_SCALE_16_TO_8_SUPPORTED +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_ptr->transformations |= PNG_SCALE_16_TO_8; info_ptr->bit_depth = 8; # else @@ -1934,25 +2046,27 @@ CONFIGURATION ERROR: you must enable at least one 16 to 8 method # endif # endif -#endif /* !READ_16BIT_SUPPORTED */ +#endif /* !READ_16BIT */ } #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) - info_ptr->color_type |= PNG_COLOR_MASK_COLOR; + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + info_ptr->color_type = (png_byte)(info_ptr->color_type | + PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED - if (png_ptr->transformations & PNG_QUANTIZE) + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) { if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && - png_ptr->palette_lookup && info_ptr->bit_depth == 8) + png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8) { info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; } @@ -1960,54 +2074,57 @@ #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 && - info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && + info_ptr->bit_depth == 8 && + info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) { info_ptr->bit_depth = 16; } #endif #ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) + if ((png_ptr->transformations & PNG_PACK) != 0 && + (info_ptr->bit_depth < 8)) info_ptr->bit_depth = 8; #endif if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) info_ptr->channels = 3; else info_ptr->channels = 1; #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_STRIP_ALPHA) + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0) { - info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; + info_ptr->color_type = (png_byte)(info_ptr->color_type & + ~PNG_COLOR_MASK_ALPHA); info_ptr->num_trans = 0; } #endif - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) info_ptr->channels++; #ifdef PNG_READ_FILLER_SUPPORTED /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ - if ((png_ptr->transformations & PNG_FILLER) && - ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || - (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) + if ((png_ptr->transformations & PNG_FILLER) != 0 && + (info_ptr->color_type == PNG_COLOR_TYPE_RGB || + info_ptr->color_type == PNG_COLOR_TYPE_GRAY)) { info_ptr->channels++; /* If adding a true alpha channel not just filler */ - if (png_ptr->transformations & PNG_ADD_ALPHA) + if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0) info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; } #endif #if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) { if (info_ptr->bit_depth < png_ptr->user_transform_depth) info_ptr->bit_depth = png_ptr->user_transform_depth; @@ -2031,291 +2148,11 @@ png_ptr->info_rowbytes = info_ptr->rowbytes; #ifndef PNG_READ_EXPAND_SUPPORTED - if (png_ptr) + if (png_ptr != NULL) return; #endif } -/* Transform the row. The order of transformations is significant, - * and is very touchy. If you add a transformation, take care to - * decide how it fits in with the other transformations here. - */ -void /* PRIVATE */ -png_do_read_transformations(png_structp png_ptr) -{ - png_debug(1, "in png_do_read_transformations"); - - if (png_ptr->row_buf == NULL) - { - /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this - * error is incredibly rare and incredibly easy to debug without this - * information. - */ - png_error(png_ptr, "NULL row buffer"); - } - - /* The following is debugging; prior to 1.5.4 the code was never compiled in; - * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro - * PNG_WARN_UNINITIALIZED_ROW removed. In 1.5 the new flag is set only for - * selected new APIs to ensure that there is no API change. - */ - if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && - !(png_ptr->flags & PNG_FLAG_ROW_INIT)) - { - /* Application has failed to call either png_read_start_image() or - * png_read_update_info() after setting transforms that expand pixels. - * This check added to libpng-1.2.19 (but not enabled until 1.5.4). - */ - png_error(png_ptr, "Uninitialized row"); - } - -#ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) - { - if (png_ptr->row_info.color_type == PNG_COLOR_TYPE_PALETTE) - { - png_do_expand_palette(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); - } - - else - { - if (png_ptr->num_trans && - (png_ptr->transformations & PNG_EXPAND_tRNS)) - png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->trans_color)); - - else - png_do_expand(&(png_ptr->row_info), png_ptr->row_buf + 1, - NULL); - } - } -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) && - !(png_ptr->transformations & PNG_COMPOSE) && - (png_ptr->row_info.color_type == PNG_COLOR_TYPE_RGB_ALPHA || - png_ptr->row_info.color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) - png_do_strip_channel(&(png_ptr->row_info), png_ptr->row_buf + 1, - 0 /* at_start == false, because SWAP_ALPHA happens later */); -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (png_ptr->transformations & PNG_RGB_TO_GRAY) - { - int rgb_error = - png_do_rgb_to_gray(png_ptr, &(png_ptr->row_info), - png_ptr->row_buf + 1); - - if (rgb_error) - { - png_ptr->rgb_to_gray_status=1; - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_WARN) - png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); - - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_ERR) - png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); - } - } -#endif - -/* From Andreas Dilger e-mail to png-implement, 26 March 1998: - * - * In most cases, the "simple transparency" should be done prior to doing - * gray-to-RGB, or you will have to test 3x as many bytes to check if a - * pixel is transparent. You would also need to make sure that the - * transparency information is upgraded to RGB. - * - * To summarize, the current flow is: - * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite - * with background "in place" if transparent, - * convert to RGB if necessary - * - Gray + alpha -> composite with gray background and remove alpha bytes, - * convert to RGB if necessary - * - * To support RGB backgrounds for gray images we need: - * - Gray + simple transparency -> convert to RGB + simple transparency, - * compare 3 or 6 bytes and composite with - * background "in place" if transparent - * (3x compare/pixel compared to doing - * composite with gray bkgrnd) - * - Gray + alpha -> convert to RGB + alpha, composite with background and - * remove alpha bytes (3x float - * operations/pixel compared with composite - * on gray background) - * - * Greg's change will do this. The reason it wasn't done before is for - * performance, as this increases the per-pixel operations. If we would check - * in advance if the background was gray or RGB, and position the gray-to-RGB - * transform appropriately, then it would save a lot of work/time. - */ - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* If gray -> RGB, do so now only if background is non-gray; else do later - * for performance reasons - */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\ - (defined PNG_READ_ALPHA_MODE_SUPPORTED) - if (png_ptr->transformations & PNG_COMPOSE) - png_do_compose(&(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED - if ((png_ptr->transformations & PNG_GAMMA) && -#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\ - (defined PNG_READ_ALPHA_MODE_SUPPORTED) - !((png_ptr->transformations & PNG_COMPOSE) && - ((png_ptr->num_trans != 0) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && -#endif - (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) - png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) && - (png_ptr->transformations & PNG_COMPOSE) && - (png_ptr->row_info.color_type == PNG_COLOR_TYPE_RGB_ALPHA || - png_ptr->row_info.color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) - png_do_strip_channel(&(png_ptr->row_info), png_ptr->row_buf + 1, - 0 /* at_start == false, because SWAP_ALPHA happens later */); -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - if ((png_ptr->transformations & PNG_ENCODE_ALPHA) && - (png_ptr->row_info.color_type & PNG_COLOR_MASK_ALPHA)) - png_do_encode_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_SCALE_16_TO_8) - png_do_scale_16_to_8(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - /* There is no harm in doing both of these because only one has any effect, - * by putting the 'scale' option first if the app asks for scale (either by - * calling the API or in a TRANSFORM flag) this is what happens. - */ - if (png_ptr->transformations & PNG_16_TO_8) - png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - if (png_ptr->transformations & PNG_QUANTIZE) - { - png_do_quantize(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->palette_lookup, png_ptr->quantize_index); - - if (png_ptr->row_info.rowbytes == 0) - png_error(png_ptr, "png_do_quantize returned rowbytes=0"); - } -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ - -#ifdef PNG_READ_EXPAND_16_SUPPORTED - /* Do the expansion now, after all the arithmetic has been done. Notice - * that previous transformations can handle the PNG_EXPAND_16 flag if this - * is efficient (particularly true in the case of gamma correction, where - * better accuracy results faster!) - */ - if (png_ptr->transformations & PNG_EXPAND_16) - png_do_expand_16(&png_ptr->row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /*NOTE: moved here in 1.5.4 (from much later in this list.) */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED - if (png_ptr->transformations & PNG_SHIFT) - png_do_unshift(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif - -#ifdef PNG_READ_PACK_SUPPORTED - if (png_ptr->transformations & PNG_PACK) - png_do_unpack(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_FILLER_SUPPORTED - if (png_ptr->transformations & PNG_FILLER) - png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, - (png_uint_32)png_ptr->filler, png_ptr->flags); -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_ALPHA) - png_do_read_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_16BIT_SUPPORTED -#ifdef PNG_READ_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -#endif - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - if (png_ptr->transformations & PNG_USER_TRANSFORM) - { - if (png_ptr->read_user_transform_fn != NULL) - (*(png_ptr->read_user_transform_fn)) /* User read transform function */ - (png_ptr, /* png_ptr */ - &(png_ptr->row_info), /* row_info: */ - /* png_uint_32 width; width of row */ - /* png_size_t rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED - if (png_ptr->user_transform_depth) - png_ptr->row_info.bit_depth = png_ptr->user_transform_depth; - - if (png_ptr->user_transform_channels) - png_ptr->row_info.channels = png_ptr->user_transform_channels; -#endif - png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * - png_ptr->row_info.channels); - - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - } -#endif -} - #ifdef PNG_READ_PACK_SUPPORTED /* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, * without changing the actual values. Thus, if you had a row with @@ -2323,7 +2160,7 @@ * the numbers 0 or 1. If you would rather they contain 0 and 255, use * png_do_shift() after this. */ -void /* PRIVATE */ +static void png_do_unpack(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_unpack"); @@ -2421,109 +2258,132 @@ * a row of bit depth 8, but only 5 are significant, this will shift * the values back to 0 through 31. */ -void /* PRIVATE */ +static void png_do_unshift(png_row_infop row_info, png_bytep row, png_const_color_8p sig_bits) { + int color_type; + png_debug(1, "in png_do_unshift"); - if ( - row_info->color_type != PNG_COLOR_TYPE_PALETTE) + /* The palette case has already been handled in the _init routine. */ + color_type = row_info->color_type; + + if (color_type != PNG_COLOR_TYPE_PALETTE) { int shift[4]; int channels = 0; - int c; - png_uint_16 value = 0; - png_uint_32 row_width = row_info->width; - - if (row_info->color_type & PNG_COLOR_MASK_COLOR) + int bit_depth = row_info->bit_depth; + + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { - shift[channels++] = row_info->bit_depth - sig_bits->red; - shift[channels++] = row_info->bit_depth - sig_bits->green; - shift[channels++] = row_info->bit_depth - sig_bits->blue; + shift[channels++] = bit_depth - sig_bits->red; + shift[channels++] = bit_depth - sig_bits->green; + shift[channels++] = bit_depth - sig_bits->blue; } else { - shift[channels++] = row_info->bit_depth - sig_bits->gray; + shift[channels++] = bit_depth - sig_bits->gray; } - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) { - shift[channels++] = row_info->bit_depth - sig_bits->alpha; + shift[channels++] = bit_depth - sig_bits->alpha; } - for (c = 0; c < channels; c++) { - if (shift[c] <= 0) - shift[c] = 0; - - else - value = 1; + int c, have_shift; + + for (c = have_shift = 0; c < channels; ++c) + { + /* A shift of more than the bit depth is an error condition but it + * gets ignored here. + */ + if (shift[c] <= 0 || shift[c] >= bit_depth) + shift[c] = 0; + + else + have_shift = 1; + } + + if (have_shift == 0) + return; } - if (!value) - return; - - switch (row_info->bit_depth) + switch (bit_depth) { default: + /* Must be 1bpp gray: should not be here! */ + /* NOTREACHED */ break; case 2: + /* Must be 2bpp gray */ + /* assert(channels == 1 && shift[0] == 1) */ { - png_bytep bp; - png_size_t i; - png_size_t istop = row_info->rowbytes; - - for (bp = row, i = 0; i < istop; i++) + png_bytep bp = row; + png_bytep bp_end = bp + row_info->rowbytes; + + while (bp < bp_end) { - *bp >>= 1; - *bp++ &= 0x55; + int b = (*bp >> 1) & 0x55; + *bp++ = (png_byte)b; } break; } case 4: + /* Must be 4bpp gray */ + /* assert(channels == 1) */ { png_bytep bp = row; - png_size_t i; - png_size_t istop = row_info->rowbytes; - png_byte mask = (png_byte)((((int)0xf0 >> shift[0]) & (int)0xf0) | - (png_byte)((int)0xf >> shift[0])); - - for (i = 0; i < istop; i++) + png_bytep bp_end = bp + row_info->rowbytes; + int gray_shift = shift[0]; + int mask = 0xf >> gray_shift; + + mask |= mask << 4; + + while (bp < bp_end) { - *bp >>= shift[0]; - *bp++ &= mask; + int b = (*bp >> gray_shift) & mask; + *bp++ = (png_byte)b; } break; } case 8: + /* Single byte components, G, GA, RGB, RGBA */ { png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = row_width * channels; - - for (i = 0; i < istop; i++) + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; + + while (bp < bp_end) { - *bp++ >>= shift[i%channels]; + int b = *bp >> shift[channel]; + if (++channel >= channels) + channel = 0; + *bp++ = (png_byte)b; } break; } #ifdef PNG_READ_16BIT_SUPPORTED case 16: + /* Double byte components, G, GA, RGB, RGBA */ { png_bytep bp = row; - png_uint_32 i; - png_uint_32 istop = channels * row_width; - - for (i = 0; i < istop; i++) + png_bytep bp_end = bp + row_info->rowbytes; + int channel = 0; + + while (bp < bp_end) { - value = (png_uint_16)((*bp << 8) + *(bp + 1)); - value >>= shift[i%channels]; + int value = (bp[0] << 8) + bp[1]; + + value >>= shift[channel]; + if (++channel >= channels) + channel = 0; *bp++ = (png_byte)(value >> 8); *bp++ = (png_byte)(value & 0xff); } @@ -2537,7 +2397,7 @@ #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale rows of bit depth 16 down to 8 accurately */ -void /* PRIVATE */ +static void png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_scale_16_to_8"); @@ -2545,7 +2405,7 @@ if (row_info->bit_depth == 16) { png_bytep sp = row; /* source */ - png_bytep dp = row; /* destinaton */ + png_bytep dp = row; /* destination */ png_bytep ep = sp + row_info->rowbytes; /* end+1 */ while (sp < ep) @@ -2595,7 +2455,7 @@ #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED -void /* PRIVATE */ +static void /* Simply discard the low byte. This was the default behavior prior * to libpng-1.5.4. */ @@ -2606,7 +2466,7 @@ if (row_info->bit_depth == 16) { png_bytep sp = row; /* source */ - png_bytep dp = row; /* destinaton */ + png_bytep dp = row; /* destination */ png_bytep ep = sp + row_info->rowbytes; /* end+1 */ while (sp < ep) @@ -2623,7 +2483,7 @@ #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_read_swap_alpha"); @@ -2720,7 +2580,7 @@ #endif #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) { png_uint_32 row_width; @@ -2822,7 +2682,7 @@ #ifdef PNG_READ_FILLER_SUPPORTED /* Add filler channel if we have RGB color */ -void /* PRIVATE */ +static void png_do_read_filler(png_row_infop row_info, png_bytep row, png_uint_32 filler, png_uint_32 flags) { @@ -2841,7 +2701,7 @@ { if (row_info->bit_depth == 8) { - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from G to GX */ png_bytep sp = row + (png_size_t)row_width; @@ -2876,7 +2736,7 @@ #ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from GG to GGXX */ png_bytep sp = row + (png_size_t)row_width * 2; @@ -2918,7 +2778,7 @@ { if (row_info->bit_depth == 8) { - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from RGB to RGBX */ png_bytep sp = row + (png_size_t)row_width * 3; @@ -2957,7 +2817,7 @@ #ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { - if (flags & PNG_FLAG_FILLER_AFTER) + if ((flags & PNG_FLAG_FILLER_AFTER) != 0) { /* This changes the data from RRGGBB to RRGGBBXX */ png_bytep sp = row + (png_size_t)row_width * 6; @@ -3009,7 +2869,7 @@ #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand grayscale files to RGB, with or without alpha */ -void /* PRIVATE */ +static void png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) { png_uint_32 i; @@ -3018,7 +2878,7 @@ png_debug(1, "in png_do_gray_to_rgb"); if (row_info->bit_depth >= 8 && - !(row_info->color_type & PNG_COLOR_MASK_COLOR)) + (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0) { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { @@ -3086,7 +2946,7 @@ } } } - row_info->channels += (png_byte)2; + row_info->channels = (png_byte)(row_info->channels + 2); row_info->color_type |= PNG_COLOR_MASK_COLOR; row_info->pixel_depth = (png_byte)(row_info->channels * row_info->bit_depth); @@ -3097,269 +2957,242 @@ #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* Reduce RGB files to grayscale, with or without alpha - * using the equation given in Poynton's ColorFAQ at - * (THIS LINK IS DEAD June 2008) - * New link: - * + * using the equation given in Poynton's ColorFAQ of 1998-01-04 at + * (THIS LINK IS DEAD June 2008 but + * versions dated 1998 through November 2002 have been archived at + * http://web.archive.org/web/20000816232553/http://www.inforamp.net/ + * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) * Charles Poynton poynton at poynton.com * * Y = 0.212671 * R + 0.715160 * G + 0.072169 * B * - * We approximate this with - * - * Y = 0.21268 * R + 0.7151 * G + 0.07217 * B - * * which can be expressed with integers as * * Y = (6969 * R + 23434 * G + 2365 * B)/32768 * - * The calculation is to be done in a linear colorspace. + * Poynton's current link (as of January 2003 through July 2011): + * + * has changed the numbers slightly: + * + * Y = 0.2126*R + 0.7152*G + 0.0722*B + * + * which can be expressed with integers as + * + * Y = (6966 * R + 23436 * G + 2366 * B)/32768 + * + * Historically, however, libpng uses numbers derived from the ITU-R Rec 709 + * end point chromaticities and the D65 white point. Depending on the + * precision used for the D65 white point this produces a variety of different + * numbers, however if the four decimal place value used in ITU-R Rec 709 is + * used (0.3127,0.3290) the Y calculation would be: + * + * Y = (6968 * R + 23435 * G + 2366 * B)/32768 * - * Other integer coefficents can be used via png_set_rgb_to_gray(). + * While this is correct the rounding results in an overflow for white, because + * the sum of the rounded coefficients is 32769, not 32768. Consequently + * libpng uses, instead, the closest non-overflowing approximation: + * + * Y = (6968 * R + 23434 * G + 2366 * B)/32768 + * + * Starting with libpng-1.5.5, if the image being converted has a cHRM chunk + * (including an sRGB chunk) then the chromaticities are used to calculate the + * coefficients. See the chunk handling in pngrutil.c for more information. + * + * In all cases the calculation is to be done in a linear colorspace. If no + * gamma information is available to correct the encoding of the original RGB + * values this results in an implicit assumption that the original PNG RGB + * values were linear. + * + * Other integer coefficents can be used via png_set_rgb_to_gray(). Because + * the API takes just red and green coefficients the blue coefficient is + * calculated to make the sum 32768. This will result in different rounding + * to that used above. */ -int /* PRIVATE */ -png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) +static int +png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) { - png_uint_32 i; - - png_uint_32 row_width = row_info->width; int rgb_error = 0; png_debug(1, "in png_do_rgb_to_gray"); - if (!(row_info->color_type & PNG_COLOR_MASK_PALETTE) && - (row_info->color_type & PNG_COLOR_MASK_COLOR)) + if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 && + (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { - png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; - png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; - png_uint_32 bc = png_ptr->rgb_to_gray_blue_coeff; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) + PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + PNG_CONST png_uint_32 bc = 32768 - rc - gc; + PNG_CONST png_uint_32 row_width = row_info->width; + PNG_CONST int have_alpha = + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; + + if (row_info->bit_depth == 8) { - if (row_info->bit_depth == 8) +#ifdef PNG_READ_GAMMA_SUPPORTED + /* Notice that gamma to/from 1 are not necessarily inverses (if + * there is an overall gamma correction). Prior to 1.5.5 this code + * checked the linearized values for equality; this doesn't match + * the documentation, the original values must be checked. + */ + if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) { - png_bytep sp = row; - png_bytep dp = row; - - for (i = 0; i < row_width; i++) + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + + if (red != green || red != blue) + { + red = png_ptr->gamma_to_1[red]; + green = png_ptr->gamma_to_1[green]; + blue = png_ptr->gamma_to_1[blue]; + + rgb_error |= 1; + *(dp++) = png_ptr->gamma_from_1[ + (rc*red + gc*green + bc*blue + 16384)>>15]; + } + + else { - png_byte red = png_ptr->gamma_to_1[*(sp++)]; - png_byte green = png_ptr->gamma_to_1[*(sp++)]; - png_byte blue = png_ptr->gamma_to_1[*(sp++)]; - - if (red != green || red != blue) - { - rgb_error |= 1; - *(dp++) = png_ptr->gamma_from_1[ - (rc*red + gc*green + bc*blue)>>15]; - } + /* If there is no overall correction the table will not be + * set. + */ + if (png_ptr->gamma_table != NULL) + red = png_ptr->gamma_table[red]; + + *(dp++) = red; + } + + if (have_alpha != 0) + *(dp++) = *(sp++); + } + } + else +#endif + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_byte red = *(sp++); + png_byte green = *(sp++); + png_byte blue = *(sp++); + + if (red != green || red != blue) + { + rgb_error |= 1; + /* NOTE: this is the historical approach which simply + * truncates the results. + */ + *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); + } + + else + *(dp++) = red; + + if (have_alpha != 0) + *(dp++) = *(sp++); + } + } + } + + else /* RGB bit_depth == 16 */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (png_ptr->gamma_16_to_1 != NULL && png_ptr->gamma_16_from_1 != NULL) + { + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + png_uint_16 red, green, blue, w; + + red = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; + green = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; + blue = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; + + if (red == green && red == blue) + { + if (png_ptr->gamma_16_table != NULL) + w = png_ptr->gamma_16_table[(red & 0xff) + >> png_ptr->gamma_shift][red >> 8]; else - *(dp++) = *(sp - 1); + w = red; } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) + + else { - png_byte red = *(sp++); - png_byte green = *(sp++); - png_byte blue = *(sp++); - - if (red != green || red != blue) - { - rgb_error |= 1; - *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); - } - - else - *(dp++) = *(sp - 1); + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) + >> png_ptr->gamma_shift][red>>8]; + png_uint_16 green_1 = + png_ptr->gamma_16_to_1[(green&0xff) >> + png_ptr->gamma_shift][green>>8]; + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) + >> png_ptr->gamma_shift][blue>>8]; + png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + + bc*blue_1 + 16384)>>15); + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> + png_ptr->gamma_shift][gray16 >> 8]; + rgb_error |= 1; + } + + *(dp++) = (png_byte)((w>>8) & 0xff); + *(dp++) = (png_byte)(w & 0xff); + + if (have_alpha != 0) + { + *(dp++) = *(sp++); + *(dp++) = *(sp++); } } } - - else /* RGB bit_depth == 16 */ + else +#endif { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_16_to_1 != NULL && - png_ptr->gamma_16_from_1 != NULL) + png_bytep sp = row; + png_bytep dp = row; + png_uint_32 i; + + for (i = 0; i < row_width; i++) { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, w; - - red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - - if (red == green && red == blue) - w = red; - - else - { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) - >> png_ptr->gamma_shift][red>>8]; - png_uint_16 green_1 = - png_ptr->gamma_16_to_1[(green&0xff) >> - png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) - >> png_ptr->gamma_shift][blue>>8]; - png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 - + bc*blue_1)>>15); - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> - png_ptr->gamma_shift][gray16 >> 8]; - rgb_error |= 1; - } - - *(dp++) = (png_byte)((w>>8) & 0xff); - *(dp++) = (png_byte)(w & 0xff); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, gray16; - - red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - - if (red != green || red != blue) - rgb_error |= 1; - - gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = (png_byte)((gray16>>8) & 0xff); - *(dp++) = (png_byte)(gray16 & 0xff); - } - } - } - } - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - { - if (row_info->bit_depth == 8) - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_from_1 != NULL && png_ptr->gamma_to_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) + png_uint_16 red, green, blue, gray16; + + red = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; + green = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; + blue = (png_uint_16)(((*(sp)) << 8) | *(sp + 1)); sp += 2; + + if (red != green || red != blue) + rgb_error |= 1; + + /* From 1.5.5 in the 16 bit case do the accurate conversion even + * in the 'fast' case - this is because this is where the code + * ends up when handling linear 16 bit data. + */ + gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> + 15); + *(dp++) = (png_byte)((gray16 >> 8) & 0xff); + *(dp++) = (png_byte)(gray16 & 0xff); + + if (have_alpha != 0) { - png_byte red = png_ptr->gamma_to_1[*(sp++)]; - png_byte green = png_ptr->gamma_to_1[*(sp++)]; - png_byte blue = png_ptr->gamma_to_1[*(sp++)]; - - if (red != green || red != blue) - rgb_error |= 1; - - *(dp++) = png_ptr->gamma_from_1 - [(rc*red + gc*green + bc*blue)>>15]; - - *(dp++) = *(sp++); /* alpha */ - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_byte red = *(sp++); - png_byte green = *(sp++); - png_byte blue = *(sp++); - if (red != green || red != blue) - rgb_error |= 1; - - *(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = *(sp++); /* alpha */ - } - } - } - else /* RGBA bit_depth == 16 */ - { -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr->gamma_16_to_1 != NULL && - png_ptr->gamma_16_from_1 != NULL) - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, w; - - red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; - - if (red == green && red == blue) - w = red; - - else - { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> - png_ptr->gamma_shift][red>>8]; - - png_uint_16 green_1 = - png_ptr->gamma_16_to_1[(green&0xff) >> - png_ptr->gamma_shift][green>>8]; - - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> - png_ptr->gamma_shift][blue>>8]; - - png_uint_16 gray16 = (png_uint_16)((rc * red_1 - + gc * green_1 + bc * blue_1)>>15); - - w = png_ptr->gamma_16_from_1[(gray16&0xff) >> - png_ptr->gamma_shift][gray16 >> 8]; - - rgb_error |= 1; - } - - *(dp++) = (png_byte)((w>>8) & 0xff); - *(dp++) = (png_byte)(w & 0xff); - *(dp++) = *(sp++); /* alpha */ *(dp++) = *(sp++); - } - } - else -#endif - { - png_bytep sp = row; - png_bytep dp = row; - for (i = 0; i < row_width; i++) - { - png_uint_16 red, green, blue, gray16; - red = (png_uint_16)((*(sp)<<8) | *(sp + 1)); sp += 2; - green = (png_uint_16)((*(sp)<<8) | *(sp + 1)); sp += 2; - blue = (png_uint_16)((*(sp)<<8) | *(sp + 1)); sp += 2; - - if (red != green || red != blue) - rgb_error |= 1; - - gray16 = (png_uint_16)((rc*red + gc*green + bc*blue)>>15); - *(dp++) = (png_byte)((gray16>>8) & 0xff); - *(dp++) = (png_byte)(gray16 & 0xff); - *(dp++) = *(sp++); /* alpha */ *(dp++) = *(sp++); } } } } - row_info->channels -= 2; + + row_info->channels = (png_byte)(row_info->channels - 2); row_info->color_type = (png_byte)(row_info->color_type & ~PNG_COLOR_MASK_COLOR); row_info->pixel_depth = (png_byte)(row_info->channels * @@ -3369,73 +3202,15 @@ return rgb_error; } #endif -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ - -#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED -/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth - * large of png_color. This lets grayscale images be treated as - * paletted. Most useful for gamma correction and simplification - * of code. This API is not used internally. - */ -void PNGAPI -png_build_grayscale_palette(int bit_depth, png_colorp palette) -{ - int num_palette; - int color_inc; - int i; - int v; - - png_debug(1, "in png_do_build_grayscale_palette"); - - if (palette == NULL) - return; - - switch (bit_depth) - { - case 1: - num_palette = 2; - color_inc = 0xff; - break; - - case 2: - num_palette = 4; - color_inc = 0x55; - break; - - case 4: - num_palette = 16; - color_inc = 0x11; - break; - - case 8: - num_palette = 256; - color_inc = 1; - break; - - default: - num_palette = 0; - color_inc = 0; - break; - } - - for (i = 0, v = 0; i < num_palette; i++, v += color_inc) - { - palette[i].red = (png_byte)v; - palette[i].green = (png_byte)v; - palette[i].blue = (png_byte)v; - } -} -#endif - - -#ifdef PNG_READ_TRANSFORMS_SUPPORTED -#ifdef PNG_READ_BACKGROUND_SUPPORTED + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* Replace any alpha or transparency with the supplied background color. * "background" is already in the screen gamma, while "background_1" is * at a gamma of 1.0. Paletted files have already been taken care of. */ -void /* PRIVATE */ -png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) +static void +png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { #ifdef PNG_READ_GAMMA_SUPPORTED png_const_bytep gamma_table = png_ptr->gamma_table; @@ -3445,12 +3220,12 @@ png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1; png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1; int gamma_shift = png_ptr->gamma_shift; + int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; #endif png_bytep sp; png_uint_32 i; png_uint_32 row_width = row_info->width; - int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; int shift; png_debug(1, "in png_do_compose"); @@ -3471,11 +3246,12 @@ if ((png_uint_16)((*sp >> shift) & 0x01) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 7; sp++; @@ -3499,20 +3275,22 @@ if ((png_uint_16)((*sp >> shift) & 0x03) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } else { - png_byte p = (png_byte)((*sp >> shift) & 0x03); - png_byte g = (png_byte)((gamma_table [p | (p << 2) | - (p << 4) | (p << 6)] >> 6) & 0x03); - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(g << shift); + unsigned int p = (*sp >> shift) & 0x03; + unsigned int g = (gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03; + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 6; sp++; @@ -3533,11 +3311,12 @@ if ((png_uint_16)((*sp >> shift) & 0x03) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 6; sp++; @@ -3562,20 +3341,22 @@ if ((png_uint_16)((*sp >> shift) & 0x0f) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } else { - png_byte p = (png_byte)((*sp >> shift) & 0x0f); - png_byte g = (png_byte)((gamma_table[p | - (p << 4)] >> 4) & 0x0f); - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(g << shift); + unsigned int p = (*sp >> shift) & 0x0f; + unsigned int g = (gamma_table[p | (p << 4)] >> 4) & + 0x0f; + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 4; sp++; @@ -3596,11 +3377,12 @@ if ((png_uint_16)((*sp >> shift) & 0x0f) == png_ptr->trans_color.gray) { - *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(png_ptr->background.gray << shift); + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); } - if (!shift) + if (shift == 0) { shift = 4; sp++; @@ -3656,8 +3438,10 @@ if (v == png_ptr->trans_color.gray) { /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); } else @@ -3680,8 +3464,10 @@ if (v == png_ptr->trans_color.gray) { - *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); } } } @@ -3761,9 +3547,12 @@ /* Background is already in screen gamma */ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } @@ -3804,9 +3593,12 @@ { *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } } @@ -3843,7 +3635,7 @@ v = gamma_to_1[*sp]; png_composite(w, v, a, png_ptr->background_1.gray); - if (!optimize) + if (optimize == 0) w = gamma_from_1[w]; *sp = w; } @@ -3861,7 +3653,7 @@ *sp = (png_byte)png_ptr->background.gray; else if (a < 0xff) - png_composite(*sp, *sp, a, png_ptr->background_1.gray); + png_composite(*sp, *sp, a, png_ptr->background.gray); } } } @@ -3889,7 +3681,8 @@ else if (a == 0) { /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } @@ -3899,7 +3692,7 @@ g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; png_composite_16(v, g, a, png_ptr->background_1.gray); - if (optimize) + if (optimize != 0) w = v; else w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; @@ -3919,7 +3712,8 @@ if (a == 0) { - *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } @@ -3928,7 +3722,7 @@ png_uint_16 g, v; g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_composite_16(v, g, a, png_ptr->background_1.gray); + png_composite_16(v, g, a, png_ptr->background.gray); *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); } @@ -3972,17 +3766,17 @@ v = gamma_to_1[*sp]; png_composite(w, v, a, png_ptr->background_1.red); - if (!optimize) w = gamma_from_1[w]; + if (optimize == 0) w = gamma_from_1[w]; *sp = w; v = gamma_to_1[*(sp + 1)]; png_composite(w, v, a, png_ptr->background_1.green); - if (!optimize) w = gamma_from_1[w]; + if (optimize == 0) w = gamma_from_1[w]; *(sp + 1) = w; v = gamma_to_1[*(sp + 2)]; png_composite(w, v, a, png_ptr->background_1.blue); - if (!optimize) w = gamma_from_1[w]; + if (optimize == 0) w = gamma_from_1[w]; *(sp + 2) = w; } } @@ -4049,9 +3843,12 @@ /* Background is already in screen gamma */ *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } @@ -4061,23 +3858,26 @@ v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; png_composite_16(w, v, a, png_ptr->background_1.red); - if (!optimize) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + if (optimize == 0) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + 8]; *sp = (png_byte)((w >> 8) & 0xff); *(sp + 1) = (png_byte)(w & 0xff); v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; png_composite_16(w, v, a, png_ptr->background_1.green); - if (!optimize) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + if (optimize == 0) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + 8]; *(sp + 2) = (png_byte)((w >> 8) & 0xff); *(sp + 3) = (png_byte)(w & 0xff); v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; png_composite_16(w, v, a, png_ptr->background_1.blue); - if (!optimize) - w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + if (optimize == 0) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + 8]; *(sp + 4) = (png_byte)((w >> 8) & 0xff); *(sp + 5) = (png_byte)(w & 0xff); @@ -4098,9 +3898,12 @@ { *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } @@ -4137,7 +3940,7 @@ } } } -#endif +#endif /* READ_BACKGROUND || READ_ALPHA_MODE */ #ifdef PNG_READ_GAMMA_SUPPORTED /* Gamma correct the image, avoiding the alpha channel. Make sure @@ -4146,8 +3949,8 @@ * is 16, use gamma_16_table and gamma_shift. Build these with * build_gamma_table(). */ -void /* PRIVATE */ -png_do_gamma(png_row_infop row_info, png_bytep row, png_structp png_ptr) +static void +png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { png_const_bytep gamma_table = png_ptr->gamma_table; png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table; @@ -4347,14 +4150,14 @@ * linear.) Called only with color types that have an alpha channel. Needs the * from_1 tables. */ -void /* PRIVATE */ -png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structp png_ptr) +static void +png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { png_uint_32 row_width = row_info->width; png_debug(1, "in png_do_encode_alpha"); - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) { if (row_info->bit_depth == 8) { @@ -4413,7 +4216,7 @@ /* Expands a palette row to an RGB or RGBA row depending * upon whether you supply trans and num_trans. */ -void /* PRIVATE */ +static void png_do_expand_palette(png_row_infop row_info, png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha, int num_trans) { @@ -4566,7 +4369,7 @@ /* If the bit depth < 8, it is expanded to 8. Also, if the already * expanded transparency value is supplied, an alpha channel is built. */ -void /* PRIVATE */ +static void png_do_expand(png_row_infop row_info, png_bytep row, png_const_color_16p trans_color) { @@ -4580,7 +4383,7 @@ { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { - png_uint_16 gray = (png_uint_16)(trans_color ? trans_color->gray : 0); + unsigned int gray = trans_color != NULL ? trans_color->gray : 0; if (row_info->bit_depth < 8) { @@ -4588,7 +4391,7 @@ { case 1: { - gray = (png_uint_16)((gray & 0x01) * 0xff); + gray = (gray & 0x01) * 0xff; sp = row + (png_size_t)((row_width - 1) >> 3); dp = row + (png_size_t)row_width - 1; shift = 7 - (int)((row_width + 7) & 0x07); @@ -4616,7 +4419,7 @@ case 2: { - gray = (png_uint_16)((gray & 0x03) * 0x55); + gray = (gray & 0x03) * 0x55; sp = row + (png_size_t)((row_width - 1) >> 2); dp = row + (png_size_t)row_width - 1; shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); @@ -4641,7 +4444,7 @@ case 4: { - gray = (png_uint_16)((gray & 0x0f) * 0x11); + gray = (gray & 0x0f) * 0x11; sp = row + (png_size_t)((row_width - 1) >> 1); dp = row + (png_size_t)row_width - 1; shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); @@ -4694,8 +4497,8 @@ else if (row_info->bit_depth == 16) { - png_byte gray_high = (png_byte)((gray >> 8) & 0xff); - png_byte gray_low = (png_byte)(gray & 0xff); + unsigned int gray_high = (gray >> 8) & 0xff; + unsigned int gray_low = gray & 0xff; sp = row + row_info->rowbytes - 1; dp = row + (row_info->rowbytes << 1) - 1; for (i = 0; i < row_width; i++) @@ -4724,7 +4527,8 @@ row_width); } } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color) + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && + trans_color != NULL) { if (row_info->bit_depth == 8) { @@ -4793,10 +4597,10 @@ #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED -/* If the bit depth is 8 and the colour type is not a palette type expand the +/* If the bit depth is 8 and the color type is not a palette type expand the * whole row to 16 bits. Has no effect otherwise. */ -void /* PRIVATE */ +static void png_do_expand_16(png_row_infop row_info, png_bytep row) { if (row_info->bit_depth == 8 && @@ -4824,7 +4628,7 @@ #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED -void /* PRIVATE */ +static void png_do_quantize(png_row_infop row_info, png_bytep row, png_const_bytep palette_lookup, png_const_bytep quantize_lookup) { @@ -4915,70 +4719,304 @@ } } } -#endif /* PNG_READ_QUANTIZE_SUPPORTED */ -#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ - -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing */ +#endif /* READ_QUANTIZE */ + +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ void /* PRIVATE */ -png_do_read_intrapixel(png_row_infop row_info, png_bytep row) +png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) { - png_debug(1, "in png_do_read_intrapixel"); - - if ( - (row_info->color_type & PNG_COLOR_MASK_COLOR)) + png_debug(1, "in png_do_read_transformations"); + + if (png_ptr->row_buf == NULL) { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - - if (row_info->bit_depth == 8) + /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this + * error is incredibly rare and incredibly easy to debug without this + * information. + */ + png_error(png_ptr, "NULL row buffer"); + } + + /* The following is debugging; prior to 1.5.4 the code was never compiled in; + * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro + * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for + * all transformations, however in practice the ROW_INIT always gets done on + * demand, if necessary. + */ + if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + { + /* Application has failed to call either png_read_start_image() or + * png_read_update_info() after setting transforms that expand pixels. + * This check added to libpng-1.2.19 (but not enabled until 1.5.4). + */ + png_error(png_ptr, "Uninitialized row"); + } + +#ifdef PNG_READ_EXPAND_SUPPORTED + if ((png_ptr->transformations & PNG_EXPAND) != 0) + { + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; + png_do_expand_palette(row_info, png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); + } + + else + { + if (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND_tRNS) != 0) + png_do_expand(row_info, png_ptr->row_buf + 1, + &(png_ptr->trans_color)); else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); - *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); - } + png_do_expand(row_info, png_ptr->row_buf + 1, + NULL); } - else if (row_info->bit_depth == 16) + } +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) == 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, row_info, + png_ptr->row_buf + 1); + + if (rgb_error != 0) { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (png_uint_32)((s0 + s1 + 65536L) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 + s1 + 65536L) & 0xffffL); - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp + 1) = (png_byte)(red & 0xff); - *(rp + 4) = (png_byte)((blue >> 8) & 0xff); - *(rp + 5) = (png_byte)(blue & 0xff); - } + png_ptr->rgb_to_gray_status=1; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); } } +#endif + +/* From Andreas Dilger e-mail to png-implement, 26 March 1998: + * + * In most cases, the "simple transparency" should be done prior to doing + * gray-to-RGB, or you will have to test 3x as many bytes to check if a + * pixel is transparent. You would also need to make sure that the + * transparency information is upgraded to RGB. + * + * To summarize, the current flow is: + * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + * with background "in place" if transparent, + * convert to RGB if necessary + * - Gray + alpha -> composite with gray background and remove alpha bytes, + * convert to RGB if necessary + * + * To support RGB backgrounds for gray images we need: + * - Gray + simple transparency -> convert to RGB + simple transparency, + * compare 3 or 6 bytes and composite with + * background "in place" if transparent + * (3x compare/pixel compared to doing + * composite with gray bkgrnd) + * - Gray + alpha -> convert to RGB + alpha, composite with background and + * remove alpha bytes (3x float + * operations/pixel compared with composite + * on gray background) + * + * Greg's change will do this. The reason it wasn't done before is for + * performance, as this increases the per-pixel operations. If we would check + * in advance if the background was gray or RGB, and position the gray-to-RGB + * transform appropriately, then it would save a lot of work/time. + */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + if ((png_ptr->transformations & PNG_COMPOSE) != 0) + png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if ((png_ptr->transformations & PNG_GAMMA) != 0 && +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Because RGB_TO_GRAY does the gamma transform. */ + (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 && +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* Because PNG_COMPOSE does the gamma transform if there is something to + * do (if there is an alpha channel or transparency.) + */ + !((png_ptr->transformations & PNG_COMPOSE) && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) && +#endif + /* Because png_init_read_transformations transforms the palette, unless + * RGB_TO_GRAY will do the transform. + */ + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && + (png_ptr->transformations & PNG_COMPOSE) != 0 && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) + png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* There is no harm in doing both of these because only one has any effect, + * by putting the 'scale' option first if the app asks for scale (either by + * calling the API or in a TRANSFORM flag) this is what happens. + */ + if ((png_ptr->transformations & PNG_16_TO_8) != 0) + png_do_chop(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if ((png_ptr->transformations & PNG_QUANTIZE) != 0) + { + png_do_quantize(row_info, png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->quantize_index); + + if (row_info->rowbytes == 0) + png_error(png_ptr, "png_do_quantize returned rowbytes=0"); + } +#endif /* READ_QUANTIZE */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + /* Do the expansion now, after all the arithmetic has been done. Notice + * that previous transformations can handle the PNG_EXPAND_16 flag if this + * is efficient (particularly true in the case of gamma correction, where + * better accuracy results faster!) + */ + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) + png_do_expand_16(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* NOTE: moved here in 1.5.4 (from much later in this list.) */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_unshift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_unpack(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Added at libpng-1.5.10 */ + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, row_info); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_read_filler(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_16BIT_SUPPORTED +#ifdef PNG_READ_SWAP_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +#endif +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + { + if (png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* User read transform function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + if (png_ptr->user_transform_depth != 0) + row_info->bit_depth = png_ptr->user_transform_depth; + + if (png_ptr->user_transform_channels != 0) + row_info->channels = png_ptr->user_transform_channels; +#endif + row_info->pixel_depth = (png_byte)(row_info->bit_depth * + row_info->channels); + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); + } +#endif } -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED */ + +#endif /* READ_TRANSFORMS */ +#endif /* READ */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c --- a/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngrutil.c Fri Apr 17 10:24:46 2015 -0700 @@ -29,8 +29,8 @@ * However, the following notice accompanied the original version of this * file and, per its terms, should not be removed: * - * Last changed in libpng 1.5.4 [July 7, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -46,10 +46,8 @@ #ifdef PNG_READ_SUPPORTED -#define png_strtod(p,a,b) strtod(a,b) - png_uint_32 PNGAPI -png_get_uint_31(png_structp png_ptr, png_const_bytep buf) +png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) { png_uint_32 uval = png_get_uint_32(buf); @@ -68,7 +66,7 @@ #define PNG_FIXED_ERROR (-1) static png_fixed_point /* PRIVATE */ -png_get_fixed_point(png_structp png_ptr, png_const_bytep buf) +png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf) { png_uint_32 uval = png_get_uint_32(buf); @@ -115,10 +113,10 @@ png_get_int_32)(png_const_bytep buf) { png_uint_32 uval = png_get_uint_32(buf); - if ((uval & 0x80000000L) == 0) /* non-negative */ + if ((uval & 0x80000000) == 0) /* non-negative */ return uval; - uval = (uval ^ 0xffffffffL) + 1; /* 2's complement: -x = ~x+1 */ + uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ return -(png_int_32)uval; } @@ -126,7 +124,7 @@ png_uint_16 (PNGAPI png_get_uint_16)(png_const_bytep buf) { - /* ANSI-C requires an int value to accommodate at least 16 bits so this + /* ANSI-C requires an int value to accomodate at least 16 bits so this * works and allows the compiler not to worry about possible narrowing * on 32 bit systems. (Pre-ANSI systems did not make integers smaller * than 16 bits either.) @@ -138,11 +136,11 @@ return (png_uint_16)val; } -#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */ +#endif /* READ_INT_FUNCTIONS */ /* Read and check the PNG file signature */ void /* PRIVATE */ -png_read_sig(png_structp png_ptr, png_infop info_ptr) +png_read_sig(png_structrp png_ptr, png_inforp info_ptr) { png_size_t num_checked, num_to_check; @@ -161,7 +159,7 @@ png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); png_ptr->sig_bytes = 8; - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0) { if (num_checked < 4 && png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) @@ -177,7 +175,7 @@ * Put the type name into png_ptr->chunk_name, and return the length. */ png_uint_32 /* PRIVATE */ -png_read_chunk_header(png_structp png_ptr) +png_read_chunk_header(png_structrp png_ptr) { png_byte buf[8]; png_uint_32 length; @@ -193,14 +191,14 @@ length = png_get_uint_31(png_ptr, buf); /* Put the chunk name into png_ptr->chunk_name. */ - png_memcpy(png_ptr->chunk_name, buf + 4, 4); - - png_debug2(0, "Reading %s chunk, length = %u", - png_ptr->chunk_name, length); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4); + + png_debug2(0, "Reading %lx chunk, length = %lu", + (unsigned long)png_ptr->chunk_name, (unsigned long)length); /* Reset the crc and run it over the chunk name. */ png_reset_crc(png_ptr); - png_calculate_crc(png_ptr, png_ptr->chunk_name, 4); + png_calculate_crc(png_ptr, buf + 4, 4); /* Check to see if chunk name is valid. */ png_check_chunk_name(png_ptr, png_ptr->chunk_name); @@ -214,7 +212,7 @@ /* Read data, and (optionally) run it through the CRC. */ void /* PRIVATE */ -png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length) +png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length) { if (png_ptr == NULL) return; @@ -224,41 +222,40 @@ } /* Optionally skip data and then check the CRC. Depending on whether we - * are reading a ancillary or critical chunk, and how the program has set + * are reading an ancillary or critical chunk, and how the program has set * things up, we may calculate the CRC on the data and print a message. * Returns '1' if there was a CRC error, '0' otherwise. */ int /* PRIVATE */ -png_crc_finish(png_structp png_ptr, png_uint_32 skip) +png_crc_finish(png_structrp png_ptr, png_uint_32 skip) { - png_size_t i; - png_size_t istop = png_ptr->zbuf_size; - - for (i = (png_size_t)skip; i > istop; i -= istop) + /* The size of the local buffer for inflate is a good guess as to a + * reasonable size to use for buffering reads from the application. + */ + while (skip > 0) { - png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); + png_uint_32 len; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + len = (sizeof tmpbuf); + if (len > skip) + len = skip; + skip -= len; + + png_crc_read(png_ptr, tmpbuf, len); } - if (i) + if (png_crc_error(png_ptr) != 0) { - png_crc_read(png_ptr, png_ptr->zbuf, i); - } - - if (png_crc_error(png_ptr)) - { - if (((png_ptr->chunk_name[0] & 0x20) && /* Ancillary */ - !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) || - (!(png_ptr->chunk_name[0] & 0x20) && /* Critical */ - (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE))) + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ? + (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 : + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0) { png_chunk_warning(png_ptr, "CRC error"); } else - { - png_chunk_benign_error(png_ptr, "CRC error"); - return (0); - } + png_chunk_error(png_ptr, "CRC error"); return (1); } @@ -270,22 +267,22 @@ * the data it has read thus far. */ int /* PRIVATE */ -png_crc_error(png_structp png_ptr) +png_crc_error(png_structrp png_ptr) { png_byte crc_bytes[4]; png_uint_32 crc; int need_crc = 1; - if (png_ptr->chunk_name[0] & 0x20) /* ancillary */ + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) { if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) need_crc = 0; } - else /* critical */ + else /* critical */ { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) need_crc = 0; } @@ -296,7 +293,7 @@ /* The chunk CRC must be serialized in a single I/O call. */ png_read_data(png_ptr, crc_bytes, 4); - if (need_crc) + if (need_crc != 0) { crc = png_get_uint_32(crc_bytes); return ((int)(crc != png_ptr->crc)); @@ -306,252 +303,522 @@ return (0); } -#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED -static png_size_t -png_inflate(png_structp png_ptr, png_bytep data, png_size_t size, - png_bytep output, png_size_t output_size) +#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\ + defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\ + defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\ + defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_SEQUENTIAL_READ_SUPPORTED) +/* Manage the read buffer; this simply reallocates the buffer if it is not small + * enough (or if it is not allocated). The routine returns a pointer to the + * buffer; if an error occurs and 'warn' is set the routine returns NULL, else + * it will call png_error (via png_malloc) on failure. (warn == 2 means + * 'silent'). + */ +static png_bytep +png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) { - png_size_t count = 0; - - /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it can't - * even necessarily handle 65536 bytes) because the type uInt is "16 bits or - * more". Consequently it is necessary to chunk the input to zlib. This - * code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the maximum value - * that can be stored in a uInt.) It is possible to set ZLIB_IO_MAX to a - * lower value in pngpriv.h and this may sometimes have a performance - * advantage, because it forces access of the input data to be separated from - * at least some of the use by some period of time. - */ - png_ptr->zstream.next_in = data; - /* avail_in is set below from 'size' */ - png_ptr->zstream.avail_in = 0; - - while (1) + png_bytep buffer = png_ptr->read_buffer; + + if (buffer != NULL && new_size > png_ptr->read_buffer_size) + { + png_ptr->read_buffer = NULL; + png_ptr->read_buffer = NULL; + png_ptr->read_buffer_size = 0; + png_free(png_ptr, buffer); + buffer = NULL; + } + + if (buffer == NULL) { - int ret, avail; - - /* The setting of 'avail_in' used to be outside the loop, by setting it - * inside it is possible to chunk the input to zlib and simply rely on - * zlib to advance the 'next_in' pointer. This allows arbitrary amounts o - * data to be passed through zlib at the unavoidable cost of requiring a - * window save (memcpy of up to 32768 output bytes) every ZLIB_IO_MAX - * input bytes. - */ - if (png_ptr->zstream.avail_in == 0 && size > 0) + buffer = png_voidcast(png_bytep, png_malloc_base(png_ptr, new_size)); + + if (buffer != NULL) { - if (size <= ZLIB_IO_MAX) - { - /* The value is less than ZLIB_IO_MAX so the cast is safe: */ - png_ptr->zstream.avail_in = (uInt)size; - size = 0; - } + png_ptr->read_buffer = buffer; + png_ptr->read_buffer_size = new_size; + } + + else if (warn < 2) /* else silent */ + { + if (warn != 0) + png_chunk_warning(png_ptr, "insufficient memory to read chunk"); else - { - png_ptr->zstream.avail_in = ZLIB_IO_MAX; - size -= ZLIB_IO_MAX; - } + png_chunk_error(png_ptr, "insufficient memory to read chunk"); } - - /* Reset the output buffer each time round - we empty it - * after every inflate call. + } + + return buffer; +} +#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|SEQUENTIAL_READ */ + +/* png_inflate_claim: claim the zstream for some nefarious purpose that involves + * decompression. Returns Z_OK on success, else a zlib error code. It checks + * the owner but, in final release builds, just issues a warning if some other + * chunk apparently owns the stream. Prior to release it does a png_error. + */ +static int +png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) +{ + if (png_ptr->zowner != 0) + { + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. */ - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = png_ptr->zbuf_size; - - ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); - avail = png_ptr->zbuf_size - png_ptr->zstream.avail_out; - - /* First copy/count any new output - but only if we didn't - * get an error code. + (void)png_safecat(msg, (sizeof msg), 4, " using zstream"); +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_chunk_warning(png_ptr, msg); + png_ptr->zowner = 0; +#else + png_chunk_error(png_ptr, msg); +#endif + } + + /* Implementation note: unlike 'png_deflate_claim' this internal function + * does not take the size of the data as an argument. Some efficiency could + * be gained by using this when it is known *if* the zlib stream itself does + * not record the number; however, this is an illusion: the original writer + * of the PNG may have selected a lower window size, and we really must + * follow that because, for systems with with limited capabilities, we + * would otherwise reject the application's attempts to use a smaller window + * size (zlib doesn't have an interface to say "this or lower"!). + * + * inflateReset2 was added to zlib 1.2.4; before this the window could not be + * reset, therefore it is necessary to always allocate the maximum window + * size with earlier zlibs just in case later compressed chunks need it. + */ + { + int ret; /* zlib return code */ +#if PNG_ZLIB_VERNUM >= 0x1240 + +# if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW) + int window_bits; + + if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == + PNG_OPTION_ON) + window_bits = 15; + + else + window_bits = 0; +# else +# define window_bits 0 +# endif +#endif + + /* Set this for safety, just in case the previous owner left pointers to + * memory allocations. */ - if ((ret == Z_OK || ret == Z_STREAM_END) && avail > 0) + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) { - png_size_t space = avail; /* > 0, see above */ - - if (output != 0 && output_size > count) - { - png_size_t copy = output_size - count; - - if (space < copy) - copy = space; - - png_memcpy(output + count, png_ptr->zbuf, copy); - } - count += space; +#if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateReset(&png_ptr->zstream); +#else + ret = inflateReset2(&png_ptr->zstream, window_bits); +#endif + } + + else + { +#if PNG_ZLIB_VERNUM < 0x1240 + ret = inflateInit(&png_ptr->zstream); +#else + ret = inflateInit2(&png_ptr->zstream, window_bits); +#endif + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; } if (ret == Z_OK) - continue; - - /* Termination conditions - always reset the zstream, it - * must be left in inflateInit state. + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } + +#ifdef window_bits +# undef window_bits +#endif +} + +#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED +/* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to + * allow the caller to do multiple calls if required. If the 'finish' flag is + * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must + * be returned or there has been a problem, otherwise Z_SYNC_FLUSH is used and + * Z_OK or Z_STREAM_END will be returned on success. + * + * The input and output sizes are updated to the actual amounts of data consumed + * or written, not the amount available (as in a z_stream). The data pointers + * are not changed, so the next input is (data+input_size) and the next + * available output is (output+output_size). + */ +static int +png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, + /* INPUT: */ png_const_bytep input, png_uint_32p input_size_ptr, + /* OUTPUT: */ png_bytep output, png_alloc_size_t *output_size_ptr) +{ + if (png_ptr->zowner == owner) /* Else not claimed */ + { + int ret; + png_alloc_size_t avail_out = *output_size_ptr; + png_uint_32 avail_in = *input_size_ptr; + + /* zlib can't necessarily handle more than 65535 bytes at once (i.e. it + * can't even necessarily handle 65536 bytes) because the type uInt is + * "16 bits or more". Consequently it is necessary to chunk the input to + * zlib. This code uses ZLIB_IO_MAX, from pngpriv.h, as the maximum (the + * maximum value that can be stored in a uInt.) It is possible to set + * ZLIB_IO_MAX to a lower value in pngpriv.h and this may sometimes have + * a performance advantage, because it reduces the amount of data accessed + * at each step and that may give the OS more time to page it in. */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + /* avail_in and avail_out are set below from 'size' */ png_ptr->zstream.avail_in = 0; - inflateReset(&png_ptr->zstream); - - if (ret == Z_STREAM_END) - return count; /* NOTE: may be zero. */ - - /* Now handle the error codes - the API always returns 0 - * and the error message is dumped into the uncompressed - * buffer if available. + png_ptr->zstream.avail_out = 0; + + /* Read directly into the output if it is available (this is set to + * a local buffer below if output is NULL). */ -# ifdef PNG_WARNINGS_SUPPORTED + if (output != NULL) + png_ptr->zstream.next_out = output; + + do { - png_const_charp msg; - - if (png_ptr->zstream.msg != 0) - msg = png_ptr->zstream.msg; - - else switch (ret) + uInt avail; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + + /* zlib INPUT BUFFER */ + /* The setting of 'avail_in' used to be outside the loop; by setting it + * inside it is possible to chunk the input to zlib and simply rely on + * zlib to advance the 'next_in' pointer. This allows arbitrary + * amounts of data to be passed through zlib at the unavoidable cost of + * requiring a window save (memcpy of up to 32768 output bytes) + * every ZLIB_IO_MAX input bytes. + */ + avail_in += png_ptr->zstream.avail_in; /* not consumed last time */ + + avail = ZLIB_IO_MAX; + + if (avail_in < avail) + avail = (uInt)avail_in; /* safe: < than ZLIB_IO_MAX */ + + avail_in -= avail; + png_ptr->zstream.avail_in = avail; + + /* zlib OUTPUT BUFFER */ + avail_out += png_ptr->zstream.avail_out; /* not written last time */ + + avail = ZLIB_IO_MAX; /* maximum zlib can process */ + + if (output == NULL) { - case Z_BUF_ERROR: - msg = "Buffer error in compressed datastream"; - break; - - case Z_DATA_ERROR: - msg = "Data error in compressed datastream"; - break; - - default: - msg = "Incomplete compressed datastream"; - break; + /* Reset the output buffer each time round if output is NULL and + * make available the full buffer, up to 'remaining_space' + */ + png_ptr->zstream.next_out = local_buffer; + if ((sizeof local_buffer) < avail) + avail = (sizeof local_buffer); } - png_chunk_warning(png_ptr, msg); - } -# endif - - /* 0 means an error - notice that this code simply ignores - * zero length compressed chunks as a result. + if (avail_out < avail) + avail = (uInt)avail_out; /* safe: < ZLIB_IO_MAX */ + + png_ptr->zstream.avail_out = avail; + avail_out -= avail; + + /* zlib inflate call */ + /* In fact 'avail_out' may be 0 at this point, that happens at the end + * of the read when the final LZ end code was not passed at the end of + * the previous chunk of input data. Tell zlib if we have reached the + * end of the output buffer. + */ + ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH : + (finish ? Z_FINISH : Z_SYNC_FLUSH)); + } while (ret == Z_OK); + + /* For safety kill the local buffer pointer now */ + if (output == NULL) + png_ptr->zstream.next_out = NULL; + + /* Claw back the 'size' and 'remaining_space' byte counts. */ + avail_in += png_ptr->zstream.avail_in; + avail_out += png_ptr->zstream.avail_out; + + /* Update the input and output sizes; the updated values are the amount + * consumed or written, effectively the inverse of what zlib uses. */ - return 0; + if (avail_out > 0) + *output_size_ptr -= avail_out; + + if (avail_in > 0) + *input_size_ptr -= avail_in; + + /* Ensure png_ptr->zstream.msg is set (even in the success case!) */ + png_zstream_error(png_ptr, ret); + return ret; + } + + else + { + /* This is a bad internal error. The recovery assigns to the zstream msg + * pointer, which is not owned by the caller, but this is safe; it's only + * used on errors! + */ + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; } } /* - * Decompress trailing data in a chunk. The assumption is that chunkdata + * Decompress trailing data in a chunk. The assumption is that read_buffer * points at an allocated area holding the contents of a chunk with a * trailing compressed part. What we get back is an allocated area * holding the original prefix part and an uncompressed version of the * trailing part (the malloc area passed in is freed). */ -void /* PRIVATE */ -png_decompress_chunk(png_structp png_ptr, int comp_type, - png_size_t chunklength, - png_size_t prefix_size, png_size_t *newlength) +static int +png_decompress_chunk(png_structrp png_ptr, + png_uint_32 chunklength, png_uint_32 prefix_size, + png_alloc_size_t *newlength /* must be initialized to the maximum! */, + int terminate /*add a '\0' to the end of the uncompressed data*/) { - /* The caller should guarantee this */ - if (prefix_size > chunklength) - { - /* The recovery is to delete the chunk. */ - png_warning(png_ptr, "invalid chunklength"); - prefix_size = 0; /* To delete everything */ - } - - else if (comp_type == PNG_COMPRESSION_TYPE_BASE) + /* TODO: implement different limits for different types of chunk. + * + * The caller supplies *newlength set to the maximum length of the + * uncompressed data, but this routine allocates space for the prefix and + * maybe a '\0' terminator too. We have to assume that 'prefix_size' is + * limited only by the maximum chunk size. + */ + png_alloc_size_t limit = PNG_SIZE_MAX; + +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (limit >= prefix_size + (terminate != 0)) { - png_size_t expanded_size = png_inflate(png_ptr, - (png_bytep)(png_ptr->chunkdata + prefix_size), - chunklength - prefix_size, - 0, /* output */ - 0); /* output size */ - - /* Now check the limits on this chunk - if the limit fails the - * compressed data will be removed, the prefix will remain. - */ -#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED - if (png_ptr->user_chunk_malloc_max && - (prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1)) -#else -# ifdef PNG_USER_CHUNK_MALLOC_MAX - if ((PNG_USER_CHUNK_MALLOC_MAX > 0) && - prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1) -# endif -#endif - png_warning(png_ptr, "Exceeded size limit while expanding chunk"); - - /* If the size is zero either there was an error and a message - * has already been output (warning) or the size really is zero - * and we have nothing to do - the code will exit through the - * error case below. - */ -#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \ - defined(PNG_USER_CHUNK_MALLOC_MAX) - else if (expanded_size > 0) -#else - if (expanded_size > 0) -#endif + int ret; + + limit -= prefix_size + (terminate != 0); + + if (limit < *newlength) + *newlength = limit; + + /* Now try to claim the stream. */ + ret = png_inflate_claim(png_ptr, png_ptr->chunk_name); + + if (ret == Z_OK) { - /* Success (maybe) - really uncompress the chunk. */ - png_size_t new_size = 0; - png_charp text = png_malloc_warn(png_ptr, - prefix_size + expanded_size + 1); - - if (text != NULL) + png_uint_32 lzsize = chunklength - prefix_size; + + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, + /* output: */ NULL, newlength); + + if (ret == Z_STREAM_END) { - png_memcpy(text, png_ptr->chunkdata, prefix_size); - new_size = png_inflate(png_ptr, - (png_bytep)(png_ptr->chunkdata + prefix_size), - chunklength - prefix_size, - (png_bytep)(text + prefix_size), expanded_size); - text[prefix_size + expanded_size] = 0; /* just in case */ - - if (new_size == expanded_size) + /* Use 'inflateReset' here, not 'inflateReset2' because this + * preserves the previously decided window size (otherwise it would + * be necessary to store the previous window size.) In practice + * this doesn't matter anyway, because png_inflate will call inflate + * with Z_FINISH in almost all cases, so the window will not be + * maintained. + */ + if (inflateReset(&png_ptr->zstream) == Z_OK) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; - *newlength = prefix_size + expanded_size; - return; /* The success return! */ + /* Because of the limit checks above we know that the new, + * expanded, size will fit in a size_t (let alone an + * png_alloc_size_t). Use png_malloc_base here to avoid an + * extra OOM message. + */ + png_alloc_size_t new_size = *newlength; + png_alloc_size_t buffer_size = prefix_size + new_size + + (terminate != 0); + png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr, + buffer_size)); + + if (text != NULL) + { + ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, + png_ptr->read_buffer + prefix_size, &lzsize, + text + prefix_size, newlength); + + if (ret == Z_STREAM_END) + { + if (new_size == *newlength) + { + if (terminate != 0) + text[prefix_size + *newlength] = 0; + + if (prefix_size > 0) + memcpy(text, png_ptr->read_buffer, prefix_size); + + { + png_bytep old_ptr = png_ptr->read_buffer; + + png_ptr->read_buffer = text; + png_ptr->read_buffer_size = buffer_size; + text = old_ptr; /* freed below */ + } + } + + else + { + /* The size changed on the second read, there can be no + * guarantee that anything is correct at this point. + * The 'msg' pointer has been set to "unexpected end of + * LZ stream", which is fine, but return an error code + * that the caller won't accept. + */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } + } + + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; /* for safety */ + + /* Free the text pointer (this is the old read_buffer on + * success) + */ + png_free(png_ptr, text); + text = NULL; + + /* This really is very benign, but it's still an error because + * the extra space may otherwise be used as a Trojan Horse. + */ + if (ret == Z_STREAM_END && + chunklength - prefix_size != lzsize) + png_chunk_benign_error(png_ptr, "extra compressed data"); + } + + else + { + /* Out of memory allocating the buffer */ + ret = Z_MEM_ERROR; + png_zstream_error(png_ptr, Z_MEM_ERROR); + } } - png_warning(png_ptr, "png_inflate logic error"); - png_free(png_ptr, text); + else + { + /* inflateReset failed, store the error message */ + png_zstream_error(png_ptr, ret); + + if (ret == Z_STREAM_END) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + } } - else - png_warning(png_ptr, "Not enough memory to decompress chunk"); + else if (ret == Z_OK) + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + /* Release the claimed stream */ + png_ptr->zowner = 0; } + + else /* the claim failed */ if (ret == Z_STREAM_END) /* impossible! */ + ret = PNG_UNEXPECTED_ZLIB_RETURN; + + return ret; } - else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ + else { - PNG_WARNING_PARAMETERS(p) - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, comp_type); - png_formatted_warning(png_ptr, p, "Unknown zTXt compression type @1"); - - /* The recovery is to simply drop the data. */ + /* Application/configuration limits exceeded */ + png_zstream_error(png_ptr, Z_MEM_ERROR); + return Z_MEM_ERROR; } - - /* Generic error return - leave the prefix, delete the compressed - * data, reallocate the chunkdata to remove the potentially large - * amount of compressed data. - */ +} +#endif /* READ_COMPRESSED_TEXT */ + +#ifdef PNG_READ_iCCP_SUPPORTED +/* Perform a partial read and decompress, producing 'avail_out' bytes and + * reading from the current chunk as required. + */ +static int +png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, + png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, + int finish) +{ + if (png_ptr->zowner == png_ptr->chunk_name) { - png_charp text = png_malloc_warn(png_ptr, prefix_size + 1); - - if (text != NULL) + int ret; + + /* next_in and avail_in must have been initialized by the caller. */ + png_ptr->zstream.next_out = next_out; + png_ptr->zstream.avail_out = 0; /* set in the loop */ + + do { - if (prefix_size > 0) - png_memcpy(text, png_ptr->chunkdata, prefix_size); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = text; - - /* This is an extra zero in the 'uncompressed' part. */ - *(png_ptr->chunkdata + prefix_size) = 0x00; + if (png_ptr->zstream.avail_in == 0) + { + if (read_size > *chunk_bytes) + read_size = (uInt)*chunk_bytes; + *chunk_bytes -= read_size; + + if (read_size > 0) + png_crc_read(png_ptr, read_buffer, read_size); + + png_ptr->zstream.next_in = read_buffer; + png_ptr->zstream.avail_in = read_size; + } + + if (png_ptr->zstream.avail_out == 0) + { + uInt avail = ZLIB_IO_MAX; + if (avail > *out_size) + avail = (uInt)*out_size; + *out_size -= avail; + + png_ptr->zstream.avail_out = avail; + } + + /* Use Z_SYNC_FLUSH when there is no more chunk data to ensure that all + * the available output is produced; this allows reading of truncated + * streams. + */ + ret = inflate(&png_ptr->zstream, + *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); } - /* Ignore a malloc error here - it is safe. */ + while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); + + *out_size += png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* Should not be required, but is safe */ + + /* Ensure the error message pointer is always set: */ + png_zstream_error(png_ptr, ret); + return ret; } - *newlength = prefix_size; + else + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("zstream unclaimed"); + return Z_STREAM_ERROR; + } } -#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */ +#endif /* Read and check the IDHR chunk */ + void /* PRIVATE */ -png_handle_IHDR(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[13]; png_uint_32 width, height; @@ -560,12 +827,12 @@ png_debug(1, "in png_handle_IHDR"); - if (png_ptr->mode & PNG_HAVE_IHDR) - png_error(png_ptr, "Out of place IHDR"); + if ((png_ptr->mode & PNG_HAVE_IHDR) != 0) + png_chunk_error(png_ptr, "out of place"); /* Check the length */ if (length != 13) - png_error(png_ptr, "Invalid IHDR chunk"); + png_chunk_error(png_ptr, "invalid"); png_ptr->mode |= PNG_HAVE_IHDR; @@ -614,8 +881,7 @@ } /* Set up other useful info */ - png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * - png_ptr->channels); + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); png_debug1(3, "channels = %d", png_ptr->channels); @@ -626,7 +892,7 @@ /* Read and check the palette */ void /* PRIVATE */ -png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_color palette[PNG_MAX_PALETTE_LENGTH]; int num, i; @@ -636,26 +902,33 @@ png_debug(1, "in png_handle_PLTE"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before PLTE"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + /* Moved to before the 'after IDAT' check below because otherwise duplicate + * PLTE chunks are potentially ignored (the spec says there shall not be more + * than one PLTE, the error is not treated as benign, so this check trumps + * the requirement that PLTE appears before IDAT.) + */ + else if ((png_ptr->mode & PNG_HAVE_PLTE) != 0) + png_chunk_error(png_ptr, "duplicate"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid PLTE after IDAT"); + /* This is benign because the non-benign error happened before, when an + * IDAT was encountered in a color-mapped image with no PLTE. + */ png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (png_ptr->mode & PNG_HAVE_PLTE) - png_error(png_ptr, "Duplicate PLTE chunk"); - png_ptr->mode |= PNG_HAVE_PLTE; - if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) { - png_warning(png_ptr, - "Ignoring PLTE chunk in grayscale PNG"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "ignored in grayscale PNG"); return; } @@ -669,19 +942,18 @@ if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) { + png_crc_finish(png_ptr, length); + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - png_warning(png_ptr, "Invalid palette chunk"); - png_crc_finish(png_ptr, length); - return; - } + png_chunk_benign_error(png_ptr, "invalid"); else - { - png_error(png_ptr, "Invalid palette chunk"); - } + png_chunk_error(png_ptr, "invalid"); + + return; } + /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ num = (int)length / 3; #ifdef PNG_POINTER_INDEXING_SUPPORTED @@ -720,214 +992,196 @@ } #ifndef PNG_READ_OPT_PLTE_SUPPORTED - else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ + else if (png_crc_error(png_ptr) != 0) /* Only if we have a CRC error */ { /* If we don't want to use the data from an ancillary chunk, * we have two options: an error abort, or a warning and we * ignore the data in this chunk (which should be OK, since * it's considered ancillary for a RGB or RGBA image). + * + * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the + * chunk type to determine whether to check the ancillary or the critical + * flags. */ - if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE) == 0) { - if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) - { - png_chunk_benign_error(png_ptr, "CRC error"); - } + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) != 0) + return; else - { - png_chunk_warning(png_ptr, "CRC error"); - return; - } + png_chunk_error(png_ptr, "CRC error"); } /* Otherwise, we (optionally) emit a warning and use the chunk. */ - else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) - { + else if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0) png_chunk_warning(png_ptr, "CRC error"); - } } #endif + /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its + * own copy of the palette. This has the side effect that when png_start_row + * is called (this happens after any call to png_read_update_info) the + * info_ptr palette gets changed. This is extremely unexpected and + * confusing. + * + * Fix this by not sharing the palette in this way. + */ png_set_PLTE(png_ptr, info_ptr, palette, num); + /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before + * IDAT. Prior to 1.6.0 this was not checked; instead the code merely + * checked the apparent validity of a tRNS chunk inserted before PLTE on a + * palette PNG. 1.6.0 attempts to rigorously follow the standard and + * therefore does a benign error if the erroneous condition is detected *and* + * cancels the tRNS if the benign error returns. The alternative is to + * amend the standard since it would be rather hypocritical of the standards + * maintainers to ignore it. + */ #ifdef PNG_READ_tRNS_SUPPORTED - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + if (png_ptr->num_trans > 0 || + (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)) { - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) - { - if (png_ptr->num_trans > (png_uint_16)num) - { - png_warning(png_ptr, "Truncating incorrect tRNS chunk length"); - png_ptr->num_trans = (png_uint_16)num; - } - - if (info_ptr->num_trans > (png_uint_16)num) - { - png_warning(png_ptr, "Truncating incorrect info tRNS chunk length"); - info_ptr->num_trans = (png_uint_16)num; - } - } + /* Cancel this because otherwise it would be used if the transforms + * require it. Don't cancel the 'valid' flag because this would prevent + * detection of duplicate chunks. + */ + png_ptr->num_trans = 0; + + if (info_ptr != NULL) + info_ptr->num_trans = 0; + + png_chunk_benign_error(png_ptr, "tRNS must be after"); } #endif +#ifdef PNG_READ_hIST_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) + png_chunk_benign_error(png_ptr, "hIST must be after"); +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) + png_chunk_benign_error(png_ptr, "bKGD must be after"); +#endif } void /* PRIVATE */ -png_handle_IEND(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_debug(1, "in png_handle_IEND"); - if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) - { - png_error(png_ptr, "No image in file"); - } + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0 || + (png_ptr->mode & PNG_HAVE_IDAT) == 0) + png_chunk_error(png_ptr, "out of place"); png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); + png_crc_finish(png_ptr, length); + if (length != 0) - { - png_warning(png_ptr, "Incorrect IEND chunk length"); - } - - png_crc_finish(png_ptr, length); - - PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */ + png_chunk_benign_error(png_ptr, "invalid"); + + PNG_UNUSED(info_ptr) } #ifdef PNG_READ_gAMA_SUPPORTED void /* PRIVATE */ -png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_fixed_point igamma; png_byte buf[4]; png_debug(1, "in png_handle_gAMA"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before gAMA"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Invalid gAMA after IDAT"); png_crc_finish(png_ptr, length); - return; - } - - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place gAMA chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA) -#ifdef PNG_READ_sRGB_SUPPORTED - && !(info_ptr->valid & PNG_INFO_sRGB) -#endif - ) - { - png_warning(png_ptr, "Duplicate gAMA chunk"); - png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 4) { - png_warning(png_ptr, "Incorrect gAMA chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 4); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; igamma = png_get_fixed_point(NULL, buf); - /* Check for zero gamma or an error. */ - if (igamma <= 0) - { - png_warning(png_ptr, - "Ignoring gAMA chunk with out of range gamma"); - - return; - } - -# ifdef PNG_READ_sRGB_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) - { - if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) - { - PNG_WARNING_PARAMETERS(p) - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, igamma); - png_formatted_warning(png_ptr, p, - "Ignoring incorrect gAMA value @1 when sRGB is also present"); - return; - } - } -# endif /* PNG_READ_sRGB_SUPPORTED */ - -# ifdef PNG_READ_GAMMA_SUPPORTED - /* Gamma correction on read is supported. */ - png_ptr->gamma = igamma; -# endif - /* And set the 'info' structure members. */ - png_set_gAMA_fixed(png_ptr, info_ptr, igamma); + png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma); + png_colorspace_sync(png_ptr, info_ptr); } #endif #ifdef PNG_READ_sBIT_SUPPORTED void /* PRIVATE */ -png_handle_sBIT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_size_t truelen; + unsigned int truelen, i; + png_byte sample_depth; png_byte buf[4]; png_debug(1, "in png_handle_sBIT"); - buf[0] = buf[1] = buf[2] = buf[3] = 0; - - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sBIT"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Invalid sBIT after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (png_ptr->mode & PNG_HAVE_PLTE) + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) != 0) { - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place sBIT chunk"); - } - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) - { - png_warning(png_ptr, "Duplicate sBIT chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + { truelen = 3; + sample_depth = 8; + } else - truelen = (png_size_t)png_ptr->channels; + { + truelen = png_ptr->channels; + sample_depth = png_ptr->bit_depth; + } if (length != truelen || length > 4) { - png_warning(png_ptr, "Incorrect sBIT chunk length"); + png_chunk_benign_error(png_ptr, "invalid"); png_crc_finish(png_ptr, length); return; } + buf[0] = buf[1] = buf[2] = buf[3] = sample_depth; png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; - if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + for (i=0; i sample_depth) + { + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) { png_ptr->sig_bit.red = buf[0]; png_ptr->sig_bit.green = buf[1]; @@ -950,377 +1204,416 @@ #ifdef PNG_READ_cHRM_SUPPORTED void /* PRIVATE */ -png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[32]; - png_fixed_point x_white, y_white, x_red, y_red, x_green, y_green, x_blue, - y_blue; + png_xy xy; png_debug(1, "in png_handle_cHRM"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before cHRM"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Invalid cHRM after IDAT"); png_crc_finish(png_ptr, length); - return; - } - - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Missing PLTE before cHRM"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM) -# ifdef PNG_READ_sRGB_SUPPORTED - && !(info_ptr->valid & PNG_INFO_sRGB) -# endif - ) - { - png_warning(png_ptr, "Duplicate cHRM chunk"); - png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 32) { - png_warning(png_ptr, "Incorrect cHRM chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 32); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; - x_white = png_get_fixed_point(NULL, buf); - y_white = png_get_fixed_point(NULL, buf + 4); - x_red = png_get_fixed_point(NULL, buf + 8); - y_red = png_get_fixed_point(NULL, buf + 12); - x_green = png_get_fixed_point(NULL, buf + 16); - y_green = png_get_fixed_point(NULL, buf + 20); - x_blue = png_get_fixed_point(NULL, buf + 24); - y_blue = png_get_fixed_point(NULL, buf + 28); - - if (x_white == PNG_FIXED_ERROR || - y_white == PNG_FIXED_ERROR || - x_red == PNG_FIXED_ERROR || - y_red == PNG_FIXED_ERROR || - x_green == PNG_FIXED_ERROR || - y_green == PNG_FIXED_ERROR || - x_blue == PNG_FIXED_ERROR || - y_blue == PNG_FIXED_ERROR) + xy.whitex = png_get_fixed_point(NULL, buf); + xy.whitey = png_get_fixed_point(NULL, buf + 4); + xy.redx = png_get_fixed_point(NULL, buf + 8); + xy.redy = png_get_fixed_point(NULL, buf + 12); + xy.greenx = png_get_fixed_point(NULL, buf + 16); + xy.greeny = png_get_fixed_point(NULL, buf + 20); + xy.bluex = png_get_fixed_point(NULL, buf + 24); + xy.bluey = png_get_fixed_point(NULL, buf + 28); + + if (xy.whitex == PNG_FIXED_ERROR || + xy.whitey == PNG_FIXED_ERROR || + xy.redx == PNG_FIXED_ERROR || + xy.redy == PNG_FIXED_ERROR || + xy.greenx == PNG_FIXED_ERROR || + xy.greeny == PNG_FIXED_ERROR || + xy.bluex == PNG_FIXED_ERROR || + xy.bluey == PNG_FIXED_ERROR) { - png_warning(png_ptr, "Ignoring cHRM chunk with negative chromaticities"); + png_chunk_benign_error(png_ptr, "invalid values"); return; } -#ifdef PNG_READ_sRGB_SUPPORTED - if ((info_ptr != NULL) && (info_ptr->valid & PNG_INFO_sRGB)) + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + return; + + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0) { - if (PNG_OUT_OF_RANGE(x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(x_red, 64000L, 1000) || - PNG_OUT_OF_RANGE(y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(y_green, 60000L, 1000) || - PNG_OUT_OF_RANGE(x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(y_blue, 6000, 1000)) - { - PNG_WARNING_PARAMETERS(p) - - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, x_white); - png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_fixed, y_white); - png_warning_parameter_signed(p, 3, PNG_NUMBER_FORMAT_fixed, x_red); - png_warning_parameter_signed(p, 4, PNG_NUMBER_FORMAT_fixed, y_red); - png_warning_parameter_signed(p, 5, PNG_NUMBER_FORMAT_fixed, x_green); - png_warning_parameter_signed(p, 6, PNG_NUMBER_FORMAT_fixed, y_green); - png_warning_parameter_signed(p, 7, PNG_NUMBER_FORMAT_fixed, x_blue); - png_warning_parameter_signed(p, 8, PNG_NUMBER_FORMAT_fixed, y_blue); - - png_formatted_warning(png_ptr, p, - "Ignoring incorrect cHRM white(@1,@2) r(@3,@4)g(@5,@6)b(@7,@8) " - "when sRGB is also present"); - } + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "duplicate"); return; } -#endif /* PNG_READ_sRGB_SUPPORTED */ - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - /* Store the _white values as default coefficients for the rgb to gray - * operation if it is supported. - */ - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) - { - /* png_set_background has not been called, the coefficients must be in - * range for the following to work without overflow. - */ - if (y_red <= (1<<17) && y_green <= (1<<17) && y_blue <= (1<<17)) - { - /* The y values are chromaticities: Y/X+Y+Z, the weights for the gray - * transformation are simply the normalized Y values for red, green and - * blue scaled by 32768. - */ - png_uint_32 w = y_red + y_green + y_blue; - - png_ptr->rgb_to_gray_red_coeff = (png_uint_16)(((png_uint_32)y_red * - 32768)/w); - png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green - * 32768)/w); - png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(((png_uint_32)y_blue * - 32768)/w); - } - } -#endif - - png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red, - x_green, y_green, x_blue, y_blue); + + png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy, + 1/*prefer cHRM values*/); + png_colorspace_sync(png_ptr, info_ptr); } #endif #ifdef PNG_READ_sRGB_SUPPORTED void /* PRIVATE */ -png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - int intent; - png_byte buf[1]; + png_byte intent; png_debug(1, "in png_handle_sRGB"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sRGB"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Invalid sRGB after IDAT"); png_crc_finish(png_ptr, length); - return; - } - - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place sRGB chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB)) - { - png_warning(png_ptr, "Duplicate sRGB chunk"); - png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } if (length != 1) { - png_warning(png_ptr, "Incorrect sRGB chunk length"); png_crc_finish(png_ptr, length); - return; - } - - png_crc_read(png_ptr, buf, 1); - - if (png_crc_finish(png_ptr, 0)) - return; - - intent = buf[0]; - - /* Check for bad intent */ - if (intent >= PNG_sRGB_INTENT_LAST) - { - png_warning(png_ptr, "Unknown sRGB intent"); + png_chunk_benign_error(png_ptr, "invalid"); return; } -#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_gAMA)) + png_crc_read(png_ptr, &intent, 1); + + if (png_crc_finish(png_ptr, 0) != 0) + return; + + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + return; + + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) != 0) { - if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500L, 500)) - { - PNG_WARNING_PARAMETERS(p) - - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, - info_ptr->gamma); - - png_formatted_warning(png_ptr, p, - "Ignoring incorrect gAMA value @1 when sRGB is also present"); - } + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "too many profiles"); + return; } -#endif /* PNG_READ_gAMA_SUPPORTED */ - -#ifdef PNG_READ_cHRM_SUPPORTED - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_cHRM)) - if (PNG_OUT_OF_RANGE(info_ptr->x_white, 31270, 1000) || - PNG_OUT_OF_RANGE(info_ptr->y_white, 32900, 1000) || - PNG_OUT_OF_RANGE(info_ptr->x_red, 64000L, 1000) || - PNG_OUT_OF_RANGE(info_ptr->y_red, 33000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->x_green, 30000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->y_green, 60000L, 1000) || - PNG_OUT_OF_RANGE(info_ptr->x_blue, 15000, 1000) || - PNG_OUT_OF_RANGE(info_ptr->y_blue, 6000, 1000)) - { - png_warning(png_ptr, - "Ignoring incorrect cHRM value when sRGB is also present"); - } -#endif /* PNG_READ_cHRM_SUPPORTED */ - - png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, intent); + + (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent); + png_colorspace_sync(png_ptr, info_ptr); } -#endif /* PNG_READ_sRGB_SUPPORTED */ +#endif /* READ_sRGB */ #ifdef PNG_READ_iCCP_SUPPORTED void /* PRIVATE */ -png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) -/* Note: this does not properly handle chunks that are > 64K under DOS */ +png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) +/* Note: this does not properly handle profiles that are > 64K under DOS */ { - png_byte compression_type; - png_bytep pC; - png_charp profile; - png_uint_32 skip = 0; - png_uint_32 profile_size; - png_alloc_size_t profile_length; - png_size_t slength, prefix_length, data_length; + png_const_charp errmsg = NULL; /* error message output, or no error */ + int finished = 0; /* crc checked */ png_debug(1, "in png_handle_iCCP"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iCCP"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) != 0) { - png_warning(png_ptr, "Invalid iCCP after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (png_ptr->mode & PNG_HAVE_PLTE) - /* Should be an error, but we can cope with it */ - png_warning(png_ptr, "Out of place iCCP chunk"); - - if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP)) + /* Consistent with all the above colorspace handling an obviously *invalid* + * chunk is just ignored, so does not invalidate the color space. An + * alternative is to set the 'invalid' flags at the start of this routine + * and only clear them in they were not set before and all the tests pass. + * The minimum 'deflate' stream is assumed to be just the 2 byte header and + * 4 byte checksum. The keyword must be at least one character and there is + * a terminator (0) byte and the compression method. + */ + if (length < 9) { - png_warning(png_ptr, "Duplicate iCCP chunk"); + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too short"); + return; + } + + /* If a colorspace error has already been output skip this chunk */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) != 0) + { png_crc_finish(png_ptr, length); return; } -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "iCCP chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (profile = png_ptr->chunkdata; *profile; profile++) - /* Empty loop to find end of name */ ; - - ++profile; - - /* There should be at least one zero (the compression type byte) - * following the separator, and we should be on it - */ - if (profile >= png_ptr->chunkdata + slength - 1) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Malformed iCCP chunk"); - return; - } - - /* Compression_type should always be zero */ - compression_type = *profile++; - - if (compression_type) - { - png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk"); - compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8 - wrote nonzero) */ + uInt read_length, keyword_length; + char keyword[81]; + + /* Find the keyword; the keyword plus separator and compression method + * bytes can be at most 81 characters long. + */ + read_length = 81; /* maximum */ + if (read_length > length) + read_length = (uInt)length; + + png_crc_read(png_ptr, (png_bytep)keyword, read_length); + length -= read_length; + + keyword_length = 0; + while (keyword_length < 80 && keyword_length < read_length && + keyword[keyword_length] != 0) + ++keyword_length; + + /* TODO: make the keyword checking common */ + if (keyword_length >= 1 && keyword_length <= 79) + { + /* We only understand '0' compression - deflate - so if we get a + * different value we can't safely decode the chunk. + */ + if (keyword_length+1 < read_length && + keyword[keyword_length+1] == PNG_COMPRESSION_TYPE_BASE) + { + read_length -= keyword_length+2; + + if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK) + { + Byte profile_header[132]; + Byte local_buffer[PNG_INFLATE_BUF_SIZE]; + png_alloc_size_t size = (sizeof profile_header); + + png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2); + png_ptr->zstream.avail_in = read_length; + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, profile_header, &size, + 0/*finish: don't, because the output is too small*/); + + if (size == 0) + { + /* We have the ICC profile header; do the basic header checks. + */ + const png_uint_32 profile_length = + png_get_uint_32(profile_header); + + if (png_icc_check_length(png_ptr, &png_ptr->colorspace, + keyword, profile_length) != 0) + { + /* The length is apparently ok, so we can check the 132 + * byte header. + */ + if (png_icc_check_header(png_ptr, &png_ptr->colorspace, + keyword, profile_length, profile_header, + png_ptr->color_type) != 0) + { + /* Now read the tag table; a variable size buffer is + * needed at this point, allocate one for the whole + * profile. The header check has already validated + * that none of these stuff will overflow. + */ + const png_uint_32 tag_count = png_get_uint_32( + profile_header+128); + png_bytep profile = png_read_buffer(png_ptr, + profile_length, 2/*silent*/); + + if (profile != NULL) + { + memcpy(profile, profile_header, + (sizeof profile_header)); + + size = 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header), &size, 0); + + /* Still expect a buffer error because we expect + * there to be some tag data! + */ + if (size == 0) + { + if (png_icc_check_tag_table(png_ptr, + &png_ptr->colorspace, keyword, profile_length, + profile) != 0) + { + /* The profile has been validated for basic + * security issues, so read the whole thing in. + */ + size = profile_length - (sizeof profile_header) + - 12 * tag_count; + + (void)png_inflate_read(png_ptr, local_buffer, + (sizeof local_buffer), &length, + profile + (sizeof profile_header) + + 12 * tag_count, &size, 1/*finish*/); + + if (length > 0 && !(png_ptr->flags & + PNG_FLAG_BENIGN_ERRORS_WARN)) + errmsg = "extra compressed data"; + + /* But otherwise allow extra data: */ + else if (size == 0) + { + if (length > 0) + { + /* This can be handled completely, so + * keep going. + */ + png_chunk_warning(png_ptr, + "extra compressed data"); + } + + png_crc_finish(png_ptr, length); + finished = 1; + +# ifdef PNG_sRGB_SUPPORTED + /* Check for a match against sRGB */ + png_icc_set_sRGB(png_ptr, + &png_ptr->colorspace, profile, + png_ptr->zstream.adler); +# endif + + /* Steal the profile for info_ptr. */ + if (info_ptr != NULL) + { + png_free_data(png_ptr, info_ptr, + PNG_FREE_ICCP, 0); + + info_ptr->iccp_name = png_voidcast(char*, + png_malloc_base(png_ptr, + keyword_length+1)); + if (info_ptr->iccp_name != NULL) + { + memcpy(info_ptr->iccp_name, keyword, + keyword_length+1); + info_ptr->iccp_proflen = + profile_length; + info_ptr->iccp_profile = profile; + png_ptr->read_buffer = NULL; /*steal*/ + info_ptr->free_me |= PNG_FREE_ICCP; + info_ptr->valid |= PNG_INFO_iCCP; + } + + else + { + png_ptr->colorspace.flags |= + PNG_COLORSPACE_INVALID; + errmsg = "out of memory"; + } + } + + /* else the profile remains in the read + * buffer which gets reused for subsequent + * chunks. + */ + + if (info_ptr != NULL) + png_colorspace_sync(png_ptr, info_ptr); + + if (errmsg == NULL) + { + png_ptr->zowner = 0; + return; + } + } + + else if (size > 0) + errmsg = "truncated"; + + else + errmsg = png_ptr->zstream.msg; + } + + /* else png_icc_check_tag_table output an error */ + } + + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "out of memory"; + } + + /* else png_icc_check_header output an error */ + } + + /* else png_icc_check_length output an error */ + } + + else /* profile truncated */ + errmsg = png_ptr->zstream.msg; + + /* Release the stream */ + png_ptr->zowner = 0; + } + + else /* png_inflate_claim failed */ + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "bad compression method"; /* or missing */ + } + + else + errmsg = "bad keyword"; } - prefix_length = profile - png_ptr->chunkdata; - png_decompress_chunk(png_ptr, compression_type, - slength, prefix_length, &data_length); - - profile_length = data_length - prefix_length; - - if (prefix_length > data_length || profile_length < 4) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "Profile size field missing from iCCP chunk"); - return; - } - - /* Check the profile_size recorded in the first 32 bits of the ICC profile */ - pC = (png_bytep)(png_ptr->chunkdata + prefix_length); - profile_size = ((*(pC )) << 24) | - ((*(pC + 1)) << 16) | - ((*(pC + 2)) << 8) | - ((*(pC + 3)) ); - - /* NOTE: the following guarantees that 'profile_length' fits into 32 bits, - * because profile_size is a 32 bit value. - */ - if (profile_size < profile_length) - profile_length = profile_size; - - /* And the following guarantees that profile_size == profile_length. */ - if (profile_size > profile_length) - { - PNG_WARNING_PARAMETERS(p) - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - - png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_u, profile_size); - png_warning_parameter_unsigned(p, 2, PNG_NUMBER_FORMAT_u, profile_length); - png_formatted_warning(png_ptr, p, - "Ignoring iCCP chunk with declared size = @1 and actual length = @2"); - return; - } - - png_set_iCCP(png_ptr, info_ptr, png_ptr->chunkdata, - compression_type, (png_bytep)png_ptr->chunkdata + prefix_length, - profile_size); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + else + errmsg = "too many profiles"; + + /* Failure: the reason is in 'errmsg' */ + if (finished == 0) + png_crc_finish(png_ptr, length); + + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + if (errmsg != NULL) /* else already output */ + png_chunk_benign_error(png_ptr, errmsg); } -#endif /* PNG_READ_iCCP_SUPPORTED */ +#endif /* READ_iCCP */ #ifdef PNG_READ_sPLT_SUPPORTED void /* PRIVATE */ -png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { - png_bytep entry_start; + png_bytep entry_start, buffer; png_sPLT_t new_palette; png_sPLT_entryp pp; png_uint_32 data_length; int entry_size, i; png_uint_32 skip = 0; - png_size_t slength; png_uint_32 dl; png_size_t max_dl; png_debug(1, "in png_handle_sPLT"); #ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) { if (png_ptr->user_chunk_cache_max == 1) @@ -1338,55 +1631,53 @@ } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sPLT"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid sPLT after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } #ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) + if (length > 65535U) { - png_warning(png_ptr, "sPLT chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; } #endif - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1); + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + if (buffer == NULL) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); + return; + } + /* WARNING: this may break if size_t is less than 32 bits; it is assumed * that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a * potential breakage point if the types in pngconf.h aren't exactly right. */ - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip) != 0) return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (entry_start = (png_bytep)png_ptr->chunkdata; *entry_start; - entry_start++) + + buffer[length] = 0; + + for (entry_start = buffer; *entry_start; entry_start++) /* Empty loop to find end of name */ ; ++entry_start; /* A sample depth should follow the separator, and we should be on it */ - if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2) + if (entry_start > buffer + length - 2) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_warning(png_ptr, "malformed sPLT chunk"); return; } @@ -1394,23 +1685,19 @@ new_palette.depth = *entry_start++; entry_size = (new_palette.depth == 8 ? 6 : 10); /* This must fit in a png_uint_32 because it is derived from the original - * chunk data length (and use 'length', not 'slength' here for clarity - - * they are guaranteed to be the same, see the tests above.) + * chunk data length. */ - data_length = length - (png_uint_32)(entry_start - - (png_bytep)png_ptr->chunkdata); + data_length = length - (png_uint_32)(entry_start - buffer); /* Integrity-check the data length */ - if (data_length % entry_size) + if ((data_length % entry_size) != 0) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_warning(png_ptr, "sPLT chunk has bad length"); return; } dl = (png_int_32)(data_length / entry_size); - max_dl = PNG_SIZE_MAX / png_sizeof(png_sPLT_entry); + max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry)); if (dl > max_dl) { @@ -1421,7 +1708,7 @@ new_palette.nentries = (png_int_32)(data_length / entry_size); new_palette.entries = (png_sPLT_entryp)png_malloc_warn( - png_ptr, new_palette.nentries * png_sizeof(png_sPLT_entry)); + png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry))); if (new_palette.entries == NULL) { @@ -1479,38 +1766,36 @@ #endif /* Discard all chunk data except the name and stash that */ - new_palette.name = png_ptr->chunkdata; + new_palette.name = (png_charp)buffer; png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_free(png_ptr, new_palette.entries); } -#endif /* PNG_READ_sPLT_SUPPORTED */ +#endif /* READ_sPLT */ #ifdef PNG_READ_tRNS_SUPPORTED void /* PRIVATE */ -png_handle_tRNS(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_tRNS"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tRNS"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid tRNS after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0) { - png_warning(png_ptr, "Duplicate tRNS chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } @@ -1520,8 +1805,8 @@ if (length != 2) { - png_warning(png_ptr, "Incorrect tRNS chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } @@ -1536,12 +1821,12 @@ if (length != 6) { - png_warning(png_ptr, "Incorrect tRNS chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } - png_crc_read(png_ptr, buf, (png_size_t)length); + png_crc_read(png_ptr, buf, length); png_ptr->num_trans = 1; png_ptr->trans_color.red = png_get_uint_16(buf); png_ptr->trans_color.green = png_get_uint_16(buf + 2); @@ -1550,44 +1835,43 @@ else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (!(png_ptr->mode & PNG_HAVE_PLTE)) + if ((png_ptr->mode & PNG_HAVE_PLTE) == 0) { - /* Should be an error, but we can cope with it. */ - png_warning(png_ptr, "Missing PLTE before tRNS"); - } - - if (length > (png_uint_32)png_ptr->num_palette || - length > PNG_MAX_PALETTE_LENGTH) - { - png_warning(png_ptr, "Incorrect tRNS chunk length"); + /* TODO: is this actually an error in the ISO spec? */ png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - if (length == 0) + if (length > png_ptr->num_palette || length > PNG_MAX_PALETTE_LENGTH || + length == 0) { - png_warning(png_ptr, "Zero length tRNS chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } - png_crc_read(png_ptr, readbuf, (png_size_t)length); + png_crc_read(png_ptr, readbuf, length); png_ptr->num_trans = (png_uint_16)length; } else { - png_warning(png_ptr, "tRNS chunk not allowed with alpha channel"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid with alpha channel"); return; } - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) { png_ptr->num_trans = 0; return; } + /* TODO: this is a horrible side effect in the palette case because the + * png_struct ends up with a pointer to the tRNS buffer owned by the + * png_info. Fix this. + */ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, &(png_ptr->trans_color)); } @@ -1595,43 +1879,37 @@ #ifdef PNG_READ_bKGD_SUPPORTED void /* PRIVATE */ -png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_size_t truelen; + unsigned int truelen; png_byte buf[6]; png_color_16 background; png_debug(1, "in png_handle_bKGD"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before bKGD"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + (png_ptr->mode & PNG_HAVE_PLTE) == 0)) { - png_warning(png_ptr, "Invalid bKGD after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - !(png_ptr->mode & PNG_HAVE_PLTE)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) { - png_warning(png_ptr, "Missing PLTE before bKGD"); png_crc_finish(png_ptr, length); - return; - } - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) - { - png_warning(png_ptr, "Duplicate bKGD chunk"); - png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) truelen = 1; - else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) truelen = 6; else @@ -1639,14 +1917,14 @@ if (length != truelen) { - png_warning(png_ptr, "Incorrect bKGD chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; /* We convert the index value into RGB components so that we can allow @@ -1658,11 +1936,11 @@ { background.index = buf[0]; - if (info_ptr && info_ptr->num_palette) + if (info_ptr != NULL && info_ptr->num_palette != 0) { if (buf[0] >= info_ptr->num_palette) { - png_warning(png_ptr, "Incorrect bKGD chunk index value"); + png_chunk_benign_error(png_ptr, "invalid index"); return; } @@ -1677,7 +1955,7 @@ background.gray = 0; } - else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ + else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */ { background.index = 0; background.red = @@ -1701,44 +1979,37 @@ #ifdef PNG_READ_hIST_SUPPORTED void /* PRIVATE */ -png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int num, i; png_uint_16 readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_hIST"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before hIST"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0 || + (png_ptr->mode & PNG_HAVE_PLTE) == 0) { - png_warning(png_ptr, "Invalid hIST after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (!(png_ptr->mode & PNG_HAVE_PLTE)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) { - png_warning(png_ptr, "Missing PLTE before hIST"); png_crc_finish(png_ptr, length); - return; - } - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) - { - png_warning(png_ptr, "Duplicate hIST chunk"); - png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } num = length / 2 ; - if (num != (unsigned int)png_ptr->num_palette || num > - (unsigned int)PNG_MAX_PALETTE_LENGTH) + if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH) { - png_warning(png_ptr, "Incorrect hIST chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } @@ -1750,7 +2021,7 @@ readbuf[i] = png_get_uint_16(buf); } - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; png_set_hIST(png_ptr, info_ptr, readbuf); @@ -1759,7 +2030,7 @@ #ifdef PNG_READ_pHYs_SUPPORTED void /* PRIVATE */ -png_handle_pHYs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; png_uint_32 res_x, res_y; @@ -1767,33 +2038,33 @@ png_debug(1, "in png_handle_pHYs"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pHYs"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid pHYs after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) != 0) { - png_warning(png_ptr, "Duplicate pHYs chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (length != 9) { - png_warning(png_ptr, "Incorrect pHYs chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; res_x = png_get_uint_32(buf); @@ -1805,7 +2076,7 @@ #ifdef PNG_READ_oFFs_SUPPORTED void /* PRIVATE */ -png_handle_oFFs(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; png_int_32 offset_x, offset_y; @@ -1813,33 +2084,33 @@ png_debug(1, "in png_handle_oFFs"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before oFFs"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid oFFs after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) != 0) { - png_warning(png_ptr, "Duplicate oFFs chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } if (length != 9) { - png_warning(png_ptr, "Incorrect oFFs chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; offset_x = png_get_int_32(buf); @@ -1852,71 +2123,64 @@ #ifdef PNG_READ_pCAL_SUPPORTED /* Read the pCAL chunk (described in the PNG Extensions document) */ void /* PRIVATE */ -png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_int_32 X0, X1; png_byte type, nparams; - png_charp buf, units, endptr; + png_bytep buffer, buf, units, endptr; png_charpp params; - png_size_t slength; int i; png_debug(1, "in png_handle_pCAL"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before pCAL"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid pCAL after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) != 0) { - png_warning(png_ptr, "Duplicate pCAL chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)", length + 1); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - - if (png_ptr->chunkdata == NULL) + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + + if (buffer == NULL) { - png_warning(png_ptr, "No memory for pCAL purpose"); + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) return; - } - - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ + + buffer[length] = 0; /* Null terminate the last string */ png_debug(3, "Finding end of pCAL purpose string"); - for (buf = png_ptr->chunkdata; *buf; buf++) + for (buf = buffer; *buf; buf++) /* Empty loop */ ; - endptr = png_ptr->chunkdata + slength; + endptr = buffer + length; /* We need to have at least 12 bytes after the purpose string * in order to get the parameter information. */ if (endptr <= buf + 12) { - png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_chunk_benign_error(png_ptr, "invalid"); return; } @@ -1936,15 +2200,13 @@ (type == PNG_EQUATION_ARBITRARY && nparams != 3) || (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) { - png_warning(png_ptr, "Invalid pCAL parameters for equation type"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_chunk_benign_error(png_ptr, "invalid parameter count"); return; } else if (type >= PNG_EQUATION_LAST) { - png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); + png_chunk_benign_error(png_ptr, "unrecognized equation type"); } for (buf = units; *buf; buf++) @@ -1952,43 +2214,37 @@ png_debug(3, "Allocating pCAL parameters array"); - params = (png_charpp)png_malloc_warn(png_ptr, - (png_size_t)(nparams * png_sizeof(png_charp))); + params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + nparams * (sizeof (png_charp)))); if (params == NULL) { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_warning(png_ptr, "No memory for pCAL params"); + png_chunk_benign_error(png_ptr, "out of memory"); return; } /* Get pointers to the start of each parameter string. */ - for (i = 0; i < (int)nparams; i++) + for (i = 0; i < nparams; i++) { buf++; /* Skip the null string terminator from previous parameter. */ png_debug1(3, "Reading pCAL parameter %d", i); - for (params[i] = buf; buf <= endptr && *buf != 0x00; buf++) + for (params[i] = (png_charp)buf; buf <= endptr && *buf != 0; buf++) /* Empty loop to move past each parameter string */ ; /* Make sure we haven't run out of data yet */ if (buf > endptr) { - png_warning(png_ptr, "Invalid pCAL data"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; png_free(png_ptr, params); + png_chunk_benign_error(png_ptr, "invalid data"); return; } } - png_set_pCAL(png_ptr, info_ptr, png_ptr->chunkdata, X0, X1, type, nparams, - units, params); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams, + (png_charp)units, params); + png_free(png_ptr, params); } #endif @@ -1996,67 +2252,61 @@ #ifdef PNG_READ_sCAL_SUPPORTED /* Read the sCAL chunk */ void /* PRIVATE */ -png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_size_t slength, i; + png_bytep buffer; + png_size_t i; int state; png_debug(1, "in png_handle_sCAL"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before sCAL"); - - else if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) { - png_warning(png_ptr, "Invalid sCAL after IDAT"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); return; } - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL) != 0) { - png_warning(png_ptr, "Duplicate sCAL chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } /* Need unit type, width, \0, height: minimum 4 bytes */ else if (length < 4) { - png_warning(png_ptr, "sCAL chunk too short"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", length + 1); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - - if (png_ptr->chunkdata == NULL) + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); + + if (buffer == NULL) { - png_warning(png_ptr, "Out of memory while processing sCAL chunk"); + png_chunk_benign_error(png_ptr, "out of memory"); png_crc_finish(png_ptr, length); return; } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */ - - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_read(png_ptr, buffer, length); + buffer[length] = 0; /* Null terminate the last string */ + + if (png_crc_finish(png_ptr, 0) != 0) return; - } /* Validate the unit. */ - if (png_ptr->chunkdata[0] != 1 && png_ptr->chunkdata[0] != 2) + if (buffer[0] != 1 && buffer[0] != 2) { - png_warning(png_ptr, "Invalid sCAL ignored: invalid unit"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_chunk_benign_error(png_ptr, "invalid unit"); return; } @@ -2066,70 +2316,65 @@ i = 1; state = 0; - if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) || - i >= slength || png_ptr->chunkdata[i++] != 0) - png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format"); - - else if (!PNG_FP_IS_POSITIVE(state)) - png_warning(png_ptr, "Invalid sCAL chunk ignored: non-positive width"); + if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 || + i >= length || buffer[i++] != 0) + png_chunk_benign_error(png_ptr, "bad width format"); + + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive width"); else { png_size_t heighti = i; state = 0; - if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) || - i != slength) - png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format"); - - else if (!PNG_FP_IS_POSITIVE(state)) - png_warning(png_ptr, - "Invalid sCAL chunk ignored: non-positive height"); + if (png_check_fp_number((png_const_charp)buffer, length, + &state, &i) == 0 || i != length) + png_chunk_benign_error(png_ptr, "bad height format"); + + else if (PNG_FP_IS_POSITIVE(state) == 0) + png_chunk_benign_error(png_ptr, "non-positive height"); else /* This is the (only) success case. */ - png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], - png_ptr->chunkdata+1, png_ptr->chunkdata+heighti); + png_set_sCAL_s(png_ptr, info_ptr, buffer[0], + (png_charp)buffer+1, (png_charp)buffer+heighti); } - - /* Clean up - just free the temporarily allocated buffer. */ - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; } #endif #ifdef PNG_READ_tIME_SUPPORTED void /* PRIVATE */ -png_handle_tIME(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[7]; png_time mod_time; png_debug(1, "in png_handle_tIME"); - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Out of place tIME chunk"); - - else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) != 0) { - png_warning(png_ptr, "Duplicate tIME chunk"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); return; } - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; if (length != 7) { - png_warning(png_ptr, "Incorrect tIME chunk length"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); return; } png_crc_read(png_ptr, buf, 7); - if (png_crc_finish(png_ptr, 0)) + if (png_crc_finish(png_ptr, 0) != 0) return; mod_time.second = buf[6]; @@ -2146,14 +2391,13 @@ #ifdef PNG_READ_tEXt_SUPPORTED /* Note: this does not properly handle chunks that are > 64K under DOS */ void /* PRIVATE */ -png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_textp text_ptr; + png_text text_info; + png_bytep buffer; png_charp key; png_charp text; png_uint_32 skip = 0; - png_size_t slength; - int ret; png_debug(1, "in png_handle_tEXt"); @@ -2168,84 +2412,59 @@ if (--png_ptr->user_chunk_cache_max == 1) { - png_warning(png_ptr, "No space in chunk cache for tEXt"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before tEXt"); - - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; #ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) + if (length > 65535U) { - png_warning(png_ptr, "tEXt chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; } #endif - png_free(png_ptr, png_ptr->chunkdata); - - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - - if (png_ptr->chunkdata == NULL) + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); + + if (buffer == NULL) { - png_warning(png_ptr, "No memory to process text chunk"); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, skip)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, skip) != 0) return; - } - - key = png_ptr->chunkdata; - - key[slength] = 0x00; + + key = (png_charp)buffer; + key[length] = 0; for (text = key; *text; text++) /* Empty loop to find end of key */ ; - if (text != key + slength) + if (text != key + length) text++; - text_ptr = (png_textp)png_malloc_warn(png_ptr, - png_sizeof(png_text)); - - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process text chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - text_ptr->compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr->key = key; - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; - text_ptr->itxt_length = 0; - text_ptr->text = text; - text_ptr->text_length = png_strlen(text); - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - png_free(png_ptr, text_ptr); - - if (ret) + text_info.compression = PNG_TEXT_COMPRESSION_NONE; + text_info.key = key; + text_info.lang = NULL; + text_info.lang_key = NULL; + text_info.itxt_length = 0; + text_info.text = text; + text_info.text_length = strlen(text); + + if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) != 0) png_warning(png_ptr, "Insufficient memory to process text chunk"); } #endif @@ -2253,13 +2472,11 @@ #ifdef PNG_READ_zTXt_SUPPORTED /* Note: this does not correctly handle chunks that are > 64K under DOS */ void /* PRIVATE */ -png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_textp text_ptr; - png_charp text; - int comp_type; - int ret; - png_size_t slength, prefix_len, data_len; + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 keyword_length; png_debug(1, "in png_handle_zTXt"); @@ -2274,123 +2491,101 @@ if (--png_ptr->user_chunk_cache_max == 1) { - png_warning(png_ptr, "No space in chunk cache for zTXt"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before zTXt"); - - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; -#ifdef PNG_MAX_MALLOC_64K - /* We will no doubt have problems with chunks even half this size, but - * there is no hard and fast rule to tell us where to stop. - */ - if (length > (png_uint_32)65535L) + buffer = png_read_buffer(png_ptr, length, 2/*silent*/); + + if (buffer == NULL) { - png_warning(png_ptr, "zTXt chunk too large to fit in memory"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of memory"); return; } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "Out of memory processing zTXt chunk"); + + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) return; - } - - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (text = png_ptr->chunkdata; *text; text++) - /* Empty loop */ ; - - /* zTXt must have some text after the chunkdataword */ - if (text >= png_ptr->chunkdata + slength - 2) - { - png_warning(png_ptr, "Truncated zTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } + + /* TODO: also check that the keyword contents match the spec! */ + for (keyword_length = 0; + keyword_length < length && buffer[keyword_length] != 0; + ++keyword_length) + /* Empty loop to find end of name */ ; + + if (keyword_length > 79 || keyword_length < 1) + errmsg = "bad keyword"; + + /* zTXt must have some LZ data after the keyword, although it may expand to + * zero bytes; we need a '\0' at the end of the keyword, the compression type + * then the LZ data: + */ + else if (keyword_length + 3 > length) + errmsg = "truncated"; + + else if (buffer[keyword_length+1] != PNG_COMPRESSION_TYPE_BASE) + errmsg = "unknown compression type"; else { - comp_type = *(++text); - - if (comp_type != PNG_TEXT_COMPRESSION_zTXt) - { - png_warning(png_ptr, "Unknown compression type in zTXt chunk"); - comp_type = PNG_TEXT_COMPRESSION_zTXt; - } - - text++; /* Skip the compression_method byte */ + png_alloc_size_t uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for iCCP + * and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, keyword_length+2, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + { + png_text text; + + /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except + * for the extra compression type byte and the fact that it isn't + * necessarily '\0' terminated. + */ + buffer = png_ptr->read_buffer; + buffer[uncompressed_length+(keyword_length+2)] = 0; + + text.compression = PNG_TEXT_COMPRESSION_zTXt; + text.key = (png_charp)buffer; + text.text = (png_charp)(buffer + keyword_length+2); + text.text_length = uncompressed_length; + text.itxt_length = 0; + text.lang = NULL; + text.lang_key = NULL; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) + errmsg = "insufficient memory"; + } + + else + errmsg = png_ptr->zstream.msg; } - prefix_len = text - png_ptr->chunkdata; - - png_decompress_chunk(png_ptr, comp_type, - (png_size_t)length, prefix_len, &data_len); - - text_ptr = (png_textp)png_malloc_warn(png_ptr, - png_sizeof(png_text)); - - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process zTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - text_ptr->compression = comp_type; - text_ptr->key = png_ptr->chunkdata; - text_ptr->lang = NULL; - text_ptr->lang_key = NULL; - text_ptr->itxt_length = 0; - text_ptr->text = png_ptr->chunkdata + prefix_len; - text_ptr->text_length = data_len; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - - if (ret) - png_error(png_ptr, "Insufficient memory to store zTXt chunk"); + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); } #endif #ifdef PNG_READ_iTXt_SUPPORTED /* Note: this does not correctly handle chunks that are > 64K under DOS */ void /* PRIVATE */ -png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_textp text_ptr; - png_charp key, lang, text, lang_key; - int comp_flag; - int comp_type = 0; - int ret; - png_size_t slength, prefix_len, data_len; + png_const_charp errmsg = NULL; + png_bytep buffer; + png_uint_32 prefix_length; png_debug(1, "in png_handle_iTXt"); @@ -2405,274 +2600,393 @@ if (--png_ptr->user_chunk_cache_max == 1) { - png_warning(png_ptr, "No space in chunk cache for iTXt"); png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "no space in chunk cache"); return; } } #endif - if (!(png_ptr->mode & PNG_HAVE_IHDR)) - png_error(png_ptr, "Missing IHDR before iTXt"); - - if (png_ptr->mode & PNG_HAVE_IDAT) + if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + png_chunk_error(png_ptr, "missing IHDR"); + + if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) png_ptr->mode |= PNG_AFTER_IDAT; -#ifdef PNG_MAX_MALLOC_64K - /* We will no doubt have problems with chunks even half this size, but - * there is no hard and fast rule to tell us where to stop. - */ - if (length > (png_uint_32)65535L) + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); + + if (buffer == NULL) { - png_warning(png_ptr, "iTXt chunk too large to fit in memory"); png_crc_finish(png_ptr, length); - return; - } -#endif - - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = (png_charp)png_malloc_warn(png_ptr, length + 1); - - if (png_ptr->chunkdata == NULL) - { - png_warning(png_ptr, "No memory to process iTXt chunk"); + png_chunk_benign_error(png_ptr, "out of memory"); return; } - slength = (png_size_t)length; - png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength); - - if (png_crc_finish(png_ptr, 0)) - { - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; + png_crc_read(png_ptr, buffer, length); + + if (png_crc_finish(png_ptr, 0) != 0) return; - } - - png_ptr->chunkdata[slength] = 0x00; - - for (lang = png_ptr->chunkdata; *lang; lang++) + + /* First the keyword. */ + for (prefix_length=0; + prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) /* Empty loop */ ; - lang++; /* Skip NUL separator */ - - /* iTXt must have a language tag (possibly empty), two compression bytes, - * translated keyword (possibly empty), and possibly some text after the - * keyword + /* Perform a basic check on the keyword length here. */ + if (prefix_length > 79 || prefix_length < 1) + errmsg = "bad keyword"; + + /* Expect keyword, compression flag, compression type, language, translated + * keyword (both may be empty but are 0 terminated) then the text, which may + * be empty. */ - - if (lang >= png_ptr->chunkdata + slength - 3) + else if (prefix_length + 5 > length) + errmsg = "truncated"; + + else if (buffer[prefix_length+1] == 0 || + (buffer[prefix_length+1] == 1 && + buffer[prefix_length+2] == PNG_COMPRESSION_TYPE_BASE)) { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; + int compressed = buffer[prefix_length+1] != 0; + png_uint_32 language_offset, translated_keyword_offset; + png_alloc_size_t uncompressed_length = 0; + + /* Now the language tag */ + prefix_length += 3; + language_offset = prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* WARNING: the length may be invalid here, this is checked below. */ + translated_keyword_offset = ++prefix_length; + + for (; prefix_length < length && buffer[prefix_length] != 0; + ++prefix_length) + /* Empty loop */ ; + + /* prefix_length should now be at the trailing '\0' of the translated + * keyword, but it may already be over the end. None of this arithmetic + * can overflow because chunks are at most 2^31 bytes long, but on 16-bit + * systems the available allocation may overflow. + */ + ++prefix_length; + + if (compressed == 0 && prefix_length <= length) + uncompressed_length = length - prefix_length; + + else if (compressed != 0 && prefix_length < length) + { + uncompressed_length = PNG_SIZE_MAX; + + /* TODO: at present png_decompress_chunk imposes a single application + * level memory limit, this should be split to different values for + * iCCP and text chunks. + */ + if (png_decompress_chunk(png_ptr, length, prefix_length, + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + buffer = png_ptr->read_buffer; + + else + errmsg = png_ptr->zstream.msg; + } + + else + errmsg = "truncated"; + + if (errmsg == NULL) + { + png_text text; + + buffer[uncompressed_length+prefix_length] = 0; + + if (compressed == 0) + text.compression = PNG_ITXT_COMPRESSION_NONE; + + else + text.compression = PNG_ITXT_COMPRESSION_zTXt; + + text.key = (png_charp)buffer; + text.lang = (png_charp)buffer + language_offset; + text.lang_key = (png_charp)buffer + translated_keyword_offset; + text.text = (png_charp)buffer + prefix_length; + text.text_length = 0; + text.itxt_length = uncompressed_length; + + if (png_set_text_2(png_ptr, info_ptr, &text, 1) != 0) + errmsg = "insufficient memory"; + } } else - { - comp_flag = *lang++; - comp_type = *lang++; - } - - for (lang_key = lang; *lang_key; lang_key++) - /* Empty loop */ ; - - lang_key++; /* Skip NUL separator */ - - if (lang_key >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Truncated iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - for (text = lang_key; *text; text++) - /* Empty loop */ ; - - text++; /* Skip NUL separator */ - - if (text >= png_ptr->chunkdata + slength) - { - png_warning(png_ptr, "Malformed iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - prefix_len = text - png_ptr->chunkdata; - - key=png_ptr->chunkdata; - - if (comp_flag) - png_decompress_chunk(png_ptr, comp_type, - (size_t)length, prefix_len, &data_len); - - else - data_len = png_strlen(png_ptr->chunkdata + prefix_len); - - text_ptr = (png_textp)png_malloc_warn(png_ptr, - png_sizeof(png_text)); - - if (text_ptr == NULL) - { - png_warning(png_ptr, "Not enough memory to process iTXt chunk"); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - return; - } - - text_ptr->compression = (int)comp_flag + 1; - text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key); - text_ptr->lang = png_ptr->chunkdata + (lang - key); - text_ptr->itxt_length = data_len; - text_ptr->text_length = 0; - text_ptr->key = png_ptr->chunkdata; - text_ptr->text = png_ptr->chunkdata + prefix_len; - - ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1); - - png_free(png_ptr, text_ptr); - png_free(png_ptr, png_ptr->chunkdata); - png_ptr->chunkdata = NULL; - - if (ret) - png_error(png_ptr, "Insufficient memory to store iTXt chunk"); + errmsg = "bad compression info"; + + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); } #endif -/* This function is called when we haven't found a handler for a - * chunk. If there isn't a problem with the chunk itself (ie bad - * chunk name, CRC, or a critical chunk), the chunk is silently ignored - * -- unless the PNG_FLAG_UNKNOWN_CHUNKS_SUPPORTED flag is on in which - * case it will be saved away to be written out later. - */ -void /* PRIVATE */ -png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +/* Utility function for png_handle_unknown; set up png_ptr::unknown_chunk */ +static int +png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) { - png_uint_32 skip = 0; - - png_debug(1, "in png_handle_unknown"); - -#ifdef PNG_USER_LIMITS_SUPPORTED - if (png_ptr->user_chunk_cache_max != 0) + png_alloc_size_t limit = PNG_SIZE_MAX; + + if (png_ptr->unknown_chunk.data != NULL) { - if (png_ptr->user_chunk_cache_max == 1) - { - png_crc_finish(png_ptr, length); - return; - } - - if (--png_ptr->user_chunk_cache_max == 1) - { - png_warning(png_ptr, "No space in chunk cache for unknown chunk"); - png_crc_finish(png_ptr, length); - return; - } - } -#endif - - if (png_ptr->mode & PNG_HAVE_IDAT) - { - PNG_IDAT; - - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) /* Not an IDAT */ - png_ptr->mode |= PNG_AFTER_IDAT; + png_free(png_ptr, png_ptr->unknown_chunk.data); + png_ptr->unknown_chunk.data = NULL; } - if (!(png_ptr->chunk_name[0] & 0x20)) +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; + +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + + if (length <= limit) { -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - && png_ptr->read_user_chunk_fn == NULL -#endif - ) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); - } - -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - if ((png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS) -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED - || (png_ptr->read_user_chunk_fn != NULL) -#endif - ) - { -#ifdef PNG_MAX_MALLOC_64K - if (length > (png_uint_32)65535L) - { - png_warning(png_ptr, "unknown chunk too large to fit in memory"); - skip = length - (png_uint_32)65535L; - length = (png_uint_32)65535L; - } -#endif - - png_memcpy((png_charp)png_ptr->unknown_chunk.name, - (png_charp)png_ptr->chunk_name, - png_sizeof(png_ptr->unknown_chunk.name)); - - png_ptr->unknown_chunk.name[png_sizeof(png_ptr->unknown_chunk.name)-1] - = '\0'; - - png_ptr->unknown_chunk.size = (png_size_t)length; + PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); + /* The following is safe because of the PNG_SIZE_MAX init above */ + png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/; + /* 'mode' is a flag array, only the bottom four bits matter here */ + png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/; if (length == 0) png_ptr->unknown_chunk.data = NULL; else { - png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr, length); - png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data, length); + /* Do a 'warn' here - it is handled below. */ + png_ptr->unknown_chunk.data = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, length)); } - -#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + } + + if (png_ptr->unknown_chunk.data == NULL && length > 0) + { + /* This is benign because we clean up correctly */ + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "unknown chunk exceeds memory limits"); + return 0; + } + + else + { + if (length > 0) + png_crc_read(png_ptr, png_ptr->unknown_chunk.data, length); + png_crc_finish(png_ptr, 0); + return 1; + } +} +#endif /* READ_UNKNOWN_CHUNKS */ + +/* Handle an unknown, or known but disabled, chunk */ +void /* PRIVATE */ +png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, + png_uint_32 length, int keep) +{ + int handled = 0; /* the chunk was handled */ + + png_debug(1, "in png_handle_unknown"); + +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* NOTE: this code is based on the code in libpng-1.4.12 except for fixing + * the bug which meant that setting a non-default behavior for a specific + * chunk would be ignored (the default was always used unless a user + * callback was installed). + * + * 'keep' is the value from the png_chunk_unknown_handling, the setting for + * this specific chunk_name, if PNG_HANDLE_AS_UNKNOWN_SUPPORTED, if not it + * will always be PNG_HANDLE_CHUNK_AS_DEFAULT and it needs to be set here. + * This is just an optimization to avoid multiple calls to the lookup + * function. + */ +# ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); +# endif +# endif + + /* One of the following methods will read the chunk or skip it (at least one + * of these is always defined because this is the only way to switch on + * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) + */ +# ifdef PNG_READ_USER_CHUNKS_SUPPORTED + /* The user callback takes precedence over the chunk keep value, but the + * keep value is still required to validate a save of a critical chunk. + */ if (png_ptr->read_user_chunk_fn != NULL) { - /* Callback to user unknown chunk handler */ - int ret; - - ret = (*(png_ptr->read_user_chunk_fn)) - (png_ptr, &png_ptr->unknown_chunk); - - if (ret < 0) - png_chunk_error(png_ptr, "error in user chunk"); - - if (ret == 0) + if (png_cache_unknown_chunk(png_ptr, length) != 0) { - if (!(png_ptr->chunk_name[0] & 0x20)) + /* Callback to user unknown chunk handler */ + int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, + &png_ptr->unknown_chunk); + + /* ret is: + * negative: An error occured, png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be discarded + * unless png_set_keep_unknown_chunks has been used to set + * a 'keep' behavior for this particular chunk, in which + * case that will be used. A critical chunk will cause an + * error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. + */ + if (ret < 0) + png_chunk_error(png_ptr, "error in user chunk"); + + else if (ret == 0) { -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_handle_as_unknown(png_ptr, png_ptr->chunk_name) != - PNG_HANDLE_CHUNK_ALWAYS) -#endif - png_chunk_error(png_ptr, "unknown critical chunk"); + /* If the keep value is 'default' or 'never' override it, but + * still error out on critical chunks unless the keep value is + * 'always' While this is weird it is the behavior in 1.4.12. + * A possible improvement would be to obey the value set for the + * chunk, but this would be an API change that would probably + * damage some applications. + * + * The png_app_warning below catches the case that matters, where + * the application has not set specific save or ignore for this + * chunk or global save or ignore. + */ + if (keep < PNG_HANDLE_CHUNK_IF_SAFE) + { +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) + { + png_chunk_warning(png_ptr, "Saving unknown chunk:"); + png_app_warning(png_ptr, + "forcing save of an unhandled chunk;" + " please call png_set_keep_unknown_chunks"); + /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ + } +# endif + keep = PNG_HANDLE_CHUNK_IF_SAFE; + } } - png_set_unknown_chunks(png_ptr, info_ptr, - &png_ptr->unknown_chunk, 1); + else /* chunk was handled */ + { + handled = 1; + /* Critical chunks can be safely discarded at this point. */ + keep = PNG_HANDLE_CHUNK_NEVER; + } } + + else + keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ } else -#endif - png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1); - + /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ +# endif /* READ_USER_CHUNKS */ + +# ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED + { + /* keep is currently just the per-chunk setting, if there was no + * setting change it to the global default now (not that this may + * still be AS_DEFAULT) then obtain the cache of the chunk if required, + * if not simply skip the chunk. + */ + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + keep = png_ptr->unknown_default; + + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { + if (png_cache_unknown_chunk(png_ptr, length) == 0) + keep = PNG_HANDLE_CHUNK_NEVER; + } + + else + png_crc_finish(png_ptr, length); + } +# else +# ifndef PNG_READ_USER_CHUNKS_SUPPORTED +# error no method to support READ_UNKNOWN_CHUNKS +# endif + + { + /* If here there is no read callback pointer set and no support is + * compiled in to just save the unknown chunks, so simply skip this + * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then + * the app has erroneously asked for unknown chunk saving when there + * is no support. + */ + if (keep > PNG_HANDLE_CHUNK_NEVER) + png_app_error(png_ptr, "no unknown chunk support available"); + + png_crc_finish(png_ptr, length); + } +# endif + +# ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED + /* Now store the chunk in the chunk list if appropriate, and if the limits + * permit it. + */ + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { +# ifdef PNG_USER_LIMITS_SUPPORTED + switch (png_ptr->user_chunk_cache_max) + { + case 2: + png_ptr->user_chunk_cache_max = 1; + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + /* FALL THROUGH */ + case 1: + /* NOTE: prior to 1.6.0 this case resulted in an unknown critical + * chunk being skipped, now there will be a hard error below. + */ + break; + + default: /* not at limit */ + --(png_ptr->user_chunk_cache_max); + /* FALL THROUGH */ + case 0: /* no limit */ +# endif /* USER_LIMITS */ + /* Here when the limit isn't reached or when limits are compiled + * out; store the chunk. + */ + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + handled = 1; +# ifdef PNG_USER_LIMITS_SUPPORTED + break; + } +# endif + } +# else /* no store support: the chunk must be handled by the user callback */ + PNG_UNUSED(info_ptr) +# endif + + /* Regardless of the error handling below the cached data (if any) can be + * freed now. Notice that the data is not freed if there is a png_error, but + * it will be freed by destroy_read_struct. + */ + if (png_ptr->unknown_chunk.data != NULL) png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; - } - - else -#endif - skip = length; - - png_crc_finish(png_ptr, skip); - -#ifndef PNG_READ_USER_CHUNKS_SUPPORTED - PNG_UNUSED(info_ptr) /* Quiet compiler warnings about unused info_ptr */ -#endif + png_ptr->unknown_chunk.data = NULL; + +#else /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ + /* There is no support to read an unknown chunk, so just skip it. */ + png_crc_finish(png_ptr, length); + PNG_UNUSED(info_ptr) + PNG_UNUSED(keep) +#endif /* !READ_UNKNOWN_CHUNKS */ + + /* Check for unhandled critical chunks */ + if (handled == 0 && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) + png_chunk_error(png_ptr, "unhandled critical chunk"); } /* This function is called to verify that a chunk name is valid. @@ -2682,267 +2996,527 @@ * the chunk name itself is valid. */ -#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) - -void /* PRIVATE */ -png_check_chunk_name(png_structp png_ptr, png_const_bytep chunk_name) -{ - png_debug(1, "in png_check_chunk_name"); - if (isnonalpha(chunk_name[0]) || isnonalpha(chunk_name[1]) || - isnonalpha(chunk_name[2]) || isnonalpha(chunk_name[3])) - { - png_chunk_error(png_ptr, "invalid chunk type"); - } -} - -/* Combines the row recently read in with the existing pixels in the - * row. This routine takes care of alpha and transparency if requested. - * This routine also handles the two methods of progressive display - * of interlaced images, depending on the mask value. - * The mask value describes which pixels are to be combined with - * the row. The pattern always repeats every 8 pixels, so just 8 - * bits are needed. A one indicates the pixel is to be combined, - * a zero indicates the pixel is to be skipped. This is in addition - * to any alpha or transparency value associated with the pixel. If - * you want all pixels to be combined, pass 0xff (255) in mask. +/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is: + * + * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) */ void /* PRIVATE */ -png_combine_row(png_structp png_ptr, png_bytep row, int mask) +png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name) { + int i; + + png_debug(1, "in png_check_chunk_name"); + + for (i=1; i<=4; ++i) + { + int c = chunk_name & 0xff; + + if (c < 65 || c > 122 || (c > 90 && c < 97)) + png_chunk_error(png_ptr, "invalid chunk type"); + + chunk_name >>= 8; + } +} + +/* Combines the row recently read in with the existing pixels in the row. This + * routine takes care of alpha and transparency if requested. This routine also + * handles the two methods of progressive display of interlaced images, + * depending on the 'display' value; if 'display' is true then the whole row + * (dp) is filled from the start by replicating the available pixels. If + * 'display' is false only those pixels present in the pass are filled in. + */ +void /* PRIVATE */ +png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) +{ + unsigned int pixel_depth = png_ptr->transformed_pixel_depth; + png_const_bytep sp = png_ptr->row_buf + 1; + png_alloc_size_t row_width = png_ptr->width; + unsigned int pass = png_ptr->pass; + png_bytep end_ptr = 0; + png_byte end_byte = 0; + unsigned int end_mask; + png_debug(1, "in png_combine_row"); - /* Added in 1.5.4: the row_info should match the information returned by any - * call to png_read_update_info at this point. Do not continue if we got + /* Added in 1.5.6: it should not be possible to enter this routine until at + * least one row has been read from the PNG data and transformed. + */ + if (pixel_depth == 0) + png_error(png_ptr, "internal row logic error"); + + /* Added in 1.5.4: the pixel depth should match the information returned by + * any call to png_read_update_info at this point. Do not continue if we got * this wrong. */ if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes != - PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)) + PNG_ROWBYTES(pixel_depth, row_width)) png_error(png_ptr, "internal row size calculation error"); - if (mask == 0xff) + /* Don't expect this to ever happen: */ + if (row_width == 0) + png_error(png_ptr, "internal row width error"); + + /* Preserve the last byte in cases where only part of it will be overwritten, + * the multiply below may overflow, we don't care because ANSI-C guarantees + * we get the low bits. + */ + end_mask = (pixel_depth * row_width) & 7; + if (end_mask != 0) + { + /* end_ptr == NULL is a flag to say do nothing */ + end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1; + end_byte = *end_ptr; +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + /* little-endian byte */ + end_mask = 0xff << end_mask; + + else /* big-endian byte */ +# endif + end_mask = 0xff >> end_mask; + /* end_mask is now the bits to *keep* from the destination row */ + } + + /* For non-interlaced images this reduces to a memcpy(). A memcpy() + * will also happen if interlacing isn't supported or if the application + * does not call png_set_interlace_handling(). In the latter cases the + * caller just gets a sequence of the unexpanded rows from each interlace + * pass. + */ +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0 && + pass < 6 && (display == 0 || + /* The following copies everything for 'display' on passes 0, 2 and 4. */ + (display == 1 && (pass & 1) != 0))) { - png_memcpy(row, png_ptr->row_buf + 1, - PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)); - } - - else - { - switch (png_ptr->row_info.pixel_depth) + /* Narrow images may have no bits in a pass; the caller should handle + * this, but this test is cheap: + */ + if (row_width <= PNG_PASS_START_COL(pass)) + return; + + if (pixel_depth < 8) { - case 1: + /* For pixel depths up to 4 bpp the 8-pixel mask can be expanded to fit + * into 32 bits, then a single loop over the bytes using the four byte + * values in the 32-bit mask can be used. For the 'display' option the + * expanded mask may also not require any masking within a byte. To + * make this work the PACKSWAP option must be taken into account - it + * simply requires the pixels to be reversed in each byte. + * + * The 'regular' case requires a mask for each of the first 6 passes, + * the 'display' case does a copy for the even passes in the range + * 0..6. This has already been handled in the test above. + * + * The masks are arranged as four bytes with the first byte to use in + * the lowest bits (little-endian) regardless of the order (PACKSWAP or + * not) of the pixels in each byte. + * + * NOTE: the whole of this logic depends on the caller of this function + * only calling it on rows appropriate to the pass. This function only + * understands the 'x' logic; the 'y' logic is handled by the caller. + * + * The following defines allow generation of compile time constant bit + * masks for each pixel depth and each possibility of swapped or not + * swapped bytes. Pass 'p' is in the range 0..6; 'x', a pixel index, + * is in the range 0..7; and the result is 1 if the pixel is to be + * copied in the pass, 0 if not. 'S' is for the sparkle method, 'B' + * for the block method. + * + * With some compilers a compile time expression of the general form: + * + * (shift >= 32) ? (a >> (shift-32)) : (b >> shift) + * + * Produces warnings with values of 'shift' in the range 33 to 63 + * because the right hand side of the ?: expression is evaluated by + * the compiler even though it isn't used. Microsoft Visual C (various + * versions) and the Intel C compiler are known to do this. To avoid + * this the following macros are used in 1.5.6. This is a temporary + * solution to avoid destabilizing the code during the release process. + */ +# if PNG_USE_COMPILE_TIME_MASKS +# define PNG_LSR(x,s) ((x)>>((s) & 0x1f)) +# define PNG_LSL(x,s) ((x)<<((s) & 0x1f)) +# else +# define PNG_LSR(x,s) ((x)>>(s)) +# define PNG_LSL(x,s) ((x)<<(s)) +# endif +# define S_COPY(p,x) (((p)<4 ? PNG_LSR(0x80088822,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xaa55ff00,(7-(p))*8+(7-(x)))) & 1) +# define B_COPY(p,x) (((p)<4 ? PNG_LSR(0xff0fff33,(3-(p))*8+(7-(x))) :\ + PNG_LSR(0xff55ff00,(7-(p))*8+(7-(x)))) & 1) + + /* Return a mask for pass 'p' pixel 'x' at depth 'd'. The mask is + * little endian - the first pixel is at bit 0 - however the extra + * parameter 's' can be set to cause the mask position to be swapped + * within each byte, to match the PNG format. This is done by XOR of + * the shift with 7, 6 or 4 for bit depths 1, 2 and 4. + */ +# define PIXEL_MASK(p,x,d,s) \ + (PNG_LSL(((PNG_LSL(1U,(d)))-1),(((x)*(d))^((s)?8-(d):0)))) + + /* Hence generate the appropriate 'block' or 'sparkle' pixel copy mask. + */ +# define S_MASKx(p,x,d,s) (S_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) +# define B_MASKx(p,x,d,s) (B_COPY(p,x)?PIXEL_MASK(p,x,d,s):0) + + /* Combine 8 of these to get the full mask. For the 1-bpp and 2-bpp + * cases the result needs replicating, for the 4-bpp case the above + * generates a full 32 bits. + */ +# define MASK_EXPAND(m,d) ((m)*((d)==1?0x01010101:((d)==2?0x00010001:1))) + +# define S_MASK(p,d,s) MASK_EXPAND(S_MASKx(p,0,d,s) + S_MASKx(p,1,d,s) +\ + S_MASKx(p,2,d,s) + S_MASKx(p,3,d,s) + S_MASKx(p,4,d,s) +\ + S_MASKx(p,5,d,s) + S_MASKx(p,6,d,s) + S_MASKx(p,7,d,s), d) + +# define B_MASK(p,d,s) MASK_EXPAND(B_MASKx(p,0,d,s) + B_MASKx(p,1,d,s) +\ + B_MASKx(p,2,d,s) + B_MASKx(p,3,d,s) + B_MASKx(p,4,d,s) +\ + B_MASKx(p,5,d,s) + B_MASKx(p,6,d,s) + B_MASKx(p,7,d,s), d) + +#if PNG_USE_COMPILE_TIME_MASKS + /* Utility macros to construct all the masks for a depth/swap + * combination. The 's' parameter says whether the format is PNG + * (big endian bytes) or not. Only the three odd-numbered passes are + * required for the display/block algorithm. + */ +# define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\ + S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) } + +# define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) } + +# define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2)) + + /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and + * then pass: + */ + static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] = { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - int s_inc, s_start, s_end; - int m = 0x80; - int shift; - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - { - s_start = 0; - s_end = 7; - s_inc = 1; - } - - else -#endif - { - s_start = 7; - s_end = 0; - s_inc = -1; - } - - shift = s_start; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - int value; - - value = (*sp >> shift) & 0x01; - *dp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); - *dp |= (png_byte)(value << shift); - } - - if (shift == s_end) - { - shift = s_start; - sp++; - dp++; - } - - else - shift += s_inc; - - if (m == 1) - m = 0x80; - - else - m >>= 1; - } - break; - } - - case 2: + /* Little-endian byte masks for PACKSWAP */ + { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { S_MASKS(1,1), S_MASKS(2,1), S_MASKS(4,1) } + }; + + /* display_mask has only three entries for the odd passes, so index by + * pass>>1. + */ + static PNG_CONST png_uint_32 display_mask[2][3][3] = { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - int s_start, s_end, s_inc; - int m = 0x80; - int shift; - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - int value; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - { - s_start = 0; - s_end = 6; - s_inc = 2; - } + /* Little-endian byte masks for PACKSWAP */ + { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) }, + /* Normal (big-endian byte) masks - PNG format */ + { B_MASKS(1,1), B_MASKS(2,1), B_MASKS(4,1) } + }; + +# define MASK(pass,depth,display,png)\ + ((display)?display_mask[png][DEPTH_INDEX(depth)][pass>>1]:\ + row_mask[png][DEPTH_INDEX(depth)][pass]) + +#else /* !PNG_USE_COMPILE_TIME_MASKS */ + /* This is the runtime alternative: it seems unlikely that this will + * ever be either smaller or faster than the compile time approach. + */ +# define MASK(pass,depth,display,png)\ + ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png)) +#endif /* !USE_COMPILE_TIME_MASKS */ + + /* Use the appropriate mask to copy the required bits. In some cases + * the byte mask will be 0 or 0xff; optimize these cases. row_width is + * the number of pixels, but the code copies bytes, so it is necessary + * to special case the end. + */ + png_uint_32 pixels_per_byte = 8 / pixel_depth; + png_uint_32 mask; + +# ifdef PNG_READ_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + mask = MASK(pass, pixel_depth, display, 0); else -#endif - { - s_start = 6; - s_end = 0; - s_inc = -2; - } - - shift = s_start; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - value = (*sp >> shift) & 0x03; - *dp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *dp |= (png_byte)(value << shift); - } - - if (shift == s_end) - { - shift = s_start; - sp++; - dp++; - } - - else - shift += s_inc; - - if (m == 1) - m = 0x80; - - else - m >>= 1; - } - break; - } - - case 4: +# endif + mask = MASK(pass, pixel_depth, display, 1); + + for (;;) { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - int s_start, s_end, s_inc; - int m = 0x80; - int shift; - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - int value; - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - { - s_start = 0; - s_end = 4; - s_inc = 4; - } - - else -#endif + png_uint_32 m; + + /* It doesn't matter in the following if png_uint_32 has more than + * 32 bits because the high bits always match those in m<<24; it is, + * however, essential to use OR here, not +, because of this. + */ + m = mask; + mask = (m >> 8) | (m << 24); /* rotate right to good compilers */ + m &= 0xff; + + if (m != 0) /* something to copy */ { - s_start = 4; - s_end = 0; - s_inc = -4; - } - shift = s_start; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - value = (*sp >> shift) & 0xf; - *dp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *dp |= (png_byte)(value << shift); - } - - if (shift == s_end) - { - shift = s_start; - sp++; - dp++; - } - - else - shift += s_inc; - - if (m == 1) - m = 0x80; - + if (m != 0xff) + *dp = (png_byte)((*dp & ~m) | (*sp & m)); else - m >>= 1; + *dp = *sp; } - break; - } - - default: - { - png_bytep sp = png_ptr->row_buf + 1; - png_bytep dp = row; - png_size_t pixel_bytes = (png_ptr->row_info.pixel_depth >> 3); - png_uint_32 i; - png_uint_32 row_width = png_ptr->width; - png_byte m = 0x80; - - for (i = 0; i < row_width; i++) - { - if (m & mask) - { - png_memcpy(dp, sp, pixel_bytes); - } - - sp += pixel_bytes; - dp += pixel_bytes; - - if (m == 1) - m = 0x80; - - else - m >>= 1; - } - break; + + /* NOTE: this may overwrite the last byte with garbage if the image + * is not an exact number of bytes wide; libpng has always done + * this. + */ + if (row_width <= pixels_per_byte) + break; /* May need to restore part of the last byte */ + + row_width -= pixels_per_byte; + ++dp; + ++sp; } } + + else /* pixel_depth >= 8 */ + { + unsigned int bytes_to_copy, bytes_to_jump; + + /* Validate the depth - it must be a multiple of 8 */ + if (pixel_depth & 7) + png_error(png_ptr, "invalid user transform pixel depth"); + + pixel_depth >>= 3; /* now in bytes */ + row_width *= pixel_depth; + + /* Regardless of pass number the Adam 7 interlace always results in a + * fixed number of pixels to copy then to skip. There may be a + * different number of pixels to skip at the start though. + */ + { + unsigned int offset = PNG_PASS_START_COL(pass) * pixel_depth; + + row_width -= offset; + dp += offset; + sp += offset; + } + + /* Work out the bytes to copy. */ + if (display != 0) + { + /* When doing the 'block' algorithm the pixel in the pass gets + * replicated to adjacent pixels. This is why the even (0,2,4,6) + * passes are skipped above - the entire expanded row is copied. + */ + bytes_to_copy = (1<<((6-pass)>>1)) * pixel_depth; + + /* But don't allow this number to exceed the actual row width. */ + if (bytes_to_copy > row_width) + bytes_to_copy = (unsigned int)/*SAFE*/row_width; + } + + else /* normal row; Adam7 only ever gives us one pixel to copy. */ + bytes_to_copy = pixel_depth; + + /* In Adam7 there is a constant offset between where the pixels go. */ + bytes_to_jump = PNG_PASS_COL_OFFSET(pass) * pixel_depth; + + /* And simply copy these bytes. Some optimization is possible here, + * depending on the value of 'bytes_to_copy'. Special case the low + * byte counts, which we know to be frequent. + * + * Notice that these cases all 'return' rather than 'break' - this + * avoids an unnecessary test on whether to restore the last byte + * below. + */ + switch (bytes_to_copy) + { + case 1: + for (;;) + { + *dp = *sp; + + if (row_width <= bytes_to_jump) + return; + + dp += bytes_to_jump; + sp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + case 2: + /* There is a possibility of a partial copy at the end here; this + * slows the code down somewhat. + */ + do + { + dp[0] = sp[0], dp[1] = sp[1]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + while (row_width > 1); + + /* And there can only be one byte left at this point: */ + *dp = *sp; + return; + + case 3: + /* This can only be the RGB case, so each copy is exactly one + * pixel and it is not necessary to check for a partial copy. + */ + for (;;) + { + dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2]; + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + } + + default: +#if PNG_ALIGN_TYPE != PNG_ALIGN_NONE + /* Check for double byte alignment and, if possible, use a + * 16-bit copy. Don't attempt this for narrow images - ones that + * are less than an interlace panel wide. Don't attempt it for + * wide bytes_to_copy either - use the memcpy there. + */ + if (bytes_to_copy < 16 /*else use memcpy*/ && + png_isaligned(dp, png_uint_16) && + png_isaligned(sp, png_uint_16) && + bytes_to_copy % (sizeof (png_uint_16)) == 0 && + bytes_to_jump % (sizeof (png_uint_16)) == 0) + { + /* Everything is aligned for png_uint_16 copies, but try for + * png_uint_32 first. + */ + if (png_isaligned(dp, png_uint_32) != 0 && + png_isaligned(sp, png_uint_32) != 0 && + bytes_to_copy % (sizeof (png_uint_32)) == 0 && + bytes_to_jump % (sizeof (png_uint_32)) == 0) + { + png_uint_32p dp32 = png_aligncast(png_uint_32p,dp); + png_const_uint_32p sp32 = png_aligncastconst( + png_const_uint_32p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_32)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp32++ = *sp32++; + c -= (sizeof (png_uint_32)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp32 += skip; + sp32 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* Get to here when the row_width truncates the final copy. + * There will be 1-3 bytes left to copy, so don't try the + * 16-bit loop below. + */ + dp = (png_bytep)dp32; + sp = (png_const_bytep)sp32; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + + /* Else do it in 16-bit quantities, but only if the size is + * not too large. + */ + else + { + png_uint_16p dp16 = png_aligncast(png_uint_16p, dp); + png_const_uint_16p sp16 = png_aligncastconst( + png_const_uint_16p, sp); + size_t skip = (bytes_to_jump-bytes_to_copy) / + (sizeof (png_uint_16)); + + do + { + size_t c = bytes_to_copy; + do + { + *dp16++ = *sp16++; + c -= (sizeof (png_uint_16)); + } + while (c > 0); + + if (row_width <= bytes_to_jump) + return; + + dp16 += skip; + sp16 += skip; + row_width -= bytes_to_jump; + } + while (bytes_to_copy <= row_width); + + /* End of row - 1 byte left, bytes_to_copy > row_width: */ + dp = (png_bytep)dp16; + sp = (png_const_bytep)sp16; + do + *dp++ = *sp++; + while (--row_width > 0); + return; + } + } +#endif /* ALIGN_TYPE code */ + + /* The true default - use a memcpy: */ + for (;;) + { + memcpy(dp, sp, bytes_to_copy); + + if (row_width <= bytes_to_jump) + return; + + sp += bytes_to_jump; + dp += bytes_to_jump; + row_width -= bytes_to_jump; + if (bytes_to_copy > row_width) + bytes_to_copy = (unsigned int)/*SAFE*/row_width; + } + } + + /* NOT REACHED*/ + } /* pixel_depth >= 8 */ + + /* Here if pixel_depth < 8 to check 'end_ptr' below. */ } + else +#endif /* READ_INTERLACING */ + + /* If here then the switch above wasn't used so just memcpy the whole row + * from the temporary row buffer (notice that this overwrites the end of the + * destination row if it is a partial byte.) + */ + memcpy(dp, sp, PNG_ROWBYTES(pixel_depth, row_width)); + + /* Restore the overwritten bits from the last byte if necessary. */ + if (end_ptr != NULL) + *end_ptr = (png_byte)((end_byte & end_mask) | (*end_ptr & ~end_mask)); } #ifdef PNG_READ_INTERLACING_SUPPORTED void /* PRIVATE */ -png_do_read_interlace(png_structp png_ptr) +png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, + png_uint_32 transformations /* Because these may affect the byte layout */) { - png_row_infop row_info = &(png_ptr->row_info); - png_bytep row = png_ptr->row_buf + 1; - int pass = png_ptr->pass; - png_uint_32 transformations = png_ptr->transformations; /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; png_debug(1, "in png_do_read_interlace"); if (row != NULL && row_info != NULL) @@ -2965,7 +3539,7 @@ int j; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) + if ((transformations & PNG_PACKSWAP) != 0) { sshift = (int)((row_info->width + 7) & 0x07); dshift = (int)((final_width + 7) & 0x07); @@ -2989,8 +3563,9 @@ v = (png_byte)((*sp >> sshift) & 0x01); for (j = 0; j < jstop; j++) { - *dp &= (png_byte)((0x7f7f >> (7 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); + unsigned int tmp = *dp & (0x7f7f >> (7 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { @@ -3024,7 +3599,7 @@ png_uint_32 i; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) + if ((transformations & PNG_PACKSWAP) != 0) { sshift = (int)(((row_info->width + 3) & 0x03) << 1); dshift = (int)(((final_width + 3) & 0x03) << 1); @@ -3051,8 +3626,9 @@ v = (png_byte)((*sp >> sshift) & 0x03); for (j = 0; j < jstop; j++) { - *dp &= (png_byte)((0x3f3f >> (6 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); + unsigned int tmp = *dp & (0x3f3f >> (6 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { @@ -3086,7 +3662,7 @@ int jstop = png_pass_inc[pass]; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if (transformations & PNG_PACKSWAP) + if ((transformations & PNG_PACKSWAP) != 0) { sshift = (int)(((row_info->width + 1) & 0x01) << 2); dshift = (int)(((final_width + 1) & 0x01) << 2); @@ -3107,13 +3683,14 @@ for (i = 0; i < row_info->width; i++) { - png_byte v = (png_byte)((*sp >> sshift) & 0xf); + png_byte v = (png_byte)((*sp >> sshift) & 0x0f); int j; for (j = 0; j < jstop; j++) { - *dp &= (png_byte)((0xf0f >> (4 - dshift)) & 0xff); - *dp |= (png_byte)(v << dshift); + unsigned int tmp = *dp & (0xf0f >> (4 - dshift)); + tmp |= v << dshift; + *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) { @@ -3136,6 +3713,7 @@ } break; } + default: { png_size_t pixel_bytes = (row_info->pixel_depth >> 3); @@ -3150,14 +3728,14 @@ for (i = 0; i < row_info->width; i++) { - png_byte v[8]; + png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */ int j; - png_memcpy(v, sp, pixel_bytes); + memcpy(v, sp, pixel_bytes); for (j = 0; j < jstop; j++) { - png_memcpy(dp, v, pixel_bytes); + memcpy(dp, v, pixel_bytes); dp -= pixel_bytes; } @@ -3166,6 +3744,7 @@ break; } } + row_info->width = final_width; row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, final_width); } @@ -3173,167 +3752,427 @@ PNG_UNUSED(transformations) /* Silence compiler warning */ #endif } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ +#endif /* READ_INTERLACING */ + +static void +png_read_filter_row_sub(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_size_t istop = row_info->rowbytes; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp = row + bpp; + + PNG_UNUSED(prev_row) + + for (i = bpp; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*(rp-bpp))) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_up(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_size_t istop = row_info->rowbytes; + png_bytep rp = row; + png_const_bytep pp = prev_row; + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); + rp++; + } +} + +static void +png_read_filter_row_avg(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_size_t i; + png_bytep rp = row; + png_const_bytep pp = prev_row; + unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + png_size_t istop = row_info->rowbytes - bpp; + + for (i = 0; i < bpp; i++) + { + *rp = (png_byte)(((int)(*rp) + + ((int)(*pp++) / 2 )) & 0xff); + + rp++; + } + + for (i = 0; i < istop; i++) + { + *rp = (png_byte)(((int)(*rp) + + (int)(*pp++ + *(rp-bpp)) / 2 ) & 0xff); + + rp++; + } +} + +static void +png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + png_bytep rp_end = row + row_info->rowbytes; + int a, c; + + /* First pixel/byte */ + c = *prev_row++; + a = *row + c; + *row++ = (png_byte)a; + + /* Remainder */ + while (row < rp_end) + { + int b, pa, pb, pc, p; + + a &= 0xff; /* From previous iteration or start */ + b = *prev_row++; + + p = b - c; + pc = a - c; + +# ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +# else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +# endif + + /* Find the best predictor, the least of pa, pb, pc favoring the earlier + * ones in the case of a tie. + */ + if (pb < pa) pa = pb, a = b; + if (pc < pa) a = c; + + /* Calculate the current pixel in a, and move the previous row pixel to c + * for the next time round the loop + */ + c = b; + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, + png_const_bytep prev_row) +{ + int bpp = (row_info->pixel_depth + 7) >> 3; + png_bytep rp_end = row + bpp; + + /* Process the first pixel in the row completely (this is the same as 'up' + * because there is only one candidate predictor for the first row). + */ + while (row < rp_end) + { + int a = *row + *prev_row++; + *row++ = (png_byte)a; + } + + /* Remainder */ + rp_end += row_info->rowbytes - bpp; + + while (row < rp_end) + { + int a, b, c, pa, pb, pc, p; + + c = *(prev_row - bpp); + a = *(row - bpp); + b = *prev_row++; + + p = b - c; + pc = a - c; + +# ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +# else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +# endif + + if (pb < pa) pa = pb, a = b; + if (pc < pa) a = c; + + a += *row; + *row++ = (png_byte)a; + } +} + +static void +png_init_filter_functions(png_structrp pp) + /* This function is called once for every PNG image (except for PNG images + * that only use PNG_FILTER_VALUE_NONE for all rows) to set the + * implementations required to reverse the filtering of PNG rows. Reversing + * the filter is the first transformation performed on the row data. It is + * performed in place, therefore an implementation can be selected based on + * the image pixel format. If the implementation depends on image width then + * take care to ensure that it works correctly if the image is interlaced - + * interlacing causes the actual row width to vary. + */ +{ + unsigned int bpp = (pp->pixel_depth + 7) >> 3; + + pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub; + pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up; + pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg; + if (bpp == 1) + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_1byte_pixel; + else + pp->read_filter[PNG_FILTER_VALUE_PAETH-1] = + png_read_filter_row_paeth_multibyte_pixel; + +#ifdef PNG_FILTER_OPTIMIZATIONS + /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to + * call to install hardware optimizations for the above functions; simply + * replace whatever elements of the pp->read_filter[] array with a hardware + * specific (or, for that matter, generic) optimization. + * + * To see an example of this examine what configure.ac does when + * --enable-arm-neon is specified on the command line. + */ + PNG_FILTER_OPTIMIZATIONS(pp, bpp); +#endif +} void /* PRIVATE */ -png_read_filter_row(png_structp png_ptr, png_row_infop row_info, png_bytep row, - png_const_bytep prev_row, int filter) +png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row, + png_const_bytep prev_row, int filter) { - png_debug(1, "in png_read_filter_row"); - png_debug2(2, "row = %u, filter = %d", png_ptr->row_number, filter); - switch (filter) + /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define + * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic + * implementations. See png_init_filter_functions above. + */ + if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) { - case PNG_FILTER_VALUE_NONE: - break; - - case PNG_FILTER_VALUE_SUB: - { - png_size_t i; - png_size_t istop = row_info->rowbytes; - unsigned int bpp = (row_info->pixel_depth + 7) >> 3; - png_bytep rp = row + bpp; - png_bytep lp = row; - - for (i = bpp; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*lp++)) & 0xff); - rp++; - } - break; - } - case PNG_FILTER_VALUE_UP: - { - png_size_t i; - png_size_t istop = row_info->rowbytes; - png_bytep rp = row; - png_const_bytep pp = prev_row; - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); - rp++; - } - break; - } - case PNG_FILTER_VALUE_AVG: - { - png_size_t i; - png_bytep rp = row; - png_const_bytep pp = prev_row; - png_bytep lp = row; - unsigned int bpp = (row_info->pixel_depth + 7) >> 3; - png_size_t istop = row_info->rowbytes - bpp; - - for (i = 0; i < bpp; i++) - { - *rp = (png_byte)(((int)(*rp) + - ((int)(*pp++) / 2 )) & 0xff); - - rp++; - } - - for (i = 0; i < istop; i++) - { - *rp = (png_byte)(((int)(*rp) + - (int)(*pp++ + *lp++) / 2 ) & 0xff); - - rp++; - } - break; - } - case PNG_FILTER_VALUE_PAETH: - { - png_size_t i; - png_bytep rp = row; - png_const_bytep pp = prev_row; - png_bytep lp = row; - png_const_bytep cp = prev_row; - unsigned int bpp = (row_info->pixel_depth + 7) >> 3; - png_size_t istop=row_info->rowbytes - bpp; - - for (i = 0; i < bpp; i++) - { - *rp = (png_byte)(((int)(*rp) + (int)(*pp++)) & 0xff); - rp++; - } - - for (i = 0; i < istop; i++) /* Use leftover rp,pp */ - { - int a, b, c, pa, pb, pc, p; - - a = *lp++; - b = *pp++; - c = *cp++; - - p = b - c; - pc = a - c; - -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif - - /* - if (pa <= pb && pa <= pc) - p = a; - - else if (pb <= pc) - p = b; - - else - p = c; - */ - - p = (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c; - - *rp = (png_byte)(((int)(*rp) + p) & 0xff); - rp++; - } - break; - } - default: - png_error(png_ptr, "Ignoring bad adaptive filter type"); - /*NOT REACHED */ - break; + if (pp->read_filter[0] == NULL) + png_init_filter_functions(pp); + + pp->read_filter[filter-1](row_info, row, prev_row); } } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED void /* PRIVATE */ -png_read_finish_row(png_structp png_ptr) +png_read_IDAT_data(png_structrp png_ptr, png_bytep output, + png_alloc_size_t avail_out) { -#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Loop reading IDATs and decompressing the result into output[avail_out] */ + png_ptr->zstream.next_out = output; + png_ptr->zstream.avail_out = 0; /* safety: set below */ + + if (output == NULL) + avail_out = 0; + + do + { + int ret; + png_byte tmpbuf[PNG_INFLATE_BUF_SIZE]; + + if (png_ptr->zstream.avail_in == 0) + { + uInt avail_in; + png_bytep buffer; + + while (png_ptr->idat_size == 0) + { + png_crc_finish(png_ptr, 0); + + png_ptr->idat_size = png_read_chunk_header(png_ptr); + /* This is an error even in the 'check' case because the code just + * consumed a non-IDAT header. + */ + if (png_ptr->chunk_name != png_IDAT) + png_error(png_ptr, "Not enough image data"); + } + + avail_in = png_ptr->IDAT_read_size; + + if (avail_in > png_ptr->idat_size) + avail_in = (uInt)png_ptr->idat_size; + + /* A PNG with a gradually increasing IDAT size will defeat this attempt + * to minimize memory usage by causing lots of re-allocs, but + * realistically doing IDAT_read_size re-allocs is not likely to be a + * big problem. + */ + buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/); + + png_crc_read(png_ptr, buffer, avail_in); + png_ptr->idat_size -= avail_in; + + png_ptr->zstream.next_in = buffer; + png_ptr->zstream.avail_in = avail_in; + } + + /* And set up the output side. */ + if (output != NULL) /* standard read */ + { + uInt out = ZLIB_IO_MAX; + + if (out > avail_out) + out = (uInt)avail_out; + + avail_out -= out; + png_ptr->zstream.avail_out = out; + } + + else /* after last row, checking for end */ + { + png_ptr->zstream.next_out = tmpbuf; + png_ptr->zstream.avail_out = (sizeof tmpbuf); + } + + /* Use NO_FLUSH; this gives zlib the maximum opportunity to optimize the + * process. If the LZ stream is truncated the sequential reader will + * terminally damage the stream, above, by reading the chunk header of the + * following chunk (it then exits with png_error). + * + * TODO: deal more elegantly with truncated IDAT lists. + */ + ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); + + /* Take the unconsumed output back. */ + if (output != NULL) + avail_out += png_ptr->zstream.avail_out; + + else /* avail_out counts the extra bytes */ + avail_out += (sizeof tmpbuf) - png_ptr->zstream.avail_out; + + png_ptr->zstream.avail_out = 0; + + if (ret == Z_STREAM_END) + { + /* Do this for safety; we won't read any more into this row. */ + png_ptr->zstream.next_out = NULL; + + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + + if (png_ptr->zstream.avail_in > 0 || png_ptr->idat_size > 0) + png_chunk_benign_error(png_ptr, "Extra compressed data"); + break; + } + + if (ret != Z_OK) + { + png_zstream_error(png_ptr, ret); + + if (output != NULL) + png_chunk_error(png_ptr, png_ptr->zstream.msg); + + else /* checking */ + { + png_chunk_benign_error(png_ptr, png_ptr->zstream.msg); + return; + } + } + } while (avail_out > 0); + + if (avail_out > 0) + { + /* The stream ended before the image; this is the same as too few IDATs so + * should be handled the same way. + */ + if (output != NULL) + png_error(png_ptr, "Not enough image data"); + + else /* the deflate stream contained extra data */ + png_chunk_benign_error(png_ptr, "Too much image data"); + } +} + +void /* PRIVATE */ +png_read_finish_IDAT(png_structrp png_ptr) +{ + /* We don't need any more data and the stream should have ended, however the + * LZ end code may actually not have been processed. In this case we must + * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk + * may still remain to be consumed. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in + * the compressed stream, but the stream may be damaged too, so even after + * this call we may need to terminate the zstream ownership. + */ + png_read_IDAT_data(png_ptr, NULL, 0); + png_ptr->zstream.next_out = NULL; /* safety */ + + /* Now clear everything out for safety; the following may not have been + * done. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + { + png_ptr->mode |= PNG_AFTER_IDAT; + png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; + } + } + + /* If the zstream has not been released do it now *and* terminate the reading + * of the final IDAT chunk. + */ + if (png_ptr->zowner == png_IDAT) + { + /* Always do this; the pointers otherwise point into the read buffer. */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + + /* Now we no longer own the zstream. */ + png_ptr->zowner = 0; + + /* The slightly weird semantics of the sequential IDAT reading is that we + * are always in or at the end of an IDAT chunk, so we always need to do a + * crc_finish here. If idat_size is non-zero we also need to read the + * spurious bytes at the end of the chunk now. + */ + (void)png_crc_finish(png_ptr, png_ptr->idat_size); + } +} + +void /* PRIVATE */ +png_read_finish_row(png_structrp png_ptr) +{ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ - PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ - PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ - PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif /* PNG_READ_INTERLACING_SUPPORTED */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; png_debug(1, "in png_read_finish_row"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; - png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + /* TO DO: don't do this if prev_row isn't needed (requires + * read-ahead of the next row's filter byte. + */ + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); do { @@ -3347,7 +4186,7 @@ png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - if (!(png_ptr->transformations & PNG_INTERLACE)) + if ((png_ptr->transformations & PNG_INTERLACE) == 0) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[png_ptr->pass] - 1 - @@ -3363,108 +4202,40 @@ if (png_ptr->pass < 7) return; } -#endif /* PNG_READ_INTERLACING_SUPPORTED */ - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_FINISHED)) - { - PNG_IDAT; - char extra; - int ret; - - png_ptr->zstream.next_out = (Byte *)&extra; - png_ptr->zstream.avail_out = (uInt)1; - - for (;;) - { - if (!(png_ptr->zstream.avail_in)) - { - while (!png_ptr->idat_size) - { - png_crc_finish(png_ptr, 0); - png_ptr->idat_size = png_read_chunk_header(png_ptr); - if (png_memcmp(png_ptr->chunk_name, png_IDAT, 4)) - png_error(png_ptr, "Not enough image data"); - } - - png_ptr->zstream.avail_in = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_in = png_ptr->zbuf; - - if (png_ptr->zbuf_size > png_ptr->idat_size) - png_ptr->zstream.avail_in = (uInt)png_ptr->idat_size; - - png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zstream.avail_in); - png_ptr->idat_size -= png_ptr->zstream.avail_in; - } - - ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH); - - if (ret == Z_STREAM_END) - { - if (!(png_ptr->zstream.avail_out) || png_ptr->zstream.avail_in || - png_ptr->idat_size) - png_warning(png_ptr, "Extra compressed data"); - - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - - if (ret != Z_OK) - png_error(png_ptr, png_ptr->zstream.msg ? png_ptr->zstream.msg : - "Decompression Error"); - - if (!(png_ptr->zstream.avail_out)) - { - png_warning(png_ptr, "Extra compressed data"); - png_ptr->mode |= PNG_AFTER_IDAT; - png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED; - break; - } - - } - png_ptr->zstream.avail_out = 0; - } - - if (png_ptr->idat_size || png_ptr->zstream.avail_in) - png_warning(png_ptr, "Extra compression data"); - - inflateReset(&png_ptr->zstream); - - png_ptr->mode |= PNG_AFTER_IDAT; + + /* Here after at the end of the last row of the last pass. */ + png_read_finish_IDAT(png_ptr); } -#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ +#endif /* SEQUENTIAL_READ */ void /* PRIVATE */ -png_read_start_row(png_structp png_ptr) +png_read_start_row(png_structrp png_ptr) { -#ifdef PNG_READ_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ - PNG_CONST int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ - PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ - PNG_CONST int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ - PNG_CONST int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; -#endif + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; int max_pixel_depth; png_size_t row_bytes; png_debug(1, "in png_read_start_row"); - png_ptr->zstream.avail_in = 0; + #ifdef PNG_READ_TRANSFORMS_SUPPORTED png_init_read_transformations(png_ptr); #endif -#ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { - if (!(png_ptr->transformations & PNG_INTERLACE)) + if ((png_ptr->transformations & PNG_INTERLACE) == 0) png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_pass_ystart[0]) / png_pass_yinc[0]; @@ -3478,7 +4249,6 @@ } else -#endif /* PNG_READ_INTERLACING_SUPPORTED */ { png_ptr->num_rows = png_ptr->height; png_ptr->iwidth = png_ptr->width; @@ -3486,17 +4256,27 @@ max_pixel_depth = png_ptr->pixel_depth; + /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of + * calculations to calculate the final pixel depth, then + * png_do_read_transforms actually does the transforms. This means that the + * code which effectively calculates this value is actually repeated in three + * separate places. They must all match. Innocent changes to the order of + * transformations can and will break libpng in a way that causes memory + * overwrites. + * + * TODO: fix this. + */ #ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) + if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8) max_pixel_depth = 8; #endif #ifdef PNG_READ_EXPAND_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND) + if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) max_pixel_depth = 32; else @@ -3508,13 +4288,13 @@ if (max_pixel_depth < 8) max_pixel_depth = 8; - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) max_pixel_depth *= 2; } else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) { - if (png_ptr->num_trans) + if (png_ptr->num_trans != 0) { max_pixel_depth *= 4; max_pixel_depth /= 3; @@ -3524,13 +4304,13 @@ #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND_16) + if ((png_ptr->transformations & PNG_EXPAND_16) != 0) { # ifdef PNG_READ_EXPAND_SUPPORTED /* In fact it is an error if it isn't supported, but checking is * the safe way. */ - if (png_ptr->transformations & PNG_EXPAND) + if ((png_ptr->transformations & PNG_EXPAND) != 0) { if (png_ptr->bit_depth < 16) max_pixel_depth *= 2; @@ -3542,12 +4322,9 @@ #endif #ifdef PNG_READ_FILLER_SUPPORTED - if (png_ptr->transformations & (PNG_FILLER)) + if ((png_ptr->transformations & (PNG_FILLER)) != 0) { - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - max_pixel_depth = 32; - - else if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) { if (max_pixel_depth <= 8) max_pixel_depth = 16; @@ -3556,7 +4333,8 @@ max_pixel_depth = 32; } - else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) + else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB || + png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { if (max_pixel_depth <= 32) max_pixel_depth = 32; @@ -3568,14 +4346,15 @@ #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if (png_ptr->transformations & PNG_GRAY_TO_RGB) + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) { if ( #ifdef PNG_READ_EXPAND_SUPPORTED - (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || + (png_ptr->num_trans != 0 && + (png_ptr->transformations & PNG_EXPAND) != 0) || #endif #ifdef PNG_READ_FILLER_SUPPORTED - (png_ptr->transformations & (PNG_FILLER)) || + (png_ptr->transformations & (PNG_FILLER)) != 0 || #endif png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { @@ -3608,16 +4387,22 @@ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) - if (png_ptr->transformations & PNG_USER_TRANSFORM) + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) { - int user_pixel_depth = png_ptr->user_transform_depth* + int user_pixel_depth = png_ptr->user_transform_depth * png_ptr->user_transform_channels; if (user_pixel_depth > max_pixel_depth) - max_pixel_depth=user_pixel_depth; + max_pixel_depth = user_pixel_depth; } #endif + /* This value is stored in png_struct and double checked in the row read + * code. + */ + png_ptr->maximum_pixel_depth = (png_byte)max_pixel_depth; + png_ptr->transformed_pixel_depth = 0; /* calculated on demand */ + /* Align the width on the next larger 8 pixels. Mainly used * for interlacing */ @@ -3636,28 +4421,39 @@ if (row_bytes + 48 > png_ptr->old_big_row_buf_size) { png_free(png_ptr, png_ptr->big_row_buf); - - if (png_ptr->interlaced) + png_free(png_ptr, png_ptr->big_prev_row); + + if (png_ptr->interlaced != 0) png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, row_bytes + 48); else - png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, - row_bytes + 48); - - png_ptr->old_big_row_buf_size = row_bytes + 48; + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + + png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48); #ifdef PNG_ALIGNED_MEMORY_SUPPORTED /* Use 16-byte aligned memory for row_buf with at least 16 bytes - * of padding before and after row_buf. + * of padding before and after row_buf; treat prev_row similarly. + * NOTE: the alignment is to the start of the pixels, one beyond the start + * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this + * was incorrect; the filter byte was aligned, which had the exact + * opposite effect of that intended. */ - png_ptr->row_buf = png_ptr->big_row_buf + 32 - - (((png_alloc_size_t)png_ptr->big_row_buf + 15) & 0x0F); - - png_ptr->old_big_row_buf_size = row_bytes + 48; + { + png_bytep temp = png_ptr->big_row_buf + 32; + int extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->row_buf = temp - extra - 1/*filter byte*/; + + temp = png_ptr->big_prev_row + 32; + extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->prev_row = temp - extra - 1/*filter byte*/; + } + #else - /* Use 32 bytes of padding before and 16 bytes after row_buf. */ - png_ptr->row_buf = png_ptr->big_row_buf + 32; + /* Use 31 bytes of padding before and 17 bytes after row_buf. */ + png_ptr->row_buf = png_ptr->big_row_buf + 31; + png_ptr->prev_row = png_ptr->big_prev_row + 31; #endif png_ptr->old_big_row_buf_size = row_bytes + 48; } @@ -3670,16 +4466,7 @@ if (png_ptr->rowbytes > (PNG_SIZE_MAX - 1)) png_error(png_ptr, "Row has too many bytes to allocate in memory"); - if (png_ptr->rowbytes + 1 > png_ptr->old_prev_row_size) - { - png_free(png_ptr, png_ptr->prev_row); - - png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); - - png_ptr->old_prev_row_size = png_ptr->rowbytes + 1; - } - - png_memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); + memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); png_debug1(3, "width = %u,", png_ptr->width); png_debug1(3, "height = %u,", png_ptr->height); @@ -3689,6 +4476,27 @@ png_debug1(3, "irowbytes = %lu", (unsigned long)PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->iwidth) + 1); + /* The sequential reader needs a buffer for IDAT, but the progressive reader + * does not, so free the read buffer now regardless; the sequential reader + * reallocates it on demand. + */ + if (png_ptr->read_buffer != 0) + { + png_bytep buffer = png_ptr->read_buffer; + + png_ptr->read_buffer_size = 0; + png_ptr->read_buffer = NULL; + png_free(png_ptr, buffer); + } + + /* Finally claim the zstream for the inflate of the IDAT data, use the bits + * value from the stream (note that this will result in a fatal error if the + * IDAT stream has a bogus deflate header window_bits value, but this should + * not be happening any longer!) + */ + if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + png_ptr->flags |= PNG_FLAG_ROW_INIT; } -#endif /* PNG_READ_SUPPORTED */ +#endif /* READ */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c --- a/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c Fri Apr 17 10:24:46 2015 -0700 @@ -29,8 +29,8 @@ * However, the following notice accompanied the original version of this * file and, per its terms, should not be removed: * - * Last changed in libpng 1.5.4 [July 7, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -50,51 +50,84 @@ #ifdef PNG_bKGD_SUPPORTED void PNGAPI -png_set_bKGD(png_structp png_ptr, png_infop info_ptr, +png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, png_const_color_16p background) { png_debug1(1, "in %s storage function", "bKGD"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || background == NULL) return; - png_memcpy(&(info_ptr->background), background, png_sizeof(png_color_16)); + info_ptr->background = *background; info_ptr->valid |= PNG_INFO_bKGD; } #endif #ifdef PNG_cHRM_SUPPORTED void PNGFAPI -png_set_cHRM_fixed(png_structp png_ptr, png_infop info_ptr, +png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, png_fixed_point blue_y) { + png_xy xy; + png_debug1(1, "in %s storage function", "cHRM fixed"); if (png_ptr == NULL || info_ptr == NULL) return; -# ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_ptr, - white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y)) -# endif - { - info_ptr->x_white = white_x; - info_ptr->y_white = white_y; - info_ptr->x_red = red_x; - info_ptr->y_red = red_y; - info_ptr->x_green = green_x; - info_ptr->y_green = green_y; - info_ptr->x_blue = blue_x; - info_ptr->y_blue = blue_y; - info_ptr->valid |= PNG_INFO_cHRM; - } + xy.redx = red_x; + xy.redy = red_y; + xy.greenx = green_x; + xy.greeny = green_y; + xy.bluex = blue_x; + xy.bluey = blue_y; + xy.whitex = white_x; + xy.whitey = white_y; + + if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy, + 2/* override with app values*/) != 0) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); +} + +void PNGFAPI +png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, + png_fixed_point int_blue_X, png_fixed_point int_blue_Y, + png_fixed_point int_blue_Z) +{ + png_XYZ XYZ; + + png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); + + if (png_ptr == NULL || info_ptr == NULL) + return; + + XYZ.red_X = int_red_X; + XYZ.red_Y = int_red_Y; + XYZ.red_Z = int_red_Z; + XYZ.green_X = int_green_X; + XYZ.green_Y = int_green_Y; + XYZ.green_Z = int_green_Z; + XYZ.blue_X = int_blue_X; + XYZ.blue_Y = int_blue_Y; + XYZ.blue_Z = int_blue_Z; + + if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, + &XYZ, 2) != 0) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_cHRM(png_structp png_ptr, png_infop info_ptr, +png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, double white_x, double white_y, double red_x, double red_y, double green_x, double green_y, double blue_x, double blue_y) { @@ -108,41 +141,44 @@ png_fixed(png_ptr, blue_x, "cHRM Blue X"), png_fixed(png_ptr, blue_y, "cHRM Blue Y")); } -# endif /* PNG_FLOATING_POINT_SUPPORTED */ -#endif /* PNG_cHRM_SUPPORTED */ +void PNGAPI +png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, + double red_Y, double red_Z, double green_X, double green_Y, double green_Z, + double blue_X, double blue_Y, double blue_Z) +{ + png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, + png_fixed(png_ptr, red_X, "cHRM Red X"), + png_fixed(png_ptr, red_Y, "cHRM Red Y"), + png_fixed(png_ptr, red_Z, "cHRM Red Z"), + png_fixed(png_ptr, green_X, "cHRM Red X"), + png_fixed(png_ptr, green_Y, "cHRM Red Y"), + png_fixed(png_ptr, green_Z, "cHRM Red Z"), + png_fixed(png_ptr, blue_X, "cHRM Red X"), + png_fixed(png_ptr, blue_Y, "cHRM Red Y"), + png_fixed(png_ptr, blue_Z, "cHRM Red Z")); +} +# endif /* FLOATING_POINT */ + +#endif /* cHRM */ #ifdef PNG_gAMA_SUPPORTED void PNGFAPI -png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point - file_gamma) +png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, + png_fixed_point file_gamma) { png_debug1(1, "in %s storage function", "gAMA"); if (png_ptr == NULL || info_ptr == NULL) return; - /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't - * occur. Since the fixed point representation is assymetrical it is - * possible for 1/gamma to overflow the limit of 21474 and this means the - * gamma value must be at least 5/100000 and hence at most 20000.0. For - * safety the limits here are a little narrower. The values are 0.00016 to - * 6250.0, which are truely ridiculous gammma values (and will produce - * displays that are all black or all white.) - */ - if (file_gamma < 16 || file_gamma > 625000000) - png_warning(png_ptr, "Out of range gamma value ignored"); - - else - { - info_ptr->gamma = file_gamma; - info_ptr->valid |= PNG_INFO_gAMA; - } + png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma); + png_colorspace_sync_info(png_ptr, info_ptr); } # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_gAMA(png_structp png_ptr, png_infop info_ptr, double file_gamma) +png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma) { png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma, "png_set_gAMA")); @@ -152,7 +188,8 @@ #ifdef PNG_hIST_SUPPORTED void PNGAPI -png_set_hIST(png_structp png_ptr, png_infop info_ptr, png_const_uint_16p hist) +png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_uint_16p hist) { int i; @@ -175,26 +212,26 @@ /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in * version 1.2.1 */ - png_ptr->hist = (png_uint_16p)png_malloc_warn(png_ptr, - PNG_MAX_PALETTE_LENGTH * png_sizeof(png_uint_16)); + info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16)))); - if (png_ptr->hist == NULL) + if (info_ptr->hist == NULL) { png_warning(png_ptr, "Insufficient memory for hIST chunk data"); return; } - for (i = 0; i < info_ptr->num_palette; i++) - png_ptr->hist[i] = hist[i]; + info_ptr->free_me |= PNG_FREE_HIST; - info_ptr->hist = png_ptr->hist; + for (i = 0; i < info_ptr->num_palette; i++) + info_ptr->hist[i] = hist[i]; + info_ptr->valid |= PNG_INFO_hIST; - info_ptr->free_me |= PNG_FREE_HIST; } #endif void PNGAPI -png_set_IHDR(png_structp png_ptr, png_infop info_ptr, +png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int interlace_type, int compression_type, int filter_type) @@ -219,32 +256,23 @@ if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; - else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) + else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) info_ptr->channels = 3; else info_ptr->channels = 1; - if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) + if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) info_ptr->channels++; info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); - /* Check for potential overflow */ - if (width > - (PNG_UINT_32_MAX >> 3) /* 8-byte RRGGBBAA pixels */ - - 48 /* bigrowbuf hack */ - - 1 /* filter byte */ - - 7*8 /* rounding of width to multiple of 8 pixels */ - - 8) /* extra max_pixel_depth pad */ - info_ptr->rowbytes = 0; - else - info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); } #ifdef PNG_oFFs_SUPPORTED void PNGAPI -png_set_oFFs(png_structp png_ptr, png_infop info_ptr, +png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, int unit_type) { png_debug1(1, "in %s storage function", "oFFs"); @@ -261,7 +289,7 @@ #ifdef PNG_pCAL_SUPPORTED void PNGAPI -png_set_pCAL(png_structp png_ptr, png_infop info_ptr, +png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params) { @@ -270,10 +298,11 @@ png_debug1(1, "in %s storage function", "pCAL"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL + || (nparams > 0 && params == NULL)) return; - length = png_strlen(purpose) + 1; + length = strlen(purpose) + 1; png_debug1(3, "allocating purpose for info (%lu bytes)", (unsigned long)length); @@ -283,12 +312,19 @@ if (type < 0 || type > 3) png_error(png_ptr, "Invalid pCAL equation type"); + if (nparams < 0 || nparams > 255) + png_error(png_ptr, "Invalid pCAL parameter count"); + /* Validate params[nparams] */ for (i=0; ipcal_purpose = (png_charp)png_malloc_warn(png_ptr, length); + info_ptr->pcal_purpose = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); if (info_ptr->pcal_purpose == NULL) { @@ -296,7 +332,7 @@ return; } - png_memcpy(info_ptr->pcal_purpose, purpose, length); + memcpy(info_ptr->pcal_purpose, purpose, length); png_debug(3, "storing X0, X1, type, and nparams in info"); info_ptr->pcal_X0 = X0; @@ -304,11 +340,12 @@ info_ptr->pcal_type = (png_byte)type; info_ptr->pcal_nparams = (png_byte)nparams; - length = png_strlen(units) + 1; + length = strlen(units) + 1; png_debug1(3, "allocating units for info (%lu bytes)", (unsigned long)length); - info_ptr->pcal_units = (png_charp)png_malloc_warn(png_ptr, length); + info_ptr->pcal_units = png_voidcast(png_charp, + png_malloc_warn(png_ptr, length)); if (info_ptr->pcal_units == NULL) { @@ -316,10 +353,10 @@ return; } - png_memcpy(info_ptr->pcal_units, units, length); + memcpy(info_ptr->pcal_units, units, length); - info_ptr->pcal_params = (png_charpp)png_malloc_warn(png_ptr, - (png_size_t)((nparams + 1) * png_sizeof(png_charp))); + info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, + (png_size_t)((nparams + 1) * (sizeof (png_charp))))); if (info_ptr->pcal_params == NULL) { @@ -327,11 +364,11 @@ return; } - png_memset(info_ptr->pcal_params, 0, (nparams + 1) * png_sizeof(png_charp)); + memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp))); for (i = 0; i < nparams; i++) { - length = png_strlen(params[i]) + 1; + length = strlen(params[i]) + 1; png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, (unsigned long)length); @@ -343,7 +380,7 @@ return; } - png_memcpy(info_ptr->pcal_params[i], params[i], length); + memcpy(info_ptr->pcal_params[i], params[i], length); } info_ptr->valid |= PNG_INFO_pCAL; @@ -353,7 +390,7 @@ #ifdef PNG_sCAL_SUPPORTED void PNGAPI -png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, +png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, int unit, png_const_charp swidth, png_const_charp sheight) { png_size_t lengthw = 0, lengthh = 0; @@ -369,11 +406,11 @@ if (unit != 1 && unit != 2) png_error(png_ptr, "Invalid sCAL unit"); - if (swidth == NULL || (lengthw = png_strlen(swidth)) == 0 || + if (swidth == NULL || (lengthw = strlen(swidth)) == 0 || swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) png_error(png_ptr, "Invalid sCAL width"); - if (sheight == NULL || (lengthh = png_strlen(sheight)) == 0 || + if (sheight == NULL || (lengthh = strlen(sheight)) == 0 || sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) png_error(png_ptr, "Invalid sCAL height"); @@ -383,7 +420,8 @@ png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); - info_ptr->scal_s_width = (png_charp)png_malloc_warn(png_ptr, lengthw); + info_ptr->scal_s_width = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthw)); if (info_ptr->scal_s_width == NULL) { @@ -391,13 +429,14 @@ return; } - png_memcpy(info_ptr->scal_s_width, swidth, lengthw); + memcpy(info_ptr->scal_s_width, swidth, lengthw); ++lengthh; png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); - info_ptr->scal_s_height = (png_charp)png_malloc_warn(png_ptr, lengthh); + info_ptr->scal_s_height = png_voidcast(png_charp, + png_malloc_warn(png_ptr, lengthh)); if (info_ptr->scal_s_height == NULL) { @@ -408,7 +447,7 @@ return; } - png_memcpy(info_ptr->scal_s_height, sheight, lengthh); + memcpy(info_ptr->scal_s_height, sheight, lengthh); info_ptr->valid |= PNG_INFO_sCAL; info_ptr->free_me |= PNG_FREE_SCAL; @@ -416,8 +455,8 @@ # ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_sCAL(png_structp png_ptr, png_infop info_ptr, int unit, double width, - double height) +png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, + double width, double height) { png_debug1(1, "in %s storage function", "sCAL"); @@ -434,9 +473,9 @@ char swidth[PNG_sCAL_MAX_DIGITS+1]; char sheight[PNG_sCAL_MAX_DIGITS+1]; - png_ascii_from_fp(png_ptr, swidth, sizeof swidth, width, + png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, PNG_sCAL_PRECISION); - png_ascii_from_fp(png_ptr, sheight, sizeof sheight, height, + png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, PNG_sCAL_PRECISION); png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); @@ -446,7 +485,7 @@ # ifdef PNG_FIXED_POINT_SUPPORTED void PNGAPI -png_set_sCAL_fixed(png_structp png_ptr, png_infop info_ptr, int unit, +png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit, png_fixed_point width, png_fixed_point height) { png_debug1(1, "in %s storage function", "sCAL"); @@ -464,8 +503,8 @@ char swidth[PNG_sCAL_MAX_DIGITS+1]; char sheight[PNG_sCAL_MAX_DIGITS+1]; - png_ascii_from_fixed(png_ptr, swidth, sizeof swidth, width); - png_ascii_from_fixed(png_ptr, sheight, sizeof sheight, height); + png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width); + png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height); png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); } @@ -475,7 +514,7 @@ #ifdef PNG_pHYs_SUPPORTED void PNGAPI -png_set_pHYs(png_structp png_ptr, png_infop info_ptr, +png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type) { png_debug1(1, "in %s storage function", "pHYs"); @@ -491,7 +530,7 @@ #endif void PNGAPI -png_set_PLTE(png_structp png_ptr, png_infop info_ptr, +png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_const_colorp palette, int num_palette) { @@ -526,6 +565,9 @@ /* It may not actually be necessary to set png_ptr->palette here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. + * + * 1.6.0: the above statement appears to be incorrect; something has to set + * the palette inside png_struct on read. */ png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); @@ -533,10 +575,11 @@ * of num_palette entries, in case of an invalid PNG file that has * too-large sample values. */ - png_ptr->palette = (png_colorp)png_calloc(png_ptr, - PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color)); + png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, + PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); - png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof(png_color)); + if (num_palette > 0) + memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color))); info_ptr->palette = png_ptr->palette; info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; @@ -547,34 +590,34 @@ #ifdef PNG_sBIT_SUPPORTED void PNGAPI -png_set_sBIT(png_structp png_ptr, png_infop info_ptr, +png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, png_const_color_8p sig_bit) { png_debug1(1, "in %s storage function", "sBIT"); - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL) return; - png_memcpy(&(info_ptr->sig_bit), sig_bit, png_sizeof(png_color_8)); + info_ptr->sig_bit = *sig_bit; info_ptr->valid |= PNG_INFO_sBIT; } #endif #ifdef PNG_sRGB_SUPPORTED void PNGAPI -png_set_sRGB(png_structp png_ptr, png_infop info_ptr, int srgb_intent) +png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) { png_debug1(1, "in %s storage function", "sRGB"); if (png_ptr == NULL || info_ptr == NULL) return; - info_ptr->srgb_intent = (png_byte)srgb_intent; - info_ptr->valid |= PNG_INFO_sRGB; + (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent); + png_colorspace_sync_info(png_ptr, info_ptr); } void PNGAPI -png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, +png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) { png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); @@ -582,71 +625,87 @@ if (png_ptr == NULL || info_ptr == NULL) return; - png_set_sRGB(png_ptr, info_ptr, srgb_intent); - -# ifdef PNG_gAMA_SUPPORTED - png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); -# endif + if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, + srgb_intent) != 0) + { + /* This causes the gAMA and cHRM to be written too */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } -# ifdef PNG_cHRM_SUPPORTED - png_set_cHRM_fixed(png_ptr, info_ptr, - /* color x y */ - /* white */ 31270L, 32900L, - /* red */ 64000L, 33000L, - /* green */ 30000L, 60000L, - /* blue */ 15000L, 6000L - ); -# endif /* cHRM */ + png_colorspace_sync_info(png_ptr, info_ptr); } #endif /* sRGB */ #ifdef PNG_iCCP_SUPPORTED void PNGAPI -png_set_iCCP(png_structp png_ptr, png_infop info_ptr, +png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp name, int compression_type, png_const_bytep profile, png_uint_32 proflen) { png_charp new_iccp_name; png_bytep new_iccp_profile; - png_uint_32 length; + png_size_t length; png_debug1(1, "in %s storage function", "iCCP"); if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) return; - length = png_strlen(name)+1; - new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length); + if (compression_type != PNG_COMPRESSION_TYPE_BASE) + png_app_error(png_ptr, "Invalid iCCP compression method"); + + /* Set the colorspace first because this validates the profile; do not + * override previously set app cHRM or gAMA here (because likely as not the + * application knows better than libpng what the correct values are.) Pass + * the info_ptr color_type field to png_colorspace_set_ICC because in the + * write case it has not yet been stored in png_ptr. + */ + { + int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name, + proflen, profile, info_ptr->color_type); + + png_colorspace_sync_info(png_ptr, info_ptr); + + /* Don't do any of the copying if the profile was bad, or inconsistent. */ + if (result == 0) + return; + + /* But do write the gAMA and cHRM chunks from the profile. */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } + + length = strlen(name)+1; + new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); if (new_iccp_name == NULL) { - png_warning(png_ptr, "Insufficient memory to process iCCP chunk"); + png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); return; } - png_memcpy(new_iccp_name, name, length); - new_iccp_profile = (png_bytep)png_malloc_warn(png_ptr, proflen); + memcpy(new_iccp_name, name, length); + new_iccp_profile = png_voidcast(png_bytep, + png_malloc_warn(png_ptr, proflen)); if (new_iccp_profile == NULL) { - png_free (png_ptr, new_iccp_name); - png_warning(png_ptr, + png_free(png_ptr, new_iccp_name); + new_iccp_name = NULL; + png_benign_error(png_ptr, "Insufficient memory to process iCCP profile"); return; } - png_memcpy(new_iccp_profile, profile, (png_size_t)proflen); + memcpy(new_iccp_profile, profile, proflen); png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); info_ptr->iccp_proflen = proflen; info_ptr->iccp_name = new_iccp_name; info_ptr->iccp_profile = new_iccp_profile; - /* Compression is always zero but is here so the API and info structure - * does not have to change if we introduce multiple compression types - */ - info_ptr->iccp_compression = (png_byte)compression_type; info_ptr->free_me |= PNG_FREE_ICCP; info_ptr->valid |= PNG_INFO_iCCP; } @@ -654,74 +713,81 @@ #ifdef PNG_TEXT_SUPPORTED void PNGAPI -png_set_text(png_structp png_ptr, png_infop info_ptr, png_const_textp text_ptr, - int num_text) +png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_textp text_ptr, int num_text) { int ret; ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); - if (ret) + if (ret != 0) png_error(png_ptr, "Insufficient memory to store text"); } int /* PRIVATE */ -png_set_text_2(png_structp png_ptr, png_infop info_ptr, +png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, png_const_textp text_ptr, int num_text) { int i; - png_debug1(1, "in %s storage function", ((png_ptr == NULL || - png_ptr->chunk_name[0] == '\0') ? - "text" : (png_const_charp)png_ptr->chunk_name)); + png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" : + (unsigned long)png_ptr->chunk_name); - if (png_ptr == NULL || info_ptr == NULL || num_text == 0) + if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) return(0); /* Make sure we have enough space in the "text" array in info_struct - * to hold all of the incoming text_ptr objects. + * to hold all of the incoming text_ptr objects. This compare can't overflow + * because max_text >= num_text (anyway, subtract of two positive integers + * can't overflow in any case.) */ - if (info_ptr->num_text + num_text > info_ptr->max_text) + if (num_text > info_ptr->max_text - info_ptr->num_text) { - if (info_ptr->text != NULL) - { - png_textp old_text; - int old_max; + int old_num_text = info_ptr->num_text; + int max_text; + png_textp new_text = NULL; - old_max = info_ptr->max_text; - info_ptr->max_text = info_ptr->num_text + num_text + 8; - old_text = info_ptr->text; - info_ptr->text = (png_textp)png_malloc_warn(png_ptr, - (png_size_t)(info_ptr->max_text * png_sizeof(png_text))); + /* Calculate an appropriate max_text, checking for overflow. */ + max_text = old_num_text; + if (num_text <= INT_MAX - max_text) + { + max_text += num_text; + + /* Round up to a multiple of 8 */ + if (max_text < INT_MAX-8) + max_text = (max_text + 8) & ~0x7; - if (info_ptr->text == NULL) - { - png_free(png_ptr, old_text); - return(1); - } + else + max_text = INT_MAX; - png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max * - png_sizeof(png_text))); - png_free(png_ptr, old_text); + /* Now allocate a new array and copy the old members in; this does all + * the overflow checks. + */ + new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, + info_ptr->text, old_num_text, max_text-old_num_text, + sizeof *new_text)); } - else + if (new_text == NULL) { - info_ptr->max_text = num_text + 8; - info_ptr->num_text = 0; - info_ptr->text = (png_textp)png_malloc_warn(png_ptr, - (png_size_t)(info_ptr->max_text * png_sizeof(png_text))); - if (info_ptr->text == NULL) - return(1); - info_ptr->free_me |= PNG_FREE_TEXT; + png_chunk_report(png_ptr, "too many text chunks", + PNG_CHUNK_WRITE_ERROR); + return 1; } - png_debug1(3, "allocated %d entries for info_ptr->text", - info_ptr->max_text); + png_free(png_ptr, info_ptr->text); + + info_ptr->text = new_text; + info_ptr->free_me |= PNG_FREE_TEXT; + info_ptr->max_text = max_text; + /* num_text is adjusted below as the entries are copied in */ + + png_debug1(3, "allocated %d entries for info_ptr->text", max_text); } + for (i = 0; i < num_text; i++) { - png_size_t text_length, key_len; - png_size_t lang_len, lang_key_len; + size_t text_length, key_len; + size_t lang_len, lang_key_len; png_textp textp = &(info_ptr->text[info_ptr->num_text]); if (text_ptr[i].key == NULL) @@ -730,11 +796,12 @@ if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE || text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) { - png_warning(png_ptr, "text compression mode is out of range"); + png_chunk_report(png_ptr, "text compression mode is out of range", + PNG_CHUNK_WRITE_ERROR); continue; } - key_len = png_strlen(text_ptr[i].key); + key_len = strlen(text_ptr[i].key); if (text_ptr[i].compression <= 0) { @@ -748,20 +815,21 @@ /* Set iTXt data */ if (text_ptr[i].lang != NULL) - lang_len = png_strlen(text_ptr[i].lang); + lang_len = strlen(text_ptr[i].lang); else lang_len = 0; if (text_ptr[i].lang_key != NULL) - lang_key_len = png_strlen(text_ptr[i].lang_key); + lang_key_len = strlen(text_ptr[i].lang_key); else lang_key_len = 0; } # else /* PNG_iTXt_SUPPORTED */ { - png_warning(png_ptr, "iTXt chunk not supported"); + png_chunk_report(png_ptr, "iTXt chunk not supported", + PNG_CHUNK_WRITE_ERROR); continue; } # endif @@ -780,32 +848,35 @@ else { - text_length = png_strlen(text_ptr[i].text); + text_length = strlen(text_ptr[i].text); textp->compression = text_ptr[i].compression; } - textp->key = (png_charp)png_malloc_warn(png_ptr, - (png_size_t) - (key_len + text_length + lang_len + lang_key_len + 4)); + textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr, + key_len + text_length + lang_len + lang_key_len + 4)); if (textp->key == NULL) - return(1); + { + png_chunk_report(png_ptr, "text chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + return 1; + } png_debug2(2, "Allocated %lu bytes at %p in png_set_text", (unsigned long)(png_uint_32) (key_len + lang_len + lang_key_len + text_length + 4), textp->key); - png_memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len)); + memcpy(textp->key, text_ptr[i].key, key_len); *(textp->key + key_len) = '\0'; if (text_ptr[i].compression > 0) { textp->lang = textp->key + key_len + 1; - png_memcpy(textp->lang, text_ptr[i].lang, lang_len); + memcpy(textp->lang, text_ptr[i].lang, lang_len); *(textp->lang + lang_len) = '\0'; textp->lang_key = textp->lang + lang_len + 1; - png_memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); + memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); *(textp->lang_key + lang_key_len) = '\0'; textp->text = textp->lang_key + lang_key_len + 1; } @@ -817,9 +888,8 @@ textp->text = textp->key + key_len + 1; } - if (text_length) - png_memcpy(textp->text, text_ptr[i].text, - (png_size_t)(text_length)); + if (text_length != 0) + memcpy(textp->text, text_ptr[i].text, text_length); *(textp->text + text_length) = '\0'; @@ -840,28 +910,39 @@ info_ptr->num_text++; png_debug1(3, "transferred text chunk %d", info_ptr->num_text); } + return(0); } #endif #ifdef PNG_tIME_SUPPORTED void PNGAPI -png_set_tIME(png_structp png_ptr, png_infop info_ptr, png_const_timep mod_time) +png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, + png_const_timep mod_time) { png_debug1(1, "in %s storage function", "tIME"); - if (png_ptr == NULL || info_ptr == NULL || - (png_ptr->mode & PNG_WROTE_tIME)) + if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || + (png_ptr->mode & PNG_WROTE_tIME) != 0) return; - png_memcpy(&(info_ptr->mod_time), mod_time, png_sizeof(png_time)); + if (mod_time->month == 0 || mod_time->month > 12 || + mod_time->day == 0 || mod_time->day > 31 || + mod_time->hour > 23 || mod_time->minute > 59 || + mod_time->second > 60) + { + png_warning(png_ptr, "Ignoring invalid time value"); + return; + } + + info_ptr->mod_time = *mod_time; info_ptr->valid |= PNG_INFO_tIME; } #endif #ifdef PNG_tRNS_SUPPORTED void PNGAPI -png_set_tRNS(png_structp png_ptr, png_infop info_ptr, +png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color) { png_debug1(1, "in %s storage function", "tRNS"); @@ -874,16 +955,20 @@ /* It may not actually be necessary to set png_ptr->trans_alpha here; * we do it for backward compatibility with the way the png_handle_tRNS * function used to do the allocation. + * + * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively + * relies on png_set_tRNS storing the information in png_struct + * (otherwise it won't be there for the code in pngrtran.c). */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ - png_ptr->trans_alpha = info_ptr->trans_alpha = - (png_bytep)png_malloc(png_ptr, (png_size_t)PNG_MAX_PALETTE_LENGTH); + png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep, + png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) - png_memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); + memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); } if (trans_color != NULL) @@ -891,16 +976,15 @@ int sample_max = (1 << info_ptr->bit_depth); if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && - (int)trans_color->gray > sample_max) || + trans_color->gray > sample_max) || (info_ptr->color_type == PNG_COLOR_TYPE_RGB && - ((int)trans_color->red > sample_max || - (int)trans_color->green > sample_max || - (int)trans_color->blue > sample_max))) + (trans_color->red > sample_max || + trans_color->green > sample_max || + trans_color->blue > sample_max))) png_warning(png_ptr, "tRNS chunk has out-of-range samples for bit_depth"); - png_memcpy(&(info_ptr->trans_color), trans_color, - png_sizeof(png_color_16)); + info_ptr->trans_color = *trans_color; if (num_trans == 0) num_trans = 1; @@ -918,8 +1002,8 @@ #ifdef PNG_sPLT_SUPPORTED void PNGAPI -png_set_sPLT(png_structp png_ptr, - png_infop info_ptr, png_const_sPLT_tp entries, int nentries) +png_set_sPLT(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) /* * entries - array of png_sPLT_t structures * to be added to the list of palettes @@ -930,220 +1014,455 @@ */ { png_sPLT_tp np; - int i; - if (png_ptr == NULL || info_ptr == NULL) + if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) return; - np = (png_sPLT_tp)png_malloc_warn(png_ptr, - (info_ptr->splt_palettes_num + nentries) * - (png_size_t)png_sizeof(png_sPLT_t)); + /* Use the internal realloc function, which checks for all the possible + * overflows. Notice that the parameters are (int) and (size_t) + */ + np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, + info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, + sizeof *np)); if (np == NULL) { - png_warning(png_ptr, "No memory for sPLT palettes"); + /* Out of memory or too many chunks */ + png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); return; } - png_memcpy(np, info_ptr->splt_palettes, - info_ptr->splt_palettes_num * png_sizeof(png_sPLT_t)); - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes=NULL; + info_ptr->splt_palettes = np; + info_ptr->free_me |= PNG_FREE_SPLT; - for (i = 0; i < nentries; i++) - { - png_sPLT_tp to = np + info_ptr->splt_palettes_num + i; - png_const_sPLT_tp from = entries + i; - png_uint_32 length; - - length = png_strlen(from->name) + 1; - to->name = (png_charp)png_malloc_warn(png_ptr, (png_size_t)length); + np += info_ptr->splt_palettes_num; - if (to->name == NULL) - { - png_warning(png_ptr, - "Out of memory while processing sPLT chunk"); - continue; - } + do + { + png_size_t length; - png_memcpy(to->name, from->name, length); - to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr, - (png_size_t)(from->nentries * png_sizeof(png_sPLT_entry))); - - if (to->entries == NULL) + /* Skip invalid input entries */ + if (entries->name == NULL || entries->entries == NULL) { - png_warning(png_ptr, - "Out of memory while processing sPLT chunk"); - png_free(png_ptr, to->name); - to->name = NULL; + /* png_handle_sPLT doesn't do this, so this is an app error */ + png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); + /* Just skip the invalid entry */ continue; } - png_memcpy(to->entries, from->entries, - from->nentries * png_sizeof(png_sPLT_entry)); + np->depth = entries->depth; + + /* In the event of out-of-memory just return - there's no point keeping + * on trying to add sPLT chunks. + */ + length = strlen(entries->name) + 1; + np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); + + if (np->name == NULL) + break; + + memcpy(np->name, entries->name, length); + + /* IMPORTANT: we have memory now that won't get freed if something else + * goes wrong; this code must free it. png_malloc_array produces no + * warnings; use a png_chunk_report (below) if there is an error. + */ + np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, + entries->nentries, sizeof (png_sPLT_entry))); + + if (np->entries == NULL) + { + png_free(png_ptr, np->name); + np->name = NULL; + break; + } - to->nentries = from->nentries; - to->depth = from->depth; + np->nentries = entries->nentries; + /* This multiply can't overflow because png_malloc_array has already + * checked it when doing the allocation. + */ + memcpy(np->entries, entries->entries, + entries->nentries * sizeof (png_sPLT_entry)); + + /* Note that 'continue' skips the advance of the out pointer and out + * count, so an invalid entry is not added. + */ + info_ptr->valid |= PNG_INFO_sPLT; + ++(info_ptr->splt_palettes_num); + ++np; + } + while (++entries, --nentries); + + if (nentries > 0) + png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); +} +#endif /* sPLT */ + +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED +static png_byte +check_location(png_const_structrp png_ptr, int location) +{ + location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); + + /* New in 1.6.0; copy the location and check it. This is an API + * change; previously the app had to use the + * png_set_unknown_chunk_location API below for each chunk. + */ + if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + /* Write struct, so unknown chunks come from the app */ + png_app_warning(png_ptr, + "png_set_unknown_chunks now expects a valid location"); + /* Use the old behavior */ + location = (png_byte)(png_ptr->mode & + (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); } - info_ptr->splt_palettes = np; - info_ptr->splt_palettes_num += nentries; - info_ptr->valid |= PNG_INFO_sPLT; - info_ptr->free_me |= PNG_FREE_SPLT; + /* This need not be an internal error - if the app calls + * png_set_unknown_chunks on a read pointer it must get the location right. + */ + if (location == 0) + png_error(png_ptr, "invalid location in png_set_unknown_chunks"); + + /* Now reduce the location to the top-most set bit by removing each least + * significant bit in turn. + */ + while (location != (location & -location)) + location &= ~(location & -location); + + /* The cast is safe because 'location' is a bit mask and only the low four + * bits are significant. + */ + return (png_byte)location; } -#endif /* PNG_sPLT_SUPPORTED */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED void PNGAPI -png_set_unknown_chunks(png_structp png_ptr, - png_infop info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) +png_set_unknown_chunks(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) { png_unknown_chunkp np; - int i; - if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0) + if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || + unknowns == NULL) return; - np = (png_unknown_chunkp)png_malloc_warn(png_ptr, - (png_size_t)(info_ptr->unknown_chunks_num + num_unknowns) * - png_sizeof(png_unknown_chunk)); + /* Check for the failure cases where support has been disabled at compile + * time. This code is hardly ever compiled - it's here because + * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this + * code) but may be meaningless if the read or write handling of unknown + * chunks is not compiled in. + */ +# if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_READ_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_app_error(png_ptr, "no unknown chunk support on read"); + return; + } +# endif +# if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ + defined(PNG_WRITE_SUPPORTED) + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + png_app_error(png_ptr, "no unknown chunk support on write"); + return; + } +# endif + + /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that + * unknown critical chunks could be lost with just a warning resulting in + * undefined behavior. Now png_chunk_report is used to provide behavior + * appropriate to read or write. + */ + np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, + info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, + sizeof *np)); if (np == NULL) { - png_warning(png_ptr, - "Out of memory while processing unknown chunk"); + png_chunk_report(png_ptr, "too many unknown chunks", + PNG_CHUNK_WRITE_ERROR); return; } - png_memcpy(np, info_ptr->unknown_chunks, - (png_size_t)info_ptr->unknown_chunks_num * - png_sizeof(png_unknown_chunk)); + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = np; /* safe because it is initialized */ + info_ptr->free_me |= PNG_FREE_UNKN; - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; + np += info_ptr->unknown_chunks_num; - for (i = 0; i < num_unknowns; i++) + /* Increment unknown_chunks_num each time round the loop to protect the + * just-allocated chunk data. + */ + for (; num_unknowns > 0; --num_unknowns, ++unknowns) { - png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i; - png_const_unknown_chunkp from = unknowns + i; + memcpy(np->name, unknowns->name, (sizeof np->name)); + np->name[(sizeof np->name)-1] = '\0'; + np->location = check_location(png_ptr, unknowns->location); - png_memcpy(to->name, from->name, png_sizeof(from->name)); - to->name[png_sizeof(to->name)-1] = '\0'; - to->size = from->size; - - /* Note our location in the read or write sequence */ - to->location = (png_byte)(png_ptr->mode & 0xff); - - if (from->size == 0) - to->data=NULL; + if (unknowns->size == 0) + { + np->data = NULL; + np->size = 0; + } else { - to->data = (png_bytep)png_malloc_warn(png_ptr, - (png_size_t)from->size); + np->data = png_voidcast(png_bytep, + png_malloc_base(png_ptr, unknowns->size)); - if (to->data == NULL) + if (np->data == NULL) { - png_warning(png_ptr, - "Out of memory while processing unknown chunk"); - to->size = 0; + png_chunk_report(png_ptr, "unknown chunk: out of memory", + PNG_CHUNK_WRITE_ERROR); + /* But just skip storing the unknown chunk */ + continue; } - else - png_memcpy(to->data, from->data, from->size); + memcpy(np->data, unknowns->data, unknowns->size); + np->size = unknowns->size; } + + /* These increments are skipped on out-of-memory for the data - the + * unknown chunk entry gets overwritten if the png_chunk_report returns. + * This is correct in the read case (the chunk is just dropped.) + */ + ++np; + ++(info_ptr->unknown_chunks_num); } - - info_ptr->unknown_chunks = np; - info_ptr->unknown_chunks_num += num_unknowns; - info_ptr->free_me |= PNG_FREE_UNKN; } void PNGAPI -png_set_unknown_chunk_location(png_structp png_ptr, png_infop info_ptr, +png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location) { - if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk < - info_ptr->unknown_chunks_num) - info_ptr->unknown_chunks[chunk].location = (png_byte)location; + /* This API is pretty pointless in 1.6.0 because the location can be set + * before the call to png_set_unknown_chunks. + * + * TODO: add a png_app_warning in 1.7 + */ + if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && + chunk < info_ptr->unknown_chunks_num) + { + if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0) + { + png_app_error(png_ptr, "invalid unknown chunk location"); + /* Fake out the pre 1.6.0 behavior: */ + if ((location & PNG_HAVE_IDAT) != 0) /* undocumented! */ + location = PNG_AFTER_IDAT; + + else + location = PNG_HAVE_IHDR; /* also undocumented */ + } + + info_ptr->unknown_chunks[chunk].location = + check_location(png_ptr, location); + } } #endif #ifdef PNG_MNG_FEATURES_SUPPORTED png_uint_32 PNGAPI -png_permit_mng_features (png_structp png_ptr, png_uint_32 mng_features) +png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features) { png_debug(1, "in png_permit_mng_features"); if (png_ptr == NULL) - return (png_uint_32)0; + return 0; - png_ptr->mng_features_permitted = - (png_byte)(mng_features & PNG_ALL_MNG_FEATURES); + png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES; - return (png_uint_32)png_ptr->mng_features_permitted; + return png_ptr->mng_features_permitted; } #endif #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED +static unsigned int +add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) +{ + unsigned int i; + + /* Utility function: update the 'keep' state of a chunk if it is already in + * the list, otherwise add it to the list. + */ + for (i=0; i= PNG_HANDLE_CHUNK_LAST) { - if (keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE) - png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); + return; + } + + if (num_chunks_in <= 0) + { + png_ptr->unknown_default = keep; + + /* '0' means just set the flags, so stop here */ + if (num_chunks_in == 0) + return; + } - else - png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS; + if (num_chunks_in < 0) + { + /* Ignore all unknown chunks and all chunks recognized by + * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND + */ + static PNG_CONST png_byte chunks_to_ignore[] = { + 98, 75, 71, 68, '\0', /* bKGD */ + 99, 72, 82, 77, '\0', /* cHRM */ + 103, 65, 77, 65, '\0', /* gAMA */ + 104, 73, 83, 84, '\0', /* hIST */ + 105, 67, 67, 80, '\0', /* iCCP */ + 105, 84, 88, 116, '\0', /* iTXt */ + 111, 70, 70, 115, '\0', /* oFFs */ + 112, 67, 65, 76, '\0', /* pCAL */ + 112, 72, 89, 115, '\0', /* pHYs */ + 115, 66, 73, 84, '\0', /* sBIT */ + 115, 67, 65, 76, '\0', /* sCAL */ + 115, 80, 76, 84, '\0', /* sPLT */ + 115, 84, 69, 82, '\0', /* sTER */ + 115, 82, 71, 66, '\0', /* sRGB */ + 116, 69, 88, 116, '\0', /* tEXt */ + 116, 73, 77, 69, '\0', /* tIME */ + 122, 84, 88, 116, '\0' /* zTXt */ + }; - if (keep == PNG_HANDLE_CHUNK_ALWAYS) - png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS; + chunk_list = chunks_to_ignore; + num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U; + } - else - png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS; + else /* num_chunks_in > 0 */ + { + if (chunk_list == NULL) + { + /* Prior to 1.6.0 this was silently ignored, now it is an app_error + * which can be switched off. + */ + png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); + return; + } + num_chunks = num_chunks_in; + } + + old_num_chunks = png_ptr->num_chunk_list; + if (png_ptr->chunk_list == NULL) + old_num_chunks = 0; + + /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow. + */ + if (num_chunks + old_num_chunks > UINT_MAX/5) + { + png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); return; } - if (chunk_list == NULL) - return; - - old_num_chunks = png_ptr->num_chunk_list; - new_list=(png_bytep)png_malloc(png_ptr, - (png_size_t)(5*(num_chunks + old_num_chunks))); + /* If these chunks are being reset to the default then no more memory is + * required because add_one_chunk above doesn't extend the list if the 'keep' + * parameter is the default. + */ + if (keep != 0) + { + new_list = png_voidcast(png_bytep, png_malloc(png_ptr, + 5 * (num_chunks + old_num_chunks))); - if (png_ptr->chunk_list != NULL) - { - png_memcpy(new_list, png_ptr->chunk_list, - (png_size_t)(5*old_num_chunks)); - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list=NULL; + if (old_num_chunks > 0) + memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); } - png_memcpy(new_list + 5*old_num_chunks, chunk_list, - (png_size_t)(5*num_chunks)); + else if (old_num_chunks > 0) + new_list = png_ptr->chunk_list; + + else + new_list = NULL; + + /* Add the new chunks together with each one's handling code. If the chunk + * already exists the code is updated, otherwise the chunk is added to the + * end. (In libpng 1.6.0 order no longer matters because this code enforces + * the earlier convention that the last setting is the one that is used.) + */ + if (new_list != NULL) + { + png_const_bytep inlist; + png_bytep outlist; + unsigned int i; + + for (i=0; inum_chunk_list = old_num_chunks + num_chunks; - png_ptr->chunk_list = new_list; - png_ptr->free_me |= PNG_FREE_LIST; + /* This means the application has removed all the specialized handling. */ + if (num_chunks == 0) + { + if (png_ptr->chunk_list != new_list) + png_free(png_ptr, new_list); + + new_list = NULL; + } + } + + else + num_chunks = 0; + + png_ptr->num_chunk_list = num_chunks; + + if (png_ptr->chunk_list != new_list) + { + if (png_ptr->chunk_list != NULL) + png_free(png_ptr, png_ptr->chunk_list); + + png_ptr->chunk_list = new_list; + } } #endif #ifdef PNG_READ_USER_CHUNKS_SUPPORTED void PNGAPI -png_set_read_user_chunk_fn(png_structp png_ptr, png_voidp user_chunk_ptr, +png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn) { png_debug(1, "in png_set_read_user_chunk_fn"); @@ -1158,64 +1477,90 @@ #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI -png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers) +png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr, + png_bytepp row_pointers) { png_debug1(1, "in %s storage function", "rows"); if (png_ptr == NULL || info_ptr == NULL) return; - if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) + if (info_ptr->row_pointers != NULL && + (info_ptr->row_pointers != row_pointers)) png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); info_ptr->row_pointers = row_pointers; - if (row_pointers) + if (row_pointers != NULL) info_ptr->valid |= PNG_INFO_IDAT; } #endif void PNGAPI -png_set_compression_buffer_size(png_structp png_ptr, png_size_t size) +png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size) { if (png_ptr == NULL) return; - png_free(png_ptr, png_ptr->zbuf); + if (size == 0 || size > PNG_UINT_31_MAX) + png_error(png_ptr, "invalid compression buffer size"); - if (size > ZLIB_IO_MAX) - { - png_warning(png_ptr, "Attempt to set buffer size beyond max ignored"); - png_ptr->zbuf_size = ZLIB_IO_MAX; - size = ZLIB_IO_MAX; /* must fit */ - } +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { + png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ + return; + } +# endif + +# ifdef PNG_WRITE_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + { + if (png_ptr->zowner != 0) + { + png_warning(png_ptr, + "Compression buffer size cannot be changed because it is in use"); + return; + } - else - png_ptr->zbuf_size = (uInt)size; - - png_ptr->zbuf = (png_bytep)png_malloc(png_ptr, size); + if (size > ZLIB_IO_MAX) + { + png_warning(png_ptr, + "Compression buffer size limited to system maximum"); + size = ZLIB_IO_MAX; /* must fit */ + } - /* The following ensures a relatively safe failure if this gets called while - * the buffer is actually in use. - */ - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = 0; - png_ptr->zstream.avail_in = 0; + else if (size < 6) + { + /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH + * if this is permitted. + */ + png_warning(png_ptr, + "Compression buffer size cannot be reduced below 6"); + return; + } + + if (png_ptr->zbuffer_size != size) + { + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_ptr->zbuffer_size = (uInt)size; + } + } +# endif } void PNGAPI -png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask) +png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) { - if (png_ptr && info_ptr) + if (png_ptr != NULL && info_ptr != NULL) info_ptr->valid &= ~mask; } - #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* This function was added to libpng 1.2.6 */ void PNGAPI -png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, +png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max) { /* Images with dimensions larger than these limits will be @@ -1231,35 +1576,64 @@ /* This function was added to libpng 1.4.0 */ void PNGAPI -png_set_chunk_cache_max (png_structp png_ptr, - png_uint_32 user_chunk_cache_max) +png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) { - if (png_ptr) + if (png_ptr != NULL) png_ptr->user_chunk_cache_max = user_chunk_cache_max; } /* This function was added to libpng 1.4.1 */ void PNGAPI -png_set_chunk_malloc_max (png_structp png_ptr, +png_set_chunk_malloc_max (png_structrp png_ptr, png_alloc_size_t user_chunk_malloc_max) { - if (png_ptr) + if (png_ptr != NULL) png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; } -#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ +#endif /* ?SET_USER_LIMITS */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI -png_set_benign_errors(png_structp png_ptr, int allowed) +png_set_benign_errors(png_structrp png_ptr, int allowed) { png_debug(1, "in png_set_benign_errors"); - if (allowed) - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + /* If allowed is 1, png_benign_error() is treated as a warning. + * + * If allowed is 0, png_benign_error() is treated as an error (which + * is the default behavior if png_set_benign_errors() is not called). + */ + + if (allowed != 0) + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; else - png_ptr->flags &= ~PNG_FLAG_BENIGN_ERRORS_WARN; + png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | + PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); } -#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif /* BENIGN_ERRORS */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Whether to report invalid palette index; added at libng-1.5.10. + * It is possible for an indexed (color-type==3) PNG file to contain + * pixels with invalid (out-of-range) indexes if the PLTE chunk has + * fewer entries than the image's bit-depth would allow. We recover + * from this gracefully by filling any incomplete palette with zeros + * (opaque black). By default, when this occurs libpng will issue + * a benign error. This API can be used to override that behavior. + */ +void PNGAPI +png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) +{ + png_debug(1, "in png_set_check_for_invalid_index"); + + if (allowed > 0) + png_ptr->num_palette_max = 0; + + else + png_ptr->num_palette_max = -1; +} +#endif +#endif /* READ || WRITE */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h --- a/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngstruct.h Fri Apr 17 10:24:46 2015 -0700 @@ -29,11 +29,11 @@ * However, the following notice accompanied the original version of this * file and, per its terms, should not be removed: * - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Copyright (c) 1998-2013 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.5.4 [July 7, 2011] + * Last changed in libpng 1.6.1 [March 28, 2013] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -52,13 +52,130 @@ * in this structure and is required for decompressing the LZ compressed * data in PNG files. */ +#ifndef ZLIB_CONST + /* We must ensure that zlib uses 'const' in declarations. */ +# define ZLIB_CONST +#endif #include "zlib.h" +#ifdef const + /* zlib.h sometimes #defines const to nothing, undo this. */ +# undef const +#endif + +/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility + * with older builds. + */ +#if ZLIB_VERNUM < 0x1260 +# define PNGZ_MSG_CAST(s) png_constcast(char*,s) +# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b) +#else +# define PNGZ_MSG_CAST(s) (s) +# define PNGZ_INPUT_CAST(b) (b) +#endif + +/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib + * can handle at once. This type need be no larger than 16 bits (so maximum of + * 65535), this define allows us to discover how big it is, but limited by the + * maximuum for png_size_t. The value can be overriden in a library build + * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably + * lower value (e.g. 255 works). A lower value may help memory usage (slightly) + * and may even improve performance on some systems (and degrade it on others.) + */ +#ifndef ZLIB_IO_MAX +# define ZLIB_IO_MAX ((uInt)-1) +#endif + +#ifdef PNG_WRITE_SUPPORTED +/* The type of a compression buffer list used by the write code. */ +typedef struct png_compression_buffer +{ + struct png_compression_buffer *next; + png_byte output[1]; /* actually zbuf_size */ +} png_compression_buffer, *png_compression_bufferp; + +#define PNG_COMPRESSION_BUFFER_SIZE(pp)\ + (offsetof(png_compression_buffer, output) + (pp)->zbuffer_size) +#endif + +/* Colorspace support; structures used in png_struct, png_info and in internal + * functions to hold and communicate information about the color space. + * + * PNG_COLORSPACE_SUPPORTED is only required if the application will perform + * colorspace corrections, otherwise all the colorspace information can be + * skipped and the size of libpng can be reduced (significantly) by compiling + * out the colorspace support. + */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* The chromaticities of the red, green and blue colorants and the chromaticity + * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). + */ +typedef struct png_xy +{ + png_fixed_point redx, redy; + png_fixed_point greenx, greeny; + png_fixed_point bluex, bluey; + png_fixed_point whitex, whitey; +} png_xy; + +/* The same data as above but encoded as CIE XYZ values. When this data comes + * from chromaticities the sum of the Y values is assumed to be 1.0 + */ +typedef struct png_XYZ +{ + png_fixed_point red_X, red_Y, red_Z; + png_fixed_point green_X, green_Y, green_Z; + png_fixed_point blue_X, blue_Y, blue_Z; +} png_XYZ; +#endif /* COLORSPACE */ + +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) +/* A colorspace is all the above plus, potentially, profile information, + * however at present libpng does not use the profile internally so it is only + * stored in the png_info struct (if iCCP is supported.) The rendering intent + * is retained here and is checked. + * + * The file gamma encoding information is also stored here and gamma correction + * is done by libpng, whereas color correction must currently be done by the + * application. + */ +typedef struct png_colorspace +{ +#ifdef PNG_GAMMA_SUPPORTED + png_fixed_point gamma; /* File gamma */ +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED + png_xy end_points_xy; /* End points as chromaticities */ + png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ + png_uint_16 rendering_intent; /* Rendering intent of a profile */ +#endif + + /* Flags are always defined to simplify the code. */ + png_uint_16 flags; /* As defined below */ +} png_colorspace, * PNG_RESTRICT png_colorspacerp; + +typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp; + +/* General flags for the 'flags' field */ +#define PNG_COLORSPACE_HAVE_GAMMA 0x0001 +#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002 +#define PNG_COLORSPACE_HAVE_INTENT 0x0004 +#define PNG_COLORSPACE_FROM_gAMA 0x0008 +#define PNG_COLORSPACE_FROM_cHRM 0x0010 +#define PNG_COLORSPACE_FROM_sRGB 0x0020 +#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040 +#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */ +#define PNG_COLORSPACE_INVALID 0x8000 +#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags)) +#endif /* COLORSPACE || GAMMA */ struct png_struct_def { #ifdef PNG_SETJMP_SUPPORTED - jmp_buf longjmp_buffer; /* used in png_error */ + jmp_buf jmp_buf_local; /* New name in 1.6.0 for jmp_buf in png_struct */ png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ + jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */ + size_t jmp_buf_size; /* size of the above, if allocated */ #endif png_error_ptr error_fn; /* function for printing errors and aborting */ #ifdef PNG_WARNINGS_SUPPORTED @@ -91,22 +208,12 @@ png_uint_32 flags; /* flags indicating various things to libpng */ png_uint_32 transformations; /* which transformations to perform */ - z_stream zstream; /* pointer to decompression structure (below) */ - png_bytep zbuf; /* buffer for zlib */ - uInt zbuf_size; /* size of zbuf (typically 65536) */ -#ifdef PNG_WRITE_SUPPORTED + png_uint_32 zowner; /* ID (chunk type) of zstream owner, 0 if none */ + z_stream zstream; /* decompression structure */ -/* Added in 1.5.4: state to keep track of whether the zstream has been - * initialized and if so whether it is for IDAT or some other chunk. - */ -#define PNG_ZLIB_UNINITIALIZED 0 -#define PNG_ZLIB_FOR_IDAT 1 -#define PNG_ZLIB_FOR_TEXT 2 /* anything other than IDAT */ -#define PNG_ZLIB_USE_MASK 3 /* bottom two bits */ -#define PNG_ZLIB_IN_USE 4 /* a flag value */ - - png_uint_32 zlib_state; /* State of zlib initialization */ -/* End of material added at libpng 1.5.4 */ +#ifdef PNG_WRITE_SUPPORTED + png_compression_bufferp zbuffer_list; /* Created on demand during write */ + uInt zbuffer_size; /* size of the actual buffer */ int zlib_level; /* holds zlib compression level */ int zlib_method; /* holds zlib compression method */ @@ -115,8 +222,7 @@ int zlib_strategy; /* holds zlib compression strategy */ #endif /* Added at libpng 1.5.4 */ -#if defined(PNG_WRITE_COMPRESSED_TEXT_SUPPORTED) || \ - defined(PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED) +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED int zlib_text_level; /* holds zlib compression level */ int zlib_text_method; /* holds zlib compression method */ int zlib_text_window_bits; /* holds zlib compression window bits */ @@ -124,6 +230,14 @@ int zlib_text_strategy; /* holds zlib compression strategy */ #endif /* End of material added at libpng 1.5.4 */ +/* Added at libpng 1.6.0 */ +#ifdef PNG_WRITE_SUPPORTED + int zlib_set_level; /* Actual values set into the zstream on write */ + int zlib_set_method; + int zlib_set_window_bits; + int zlib_set_mem_level; + int zlib_set_strategy; +#endif png_uint_32 width; /* width of image in pixels */ png_uint_32 height; /* height of image in pixels */ @@ -132,21 +246,32 @@ png_size_t rowbytes; /* size of row in bytes */ png_uint_32 iwidth; /* width of current interlaced row in pixels */ png_uint_32 row_number; /* current row in interlace pass */ - png_bytep prev_row; /* buffer to save previous (unfiltered) row */ - png_bytep row_buf; /* buffer to save current (unfiltered) row */ + png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ + png_bytep prev_row; /* buffer to save previous (unfiltered) row. + * This is a pointer into big_prev_row + */ + png_bytep row_buf; /* buffer to save current (unfiltered) row. + * This is a pointer into big_row_buf + */ +#ifdef PNG_WRITE_SUPPORTED png_bytep sub_row; /* buffer to save "sub" row when filtering */ png_bytep up_row; /* buffer to save "up" row when filtering */ png_bytep avg_row; /* buffer to save "avg" row when filtering */ png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ - png_row_info row_info; /* used for transformation routines */ +#endif png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ png_uint_32 idat_size; /* current IDAT size for read */ png_uint_32 crc; /* current chunk CRC value */ png_colorp palette; /* palette from the input file */ png_uint_16 num_palette; /* number of color entries in palette */ + +/* Added at libpng-1.5.10 */ +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED + int num_palette_max; /* maximum palette index found in IDAT */ +#endif + png_uint_16 num_trans; /* number of transparency values */ - png_byte chunk_name[5]; /* null-terminated name of current chunk */ png_byte compression; /* file compression type (always 0) */ png_byte filter; /* file filter type (always 0) */ png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ @@ -154,12 +279,17 @@ png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ png_byte color_type; /* color type of file */ png_byte bit_depth; /* bit depth of file */ - png_byte usr_bit_depth; /* bit depth of users row */ + png_byte usr_bit_depth; /* bit depth of users row: write only */ png_byte pixel_depth; /* number of bits per pixel */ png_byte channels; /* number of channels in file */ - png_byte usr_channels; /* channels at start of write */ +#ifdef PNG_WRITE_SUPPORTED + png_byte usr_channels; /* channels at start of write: write only */ +#endif png_byte sig_bytes; /* magic bytes read/written from start of file */ - + png_byte maximum_pixel_depth; + /* pixel depth used for the row buffers */ + png_byte transformed_pixel_depth; + /* pixel depth after read/write transforms */ #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) png_uint_16 filler; /* filler bytes for pixel expansion */ #endif @@ -172,7 +302,7 @@ #ifdef PNG_READ_GAMMA_SUPPORTED png_color_16 background_1; /* background normalized to gamma 1.0 */ #endif -#endif /* PNG_bKGD_SUPPORTED */ +#endif /* bKGD */ #ifdef PNG_WRITE_FLUSH_SUPPORTED png_flush_ptr output_flush_fn; /* Function for flushing output */ @@ -180,19 +310,20 @@ png_uint_32 flush_rows; /* number of rows written since last flush */ #endif -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) +#ifdef PNG_READ_GAMMA_SUPPORTED int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ - png_fixed_point gamma; /* file gamma value */ png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */ -#endif -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) png_bytep gamma_table; /* gamma table for 8-bit depth files */ + png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) png_bytep gamma_from_1; /* converts from 1.0 to screen */ png_bytep gamma_to_1; /* converts from file to 1.0 */ - png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ #endif #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) @@ -228,14 +359,7 @@ int process_mode; /* what push library is currently doing */ int cur_palette; /* current push library palette index */ -# ifdef PNG_TEXT_SUPPORTED - png_size_t current_text_size; /* current size of text input data */ - png_size_t current_text_left; /* how much text left to read in input */ - png_charp current_text; /* current text chunk buffer */ - png_charp current_text_ptr; /* current location in current_text */ -# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */ - -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ +#endif /* PROGRESSIVE_READ */ #if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) /* For the Borland special 64K segment handler */ @@ -251,10 +375,6 @@ png_bytep quantize_index; /* index translation for palette files */ #endif -#if defined(PNG_READ_QUANTIZE_SUPPORTED) || defined(PNG_hIST_SUPPORTED) - png_uint_16p hist; /* histogram */ -#endif - #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED png_byte heuristic_method; /* heuristic for row filter selection */ png_byte num_prev_filters; /* number of weights for previous rows */ @@ -265,9 +385,17 @@ png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ #endif + /* Options */ +#ifdef PNG_SET_OPTION_SUPPORTED + png_byte options; /* On/off state (up to 4 options) */ +#endif + +#if PNG_LIBPNG_VER < 10700 +/* To do: remove this from libpng-1.7 */ #ifdef PNG_TIME_RFC1123_SUPPORTED char time_buffer[29]; /* String to hold RFC 1123 time text */ #endif +#endif /* New members added in libpng-1.0.6 */ @@ -275,27 +403,31 @@ #ifdef PNG_USER_CHUNKS_SUPPORTED png_voidp user_chunk_ptr; +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ #endif +#endif -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - int num_chunk_list; - png_bytep chunk_list; +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int unknown_default; /* As PNG_HANDLE_* */ + unsigned int num_chunk_list; /* Number of entries in the list */ + png_bytep chunk_list; /* List of png_byte[5]; the textual chunk name + * followed by a PNG_HANDLE_* byte */ #endif /* New members added in libpng-1.0.3 */ #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED png_byte rgb_to_gray_status; + /* Added in libpng 1.5.5 to record setting of coefficients: */ + png_byte rgb_to_gray_coefficients_set; /* These were changed from png_byte in libpng-1.0.6 */ png_uint_16 rgb_to_gray_red_coeff; png_uint_16 rgb_to_gray_green_coeff; - png_uint_16 rgb_to_gray_blue_coeff; + /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */ #endif /* New member added in libpng-1.0.4 (renamed in 1.0.9) */ -#if defined(PNG_MNG_FEATURES_SUPPORTED) || \ - defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \ - defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED) +#if defined(PNG_MNG_FEATURES_SUPPORTED) /* Changed from png_byte to png_uint_32 at version 1.2.0 */ png_uint_32 mng_features_permitted; #endif @@ -345,21 +477,41 @@ #endif /* New member added in libpng-1.0.25 and 1.2.17 */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - /* Storage for unknown chunk that the library doesn't recognize. */ +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + /* Temporary storage for unknown chunk that the library doesn't recognize, + * used while reading the chunk. + */ png_unknown_chunk unknown_chunk; #endif -/* New members added in libpng-1.2.26 */ +/* New member added in libpng-1.2.26 */ png_size_t old_big_row_buf_size; - png_size_t old_prev_row_size; +#ifdef PNG_READ_SUPPORTED /* New member added in libpng-1.2.30 */ - png_charp chunkdata; /* buffer for reading chunk data */ + png_bytep read_buffer; /* buffer for reading chunk data */ + png_alloc_size_t read_buffer_size; /* current size of the buffer */ +#endif +#ifdef PNG_SEQUENTIAL_READ_SUPPORTED + uInt IDAT_read_size; /* limit on read buffer size for IDAT */ +#endif #ifdef PNG_IO_STATE_SUPPORTED /* New member added in libpng-1.4.0 */ png_uint_32 io_state; #endif + +/* New member added in libpng-1.5.6 */ + png_bytep big_prev_row; + +/* New member added in libpng-1.5.7 */ + void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row); + +#ifdef PNG_READ_SUPPORTED +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + png_colorspace colorspace; +#endif +#endif }; #endif /* PNGSTRUCT_H */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngtest.c --- a/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngtest.c Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngtest.c Fri Apr 17 10:24:46 2015 -0700 @@ -29,8 +29,8 @@ * However, the following notice accompanied the original version of this * file and, per its terms, should not be removed: * - * Last changed in libpng 1.5.4 [July 7, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -61,16 +61,50 @@ #define _POSIX_SOURCE 1 -#include "zlib.h" +#include +#include +#include + +/* Defined so I can write to a file on gui/windowing platforms */ +/* #define STDERR stderr */ +#define STDERR stdout /* For DOS */ + #include "png.h" + +/* Known chunks that exist in pngtest.png must be supported or pngtest will fail + * simply as a result of re-ordering them. This may be fixed in 1.7 + * + * pngtest allocates a single row buffer for each row and overwrites it, + * therefore if the write side doesn't support the writing of interlaced images + * nothing can be done for an interlaced image (and the code below will fail + * horribly trying to write extra data after writing garbage). + */ +#if defined PNG_READ_SUPPORTED && /* else nothing can be done */\ + defined PNG_READ_bKGD_SUPPORTED &&\ + defined PNG_READ_cHRM_SUPPORTED &&\ + defined PNG_READ_gAMA_SUPPORTED &&\ + defined PNG_READ_oFFs_SUPPORTED &&\ + defined PNG_READ_pCAL_SUPPORTED &&\ + defined PNG_READ_pHYs_SUPPORTED &&\ + defined PNG_READ_sBIT_SUPPORTED &&\ + defined PNG_READ_sCAL_SUPPORTED &&\ + defined PNG_READ_sRGB_SUPPORTED &&\ + defined PNG_READ_tEXt_SUPPORTED &&\ + defined PNG_READ_tIME_SUPPORTED &&\ + defined PNG_READ_zTXt_SUPPORTED &&\ + defined PNG_WRITE_INTERLACING_SUPPORTED + +#ifdef PNG_ZLIB_HEADER +# include PNG_ZLIB_HEADER /* defined by pnglibconf.h from 1.7 */ +#else +# include "zlib.h" +#endif + /* Copied from pngpriv.h but only used in error messages below. */ #ifndef PNG_ZBUF_SIZE # define PNG_ZBUF_SIZE 8192 #endif -# include -# include -# include -# define FCLOSE(file) fclose(file) +#define FCLOSE(file) fclose(file) #ifndef PNG_STDIO_SUPPORTED typedef FILE * png_FILE_p; @@ -95,17 +129,6 @@ # define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ #endif -/* The code uses memcmp and memcpy on large objects (typically row pointers) so - * it is necessary to do soemthing special on certain architectures, note that - * the actual support for this was effectively removed in 1.4, so only the - * memory remains in this program: - */ -#define CVT_PTR(ptr) (ptr) -#define CVT_PTR_NOCHECK(ptr) (ptr) -#define png_memcmp memcmp -#define png_memcpy memcpy -#define png_memset memset - /* Turn on CPU timing #define PNGTEST_TIMING */ @@ -126,30 +149,34 @@ #endif static int verbose = 0; - -int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname)); - -#ifdef __TURBOC__ -#include -#endif - -/* Defined so I can write to a file on gui/windowing platforms */ -/* #define STDERR stderr */ -#define STDERR stdout /* For DOS */ +static int strict = 0; +static int relaxed = 0; +static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */ +static int error_count = 0; /* count calls to png_error */ +static int warning_count = 0; /* count calls to png_warning */ /* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ #ifndef png_jmpbuf # define png_jmpbuf(png_ptr) png_ptr->jmpbuf #endif +/* Defines for unknown chunk handling if required. */ +#ifndef PNG_HANDLE_CHUNK_ALWAYS +# define PNG_HANDLE_CHUNK_ALWAYS 3 +#endif +#ifndef PNG_HANDLE_CHUNK_IF_SAFE +# define PNG_HANDLE_CHUNK_IF_SAFE 2 +#endif + +/* Utility to save typing/errors, the argument must be a name */ +#define MEMZERO(var) ((void)memset(&var, 0, sizeof var)) + /* Example of using row callbacks to make a simple progress meter */ static int status_pass = 1; static int status_dots_requested = 0; static int status_dots = 1; -void PNGCBAPI -read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); -void PNGCBAPI +static void PNGCBAPI read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) { if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) @@ -173,9 +200,8 @@ fprintf(stdout, "r"); } -void PNGCBAPI -write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); -void PNGCBAPI +#ifdef PNG_WRITE_SUPPORTED +static void PNGCBAPI write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) { if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) @@ -183,6 +209,7 @@ fprintf(stdout, "w"); } +#endif #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED @@ -191,9 +218,7 @@ * 5 in case illegal filter values are present.) */ static png_uint_32 filters_used[256]; -void PNGCBAPI -count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data); -void PNGCBAPI +static void PNGCBAPI count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) { if (png_ptr != NULL && row_info != NULL) @@ -208,9 +233,7 @@ static png_uint_32 zero_samples; -void PNGCBAPI -count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data); -void PNGCBAPI +static void PNGCBAPI count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) { png_bytep dp = data; @@ -288,7 +311,8 @@ png_uint_32 n, nstop; int channel; int color_channels = row_info->channels; - if (row_info->color_type > 3)color_channels--; + if (row_info->color_type > 3) + color_channels--; for (n = 0, nstop=row_info->width; nfile_name != NULL) + name = test->file_name; - else - fprintf(STDERR, "%s: libpng warning: %s\n", test, message); + fprintf(STDERR, "%s: libpng warning: %s\n", name, message); } /* This is the default error handling function. Note that replacements for @@ -566,12 +483,14 @@ static void PNGCBAPI pngtest_error(png_structp png_ptr, png_const_charp message) { + ++error_count; + pngtest_warning(png_ptr, message); /* We can return because png_error calls the default handler, which is * actually OK in this case. */ } -#endif /* !PNG_STDIO_SUPPORTED */ + /* END of code to validate stdio-free compilation */ /* START of code to validate memory allocation and deallocation */ @@ -590,9 +509,9 @@ { png_alloc_size_t size; png_voidp pointer; - struct memory_information FAR *next; + struct memory_information *next; } memory_information; -typedef memory_information FAR *memory_infop; +typedef memory_information *memory_infop; static memory_infop pinformation = NULL; static int current_allocation = 0; @@ -622,7 +541,7 @@ memory_infop pinfo; png_set_mem_fn(png_ptr, NULL, NULL, NULL); pinfo = (memory_infop)png_malloc(png_ptr, - png_sizeof(*pinfo)); + (sizeof *pinfo)); pinfo->size = size; current_allocation += size; total_allocation += size; @@ -648,9 +567,9 @@ pinfo->next = pinformation; pinformation = pinfo; /* Make sure the caller isn't assuming zeroed memory. */ - png_memset(pinfo->pointer, 0xdd, pinfo->size); + memset(pinfo->pointer, 0xdd, pinfo->size); - if (verbose) + if (verbose != 0) printf("png_malloc %lu bytes at %p\n", (unsigned long)size, pinfo->pointer); @@ -675,7 +594,7 @@ /* Unlink the element from the list. */ { - memory_infop FAR *ppinfo = &pinformation; + memory_infop *ppinfo = &pinformation; for (;;) { @@ -689,15 +608,16 @@ fprintf(STDERR, "Duplicate free of memory\n"); /* We must free the list element too, but first kill the memory that is to be freed. */ - png_memset(ptr, 0x55, pinfo->size); - png_free_default(png_ptr, pinfo); + memset(ptr, 0x55, pinfo->size); + if (pinfo != NULL) + free(pinfo); pinfo = NULL; break; } if (pinfo->next == NULL) { - fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); + fprintf(STDERR, "Pointer %p not found\n", ptr); break; } @@ -706,35 +626,84 @@ } /* Finally free the data. */ - if (verbose) + if (verbose != 0) printf("Freeing %p\n", ptr); - png_free_default(png_ptr, ptr); + if (ptr != NULL) + free(ptr); ptr = NULL; } -#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ +#endif /* USER_MEM && DEBUG */ /* END of code to test memory allocation/deallocation */ +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED /* Demonstration of user chunk support of the sTER and vpAg chunks */ -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED /* (sTER is a public chunk not yet known by libpng. vpAg is a private chunk used in ImageMagick to store "virtual page" size). */ -static png_uint_32 user_chunk_data[4]; +static struct user_chunk_data +{ + png_const_infop info_ptr; + png_uint_32 vpAg_width, vpAg_height; + png_byte vpAg_units; + png_byte sTER_mode; + int location[2]; +} +user_chunk_data; + +/* Used for location and order; zero means nothing. */ +#define have_sTER 0x01 +#define have_vpAg 0x02 +#define before_PLTE 0x10 +#define before_IDAT 0x20 +#define after_IDAT 0x40 + +static void +init_callback_info(png_const_infop info_ptr) +{ + MEMZERO(user_chunk_data); + user_chunk_data.info_ptr = info_ptr; +} + +static int +set_location(png_structp png_ptr, struct user_chunk_data *data, int what) +{ + int location; - /* 0: sTER mode + 1 - * 1: vpAg width - * 2: vpAg height - * 3: vpAg units - */ + if ((data->location[0] & what) != 0 || (data->location[1] & what) != 0) + return 0; /* already have one of these */ + + /* Find where we are (the code below zeroes info_ptr to indicate that the + * chunks before the first IDAT have been read.) + */ + if (data->info_ptr == NULL) /* after IDAT */ + location = what | after_IDAT; + + else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE) != 0) + location = what | before_IDAT; + + else + location = what | before_PLTE; -static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr, - png_unknown_chunkp chunk) + if (data->location[0] == 0) + data->location[0] = location; + + else + data->location[1] = location; + + return 1; /* handled */ +} + +static int PNGCBAPI +read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk) { - png_uint_32 - *my_user_chunk_data; + struct user_chunk_data *my_user_chunk_data = + (struct user_chunk_data*)png_get_user_chunk_ptr(png_ptr); + + if (my_user_chunk_data == NULL) + png_error(png_ptr, "lost user chunk pointer"); /* Return one of the following: * return (-n); chunk had an error @@ -759,9 +728,14 @@ if (chunk->data[0] != 0 && chunk->data[0] != 1) return (-1); /* Invalid mode */ - my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); - my_user_chunk_data[0]=chunk->data[0]+1; - return (1); + if (set_location(png_ptr, my_user_chunk_data, have_sTER) != 0) + { + my_user_chunk_data->sTER_mode=chunk->data[0]; + return (1); + } + + else + return (0); /* duplicate sTER - give it to libpng */ } if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ @@ -773,30 +747,126 @@ if (chunk->size != 9) return (-1); /* Error return */ - my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); + if (set_location(png_ptr, my_user_chunk_data, have_vpAg) == 0) + return (0); /* duplicate vpAg */ - my_user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data); - my_user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4); - my_user_chunk_data[3]=(png_uint_32)chunk->data[8]; + my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data); + my_user_chunk_data->vpAg_height = png_get_uint_31(png_ptr, chunk->data + 4); + my_user_chunk_data->vpAg_units = chunk->data[8]; return (1); +} +#ifdef PNG_WRITE_SUPPORTED +static void +write_sTER_chunk(png_structp write_ptr) +{ + png_byte sTER[5] = {115, 84, 69, 82, '\0'}; + + if (verbose != 0) + fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode); + + png_write_chunk(write_ptr, sTER, &user_chunk_data.sTER_mode, 1); } + +static void +write_vpAg_chunk(png_structp write_ptr) +{ + png_byte vpAg[5] = {118, 112, 65, 103, '\0'}; + + png_byte vpag_chunk_data[9]; + + if (verbose != 0) + fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n", + (unsigned long)user_chunk_data.vpAg_width, + (unsigned long)user_chunk_data.vpAg_height, + user_chunk_data.vpAg_units); + + png_save_uint_32(vpag_chunk_data, user_chunk_data.vpAg_width); + png_save_uint_32(vpag_chunk_data + 4, user_chunk_data.vpAg_height); + vpag_chunk_data[8] = user_chunk_data.vpAg_units; + png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9); +} + +static void +write_chunks(png_structp write_ptr, int location) +{ + int i; + + /* Notice that this preserves the original chunk order, however chunks + * intercepted by the callback will be written *after* chunks passed to + * libpng. This will actually reverse a pair of sTER chunks or a pair of + * vpAg chunks, resulting in an error later. This is not worth worrying + * about - the chunks should not be duplicated! + */ + for (i=0; i<2; ++i) + { + if (user_chunk_data.location[i] == (location | have_sTER)) + write_sTER_chunk(write_ptr); + + else if (user_chunk_data.location[i] == (location | have_vpAg)) + write_vpAg_chunk(write_ptr); + } +} +#endif /* WRITE */ +#else /* !READ_USER_CHUNKS */ +# define write_chunks(pp,loc) ((void)0) #endif /* END of code to demonstrate user chunk support */ +/* START of code to check that libpng has the required text support; this only + * checks for the write support because if read support is missing the chunk + * will simply not be reported back to pngtest. + */ +#ifdef PNG_TEXT_SUPPORTED +static void +pngtest_check_text_support(png_const_structp png_ptr, png_textp text_ptr, + int num_text) +{ + while (num_text > 0) + { + switch (text_ptr[--num_text].compression) + { + case PNG_TEXT_COMPRESSION_NONE: + break; + + case PNG_TEXT_COMPRESSION_zTXt: +# ifndef PNG_WRITE_zTXt_SUPPORTED + ++unsupported_chunks; +# endif + break; + + case PNG_ITXT_COMPRESSION_NONE: + case PNG_ITXT_COMPRESSION_zTXt: +# ifndef PNG_WRITE_iTXt_SUPPORTED + ++unsupported_chunks; +# endif + break; + + default: + /* This is an error */ + png_error(png_ptr, "invalid text chunk compression field"); + break; + } + } +} +#endif +/* END of code to check that libpng has the required text support */ + /* Test one file */ -int +static int test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) { static png_FILE_p fpin; static png_FILE_p fpout; /* "static" prevents setjmp corruption */ + pngtest_error_parameters error_parameters; png_structp read_ptr; png_infop read_info_ptr, end_info_ptr; #ifdef PNG_WRITE_SUPPORTED png_structp write_ptr; png_infop write_info_ptr; png_infop write_end_info_ptr; + int interlace_preserved = 1; #else png_structp write_ptr = NULL; png_infop write_info_ptr = NULL; @@ -805,17 +875,11 @@ png_bytep row_buf; png_uint_32 y; png_uint_32 width, height; - int num_pass, pass; + int num_pass = 1, pass; int bit_depth, color_type; -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf tmp_jmpbuf; -#endif -#endif - - char inbuf[256], outbuf[256]; row_buf = NULL; + error_parameters.file_name = inname; if ((fpin = fopen(inname, "rb")) == NULL) { @@ -839,20 +903,9 @@ read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif -#ifndef PNG_STDIO_SUPPORTED - png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, - pngtest_warning); -#endif + png_set_error_fn(read_ptr, &error_parameters, pngtest_error, + pngtest_warning); -#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED - user_chunk_data[0] = 0; - user_chunk_data[1] = 0; - user_chunk_data[2] = 0; - user_chunk_data[3] = 0; - png_set_read_user_chunk_fn(read_ptr, user_chunk_data, - read_user_chunk_callback); - -#endif #ifdef PNG_WRITE_SUPPORTED #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG write_ptr = @@ -862,10 +915,8 @@ write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif -#ifndef PNG_STDIO_SUPPORTED - png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, - pngtest_warning); -#endif + png_set_error_fn(write_ptr, &error_parameters, pngtest_error, + pngtest_warning); #endif pngtest_debug("Allocating read_info, write_info and end_info structures"); read_info_ptr = png_create_info_struct(read_ptr); @@ -875,13 +926,15 @@ write_end_info_ptr = png_create_info_struct(write_ptr); #endif +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + init_callback_info(read_info_ptr); + png_set_read_user_chunk_fn(read_ptr, &user_chunk_data, + read_user_chunk_callback); +#endif + #ifdef PNG_SETJMP_SUPPORTED pngtest_debug("Setting jmpbuf for read struct"); -#ifdef USE_FAR_KEYWORD - if (setjmp(tmp_jmpbuf)) -#else if (setjmp(png_jmpbuf(read_ptr))) -#endif { fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); png_free(read_ptr, row_buf); @@ -895,18 +948,11 @@ FCLOSE(fpout); return (1); } -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(read_ptr), tmp_jmpbuf, png_sizeof(jmp_buf)); -#endif #ifdef PNG_WRITE_SUPPORTED pngtest_debug("Setting jmpbuf for write struct"); -#ifdef USE_FAR_KEYWORD - if (setjmp(tmp_jmpbuf)) -#else if (setjmp(png_jmpbuf(write_ptr))) -#endif { fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); @@ -918,13 +964,35 @@ FCLOSE(fpout); return (1); } - -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(write_ptr), tmp_jmpbuf, png_sizeof(jmp_buf)); #endif #endif + + if (strict != 0) + { + /* Treat png_benign_error() as errors on read */ + png_set_benign_errors(read_ptr, 0); + +#ifdef PNG_WRITE_SUPPORTED + /* Treat them as errors on write */ + png_set_benign_errors(write_ptr, 0); #endif + /* if strict is not set, then app warnings and errors are treated as + * warnings in release builds, but not in unstable builds; this can be + * changed with '--relaxed'. + */ + } + + else if (relaxed != 0) + { + /* Allow application (pngtest) errors and warnings to pass */ + png_set_benign_errors(read_ptr, 1); + +#ifdef PNG_WRITE_SUPPORTED + png_set_benign_errors(write_ptr, 1); +#endif + } + pngtest_debug("Initializing input and output streams"); #ifdef PNG_STDIO_SUPPORTED png_init_io(read_ptr, fpin); @@ -943,14 +1011,6 @@ # endif #endif -#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED - /* Normally one would use Z_DEFAULT_STRATEGY for text compression. - * This is here just to make pngtest replicate the results from libpng - * versions prior to 1.5.4, and to test this new API. - */ - png_set_text_compression_strategy(write_ptr, Z_FILTERED); -#endif - if (status_dots_requested == 1) { #ifdef PNG_WRITE_SUPPORTED @@ -982,36 +1042,65 @@ png_set_write_user_transform_fn(write_ptr, count_zero_samples); #endif -#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_HANDLE_CHUNK_ALWAYS -# define PNG_HANDLE_CHUNK_ALWAYS 3 -# endif +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + /* Preserve all the unknown chunks, if possible. If this is disabled then, + * even if the png_{get,set}_unknown_chunks stuff is enabled, we can't use + * libpng to *save* the unknown chunks on read (because we can't switch the + * save option on!) + * + * Notice that if SET_UNKNOWN_CHUNKS is *not* supported read will discard all + * unknown chunks and write will write them all. + */ +#ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED -# ifndef PNG_HANDLE_CHUNK_IF_SAFE -# define PNG_HANDLE_CHUNK_IF_SAFE 2 -# endif - png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, + png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); #endif +#endif pngtest_debug("Reading info struct"); png_read_info(read_ptr, read_info_ptr); +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED + /* This is a bit of a hack; there is no obvious way in the callback function + * to determine that the chunks before the first IDAT have been read, so + * remove the info_ptr (which is only used to determine position relative to + * PLTE) here to indicate that we are after the IDAT. + */ + user_chunk_data.info_ptr = NULL; +#endif + pngtest_debug("Transferring info struct"); { int interlace_type, compression_type, filter_type; if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, - &color_type, &interlace_type, &compression_type, &filter_type)) + &color_type, &interlace_type, &compression_type, &filter_type) != 0) { png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, -#ifdef PNG_WRITE_INTERLACING_SUPPORTED color_type, interlace_type, compression_type, filter_type); -#else - color_type, PNG_INTERLACE_NONE, compression_type, filter_type); +#ifndef PNG_READ_INTERLACING_SUPPORTED + /* num_pass will not be set below, set it here if the image is + * interlaced: what happens is that write interlacing is *not* turned + * on an the partial interlaced rows are written directly. + */ + switch (interlace_type) + { + case PNG_INTERLACE_NONE: + num_pass = 1; + break; + + case PNG_INTERLACE_ADAM7: + num_pass = 7; + break; + + default: + png_error(read_ptr, "invalid interlace type"); + /*NOT REACHED*/ + } #endif } } @@ -1022,7 +1111,7 @@ blue_y; if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, - &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) + &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0) { png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); @@ -1033,7 +1122,7 @@ { png_fixed_point gamma; - if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) + if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma) != 0) png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); } #endif @@ -1045,7 +1134,7 @@ blue_y; if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, - &red_y, &green_x, &green_y, &blue_x, &blue_y)) + &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0) { png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y); @@ -1056,7 +1145,7 @@ { double gamma; - if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) + if (png_get_gAMA(read_ptr, read_info_ptr, &gamma) != 0) png_set_gAMA(write_ptr, write_info_ptr, gamma); } #endif @@ -1070,7 +1159,7 @@ int compression_type; if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, - &profile, &proflen)) + &profile, &proflen) != 0) { png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, profile, proflen); @@ -1081,7 +1170,7 @@ { int intent; - if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) + if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0) png_set_sRGB(write_ptr, write_info_ptr, intent); } #endif @@ -1089,14 +1178,14 @@ png_colorp palette; int num_palette; - if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) + if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0) png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); } #ifdef PNG_bKGD_SUPPORTED { png_color_16p background; - if (png_get_bKGD(read_ptr, read_info_ptr, &background)) + if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0) { png_set_bKGD(write_ptr, write_info_ptr, background); } @@ -1106,7 +1195,7 @@ { png_uint_16p hist; - if (png_get_hIST(read_ptr, read_info_ptr, &hist)) + if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0) png_set_hIST(write_ptr, write_info_ptr, hist); } #endif @@ -1116,7 +1205,7 @@ int unit_type; if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, - &unit_type)) + &unit_type) != 0) { png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); } @@ -1130,7 +1219,7 @@ int type, nparams; if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, - &nparams, &units, ¶ms)) + &nparams, &units, ¶ms) != 0) { png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, nparams, units, params); @@ -1142,7 +1231,8 @@ png_uint_32 res_x, res_y; int unit_type; - if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) + if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, + &unit_type) != 0) png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); } #endif @@ -1150,18 +1240,19 @@ { png_color_8p sig_bit; - if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) + if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0) png_set_sBIT(write_ptr, write_info_ptr, sig_bit); } #endif #ifdef PNG_sCAL_SUPPORTED -#ifdef PNG_FLOATING_POINT_SUPPORTED +#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ + defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) { int unit; double scal_width, scal_height; if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, - &scal_height)) + &scal_height) != 0) { png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); } @@ -1173,7 +1264,7 @@ png_charp scal_width, scal_height; if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, - &scal_height)) + &scal_height) != 0) { png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height); @@ -1190,6 +1281,21 @@ if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) { pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text); + + pngtest_check_text_support(read_ptr, text_ptr, num_text); + + if (verbose != 0) + { + int i; + + printf("\n"); + for (i=0; i 0) { pngtest_debug1("Handling %d iTXt/tEXt/zTXt chunks", num_text); + + pngtest_check_text_support(read_ptr, text_ptr, num_text); + + if (verbose != 0) + { + int i; + + printf("\n"); + for (i=0; i 0) + { + /* We don't really expect to get here because of the setjmp handling + * above, but this is safe. + */ + fprintf(STDERR, "\n %s: %d libpng errors found (%d warnings)", + inname, error_count, warning_count); + + if (strict != 0) + return (1); + } + +# ifdef PNG_WRITE_SUPPORTED + /* If there we no write support nothing was written! */ + else if (unsupported_chunks > 0) + { + fprintf(STDERR, "\n %s: unsupported chunks (%d)%s", + inname, unsupported_chunks, strict ? ": IGNORED --strict!" : ""); + } +# endif + + else if (warning_count > 0) + { + fprintf(STDERR, "\n %s: %d libpng warnings found", + inname, warning_count); + + if (strict != 0) + return (1); + } + pngtest_debug("Opening files for comparison"); if ((fpin = fopen(inname, "rb")) == NULL) { @@ -1480,61 +1629,84 @@ return (1); } - for (;;) +#ifdef PNG_WRITE_SUPPORTED /* else nothing was written */ + if (interlace_preserved != 0) /* else the files will be changed */ { - png_size_t num_in, num_out; + for (;;) + { + static int wrote_question = 0; + png_size_t num_in, num_out; + char inbuf[256], outbuf[256]; - num_in = fread(inbuf, 1, 1, fpin); - num_out = fread(outbuf, 1, 1, fpout); + num_in = fread(inbuf, 1, sizeof inbuf, fpin); + num_out = fread(outbuf, 1, sizeof outbuf, fpout); - if (num_in != num_out) - { - fprintf(STDERR, "\nFiles %s and %s are of a different size\n", - inname, outname); + if (num_in != num_out) + { + fprintf(STDERR, "\nFiles %s and %s are of a different size\n", + inname, outname); - if (wrote_question == 0) - { - fprintf(STDERR, + if (wrote_question == 0 && unsupported_chunks == 0) + { + fprintf(STDERR, " Was %s written with the same maximum IDAT chunk size (%d bytes),", - inname, PNG_ZBUF_SIZE); - fprintf(STDERR, - "\n filtering heuristic (libpng default), compression"); - fprintf(STDERR, - " level (zlib default),\n and zlib version (%s)?\n\n", - ZLIB_VERSION); - wrote_question = 1; + inname, PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question = 1; + } + + FCLOSE(fpin); + FCLOSE(fpout); + + if (strict != 0 && unsupported_chunks == 0) + return (1); + + else + return (0); } - FCLOSE(fpin); - FCLOSE(fpout); - return (0); - } + if (num_in == 0) + break; - if (!num_in) - break; - - if (png_memcmp(inbuf, outbuf, num_in)) - { - fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); - - if (wrote_question == 0) + if (memcmp(inbuf, outbuf, num_in)) { - fprintf(STDERR, + fprintf(STDERR, "\nFiles %s and %s are different\n", inname, + outname); + + if (wrote_question == 0 && unsupported_chunks == 0) + { + fprintf(STDERR, " Was %s written with the same maximum IDAT chunk size (%d bytes),", - inname, PNG_ZBUF_SIZE); - fprintf(STDERR, - "\n filtering heuristic (libpng default), compression"); - fprintf(STDERR, - " level (zlib default),\n and zlib version (%s)?\n\n", - ZLIB_VERSION); - wrote_question = 1; + inname, PNG_ZBUF_SIZE); + fprintf(STDERR, + "\n filtering heuristic (libpng default), compression"); + fprintf(STDERR, + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); + wrote_question = 1; + } + + FCLOSE(fpin); + FCLOSE(fpout); + + /* NOTE: the unsupported_chunks escape is permitted here because + * unsupported text chunk compression will result in the compression + * mode being changed (to NONE) yet, in the test case, the result + * can be exactly the same size! + */ + if (strict != 0 && unsupported_chunks == 0) + return (1); + + else + return (0); } - - FCLOSE(fpin); - FCLOSE(fpout); - return (0); } } +#endif /* WRITE */ FCLOSE(fpin); FCLOSE(fpout); @@ -1614,6 +1786,24 @@ inname = argv[2]; } + else if (strcmp(argv[1], "--strict") == 0) + { + status_dots_requested = 0; + verbose = 1; + inname = argv[2]; + strict++; + relaxed = 0; + } + + else if (strcmp(argv[1], "--relaxed") == 0) + { + status_dots_requested = 0; + verbose = 1; + inname = argv[2]; + strict = 0; + relaxed++; + } + else { inname = argv[1]; @@ -1621,10 +1811,11 @@ } } - if (!multiple && argc == 3 + verbose) + if (multiple == 0 && argc == 3 + verbose) outname = argv[2 + verbose]; - if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2)) + if ((multiple == 0 && argc > 3 + verbose) || + (multiple != 0 && argc < 2)) { fprintf(STDERR, "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", @@ -1636,7 +1827,7 @@ exit(1); } - if (multiple) + if (multiple != 0) { int i; #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG @@ -1646,6 +1837,9 @@ { int kerror; fprintf(STDERR, "\n Testing %s:", argv[i]); +#if PNG_DEBUG > 0 + fprintf(STDERR, "\n"); +#endif kerror = test_one_file(argv[i], outname); if (kerror == 0) { @@ -1660,7 +1854,7 @@ #endif #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED for (k = 0; k<256; k++) - if (filters_used[k]) + if (filters_used[k] != 0) fprintf(STDERR, " Filter %d was used %lu times\n", k, (unsigned long)filters_used[k]); #endif @@ -1669,7 +1863,7 @@ fprintf(STDERR, " tIME = %s\n", tIME_string); tIME_chunk_present = 0; -#endif /* PNG_TIME_RFC1123_SUPPORTED */ +#endif /* TIME_RFC1123 */ } else @@ -1691,9 +1885,9 @@ while (pinfo != NULL) { - fprintf(STDERR, " %lu bytes at %x\n", + fprintf(STDERR, " %lu bytes at %p\n", (unsigned long)pinfo->size, - (unsigned int)pinfo->pointer); + pinfo->pointer); pinfo = pinfo->next; } } @@ -1727,7 +1921,12 @@ status_dots_requested = 0; if (i == 0 || verbose == 1 || ierror != 0) + { fprintf(STDERR, "\n Testing %s:", inname); +#if PNG_DEBUG > 0 + fprintf(STDERR, "\n"); +#endif + } kerror = test_one_file(inname, outname); @@ -1746,21 +1945,26 @@ #endif #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED for (k = 0; k<256; k++) - if (filters_used[k]) + if (filters_used[k] != 0) fprintf(STDERR, " Filter %d was used %lu times\n", k, (unsigned long)filters_used[k]); #endif #ifdef PNG_TIME_RFC1123_SUPPORTED if (tIME_chunk_present != 0) fprintf(STDERR, " tIME = %s\n", tIME_string); -#endif /* PNG_TIME_RFC1123_SUPPORTED */ +#endif /* TIME_RFC1123 */ } } else { if (verbose == 0 && i != 2) + { fprintf(STDERR, "\n Testing %s:", inname); +#if PNG_DEBUG > 0 + fprintf(STDERR, "\n"); +#endif + } fprintf(STDERR, " FAIL\n"); ierror += kerror; @@ -1779,8 +1983,8 @@ while (pinfo != NULL) { - fprintf(STDERR, " %lu bytes at %x\n", - (unsigned long)pinfo->size, (unsigned int)pinfo->pointer); + fprintf(STDERR, " %lu bytes at %p\n", + (unsigned long)pinfo->size, pinfo->pointer); pinfo = pinfo->next; } } @@ -1820,6 +2024,16 @@ return (int)(ierror != 0); } +#else +int +main(void) +{ + fprintf(STDERR, + " test ignored because libpng was not built with read support\n"); + /* And skip this test */ + return PNG_LIBPNG_VER < 10600 ? 0 : 77; +} +#endif /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_5_4 Your_png_h_is_not_version_1_5_4; +typedef png_libpng_version_1_6_16 Your_png_h_is_not_version_1_6_16; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c --- a/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngtrans.c Fri Apr 17 10:24:46 2015 -0700 @@ -29,8 +29,8 @@ * However, the following notice accompanied the original version of this * file and, per its terms, should not be removed: * - * Last changed in libpng 1.5.4 [July 7, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -46,7 +46,7 @@ #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Turn on BGR-to-RGB mapping */ void PNGAPI -png_set_bgr(png_structp png_ptr) +png_set_bgr(png_structrp png_ptr) { png_debug(1, "in png_set_bgr"); @@ -60,7 +60,7 @@ #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Turn on 16 bit byte swapping */ void PNGAPI -png_set_swap(png_structp png_ptr) +png_set_swap(png_structrp png_ptr) { png_debug(1, "in png_set_swap"); @@ -75,7 +75,7 @@ #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) /* Turn on pixel packing */ void PNGAPI -png_set_packing(png_structp png_ptr) +png_set_packing(png_structrp png_ptr) { png_debug(1, "in png_set_packing"); @@ -85,7 +85,9 @@ if (png_ptr->bit_depth < 8) { png_ptr->transformations |= PNG_PACK; - png_ptr->usr_bit_depth = 8; +# ifdef PNG_WRITE_SUPPORTED + png_ptr->usr_bit_depth = 8; +# endif } } #endif @@ -93,7 +95,7 @@ #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) /* Turn on packed pixel swapping */ void PNGAPI -png_set_packswap(png_structp png_ptr) +png_set_packswap(png_structrp png_ptr) { png_debug(1, "in png_set_packswap"); @@ -107,7 +109,7 @@ #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) void PNGAPI -png_set_shift(png_structp png_ptr, png_const_color_8p true_bits) +png_set_shift(png_structrp png_ptr, png_const_color_8p true_bits) { png_debug(1, "in png_set_shift"); @@ -122,11 +124,11 @@ #if defined(PNG_READ_INTERLACING_SUPPORTED) || \ defined(PNG_WRITE_INTERLACING_SUPPORTED) int PNGAPI -png_set_interlace_handling(png_structp png_ptr) +png_set_interlace_handling(png_structrp png_ptr) { png_debug(1, "in png_set_interlace handling"); - if (png_ptr && png_ptr->interlaced) + if (png_ptr != 0 && png_ptr->interlaced != 0) { png_ptr->transformations |= PNG_INTERLACE; return (7); @@ -143,44 +145,91 @@ * that don't like bytes as parameters. */ void PNGAPI -png_set_filler(png_structp png_ptr, png_uint_32 filler, int filler_loc) +png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) { png_debug(1, "in png_set_filler"); if (png_ptr == NULL) return; + /* In libpng 1.6 it is possible to determine whether this is a read or write + * operation and therefore to do more checking here for a valid call. + */ + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + { +# ifdef PNG_READ_FILLER_SUPPORTED + /* On read png_set_filler is always valid, regardless of the base PNG + * format, because other transformations can give a format where the + * filler code can execute (basically an 8 or 16-bit component RGB or G + * format.) + * + * NOTE: usr_channels is not used by the read code! (This has led to + * confusion in the past.) The filler is only used in the read code. + */ + png_ptr->filler = (png_uint_16)filler; +# else + png_app_error(png_ptr, "png_set_filler not supported on read"); + PNG_UNUSED(filler) /* not used in the write case */ + return; +# endif + } + + else /* write */ + { +# ifdef PNG_WRITE_FILLER_SUPPORTED + /* On write the usr_channels parameter must be set correctly at the + * start to record the number of channels in the app-supplied data. + */ + switch (png_ptr->color_type) + { + case PNG_COLOR_TYPE_RGB: + png_ptr->usr_channels = 4; + break; + + case PNG_COLOR_TYPE_GRAY: + if (png_ptr->bit_depth >= 8) + { + png_ptr->usr_channels = 2; + break; + } + + else + { + /* There simply isn't any code in libpng to strip out bits + * from bytes when the components are less than a byte in + * size! + */ + png_app_error(png_ptr, + "png_set_filler is invalid for low bit depth gray output"); + return; + } + + default: + png_app_error(png_ptr, + "png_set_filler: inappropriate color type"); + return; + } +# else + png_app_error(png_ptr, "png_set_filler not supported on write"); + return; +# endif + } + + /* Here on success - libpng supports the operation, set the transformation + * and the flag to say where the filler channel is. + */ png_ptr->transformations |= PNG_FILLER; - png_ptr->filler = (png_uint_16)filler; if (filler_loc == PNG_FILLER_AFTER) png_ptr->flags |= PNG_FLAG_FILLER_AFTER; else png_ptr->flags &= ~PNG_FLAG_FILLER_AFTER; - - /* This should probably go in the "do_read_filler" routine. - * I attempted to do that in libpng-1.0.1a but that caused problems - * so I restored it in libpng-1.0.2a - */ - - if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) - { - png_ptr->usr_channels = 4; - } - - /* Also I added this in libpng-1.0.2a (what happens when we expand - * a less-than-8-bit grayscale to GA?) */ - - if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY && png_ptr->bit_depth >= 8) - { - png_ptr->usr_channels = 2; - } } /* Added to libpng-1.2.7 */ void PNGAPI -png_set_add_alpha(png_structp png_ptr, png_uint_32 filler, int filler_loc) +png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc) { png_debug(1, "in png_set_add_alpha"); @@ -188,7 +237,9 @@ return; png_set_filler(png_ptr, filler, filler_loc); - png_ptr->transformations |= PNG_ADD_ALPHA; + /* The above may fail to do anything. */ + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_ptr->transformations |= PNG_ADD_ALPHA; } #endif @@ -196,7 +247,7 @@ #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) void PNGAPI -png_set_swap_alpha(png_structp png_ptr) +png_set_swap_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_swap_alpha"); @@ -210,7 +261,7 @@ #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) void PNGAPI -png_set_invert_alpha(png_structp png_ptr) +png_set_invert_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_invert_alpha"); @@ -223,7 +274,7 @@ #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) void PNGAPI -png_set_invert_mono(png_structp png_ptr) +png_set_invert_mono(png_structrp png_ptr) { png_debug(1, "in png_set_invert_mono"); @@ -304,9 +355,16 @@ for (i = 0; i < istop; i++, rp += 2) { +#ifdef PNG_BUILTIN_BSWAP16_SUPPORTED + /* Feature added to libpng-1.6.11 for testing purposes, not + * enabled by default. + */ + *(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp); +#else png_byte t = *rp; *rp = *(rp + 1); *(rp + 1) = t; +#endif } } } @@ -448,7 +506,7 @@ *rp = table[*rp]; } } -#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ +#endif /* PACKSWAP || WRITE_PACKSWAP */ #if defined(PNG_WRITE_FILLER_SUPPORTED) || \ defined(PNG_READ_STRIP_ALPHA_SUPPORTED) @@ -480,7 +538,7 @@ { if (row_info->bit_depth == 8) { - if (at_start) /* Skip initial filler */ + if (at_start != 0) /* Skip initial filler */ ++sp; else /* Skip initial channel and, for sp, the filler */ sp += 2, ++dp; @@ -494,7 +552,7 @@ else if (row_info->bit_depth == 16) { - if (at_start) /* Skip initial filler */ + if (at_start != 0) /* Skip initial filler */ sp += 2; else /* Skip initial channel and, for sp, the filler */ sp += 4, dp += 2; @@ -520,7 +578,7 @@ { if (row_info->bit_depth == 8) { - if (at_start) /* Skip initial filler */ + if (at_start != 0) /* Skip initial filler */ ++sp; else /* Skip initial channels and, for sp, the filler */ sp += 4, dp += 3; @@ -534,7 +592,7 @@ else if (row_info->bit_depth == 16) { - if (at_start) /* Skip initial filler */ + if (at_start != 0) /* Skip initial filler */ sp += 2; else /* Skip initial channels and, for sp, the filler */ sp += 8, dp += 6; @@ -575,7 +633,7 @@ { png_debug(1, "in png_do_bgr"); - if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { png_uint_32 row_width = row_info->width; if (row_info->bit_depth == 8) @@ -645,19 +703,133 @@ #endif } } -#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ +#endif /* READ_BGR || WRITE_BGR */ + +#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ + defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) +/* Added at libpng-1.5.10 */ +void /* PRIVATE */ +png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) +{ + if (png_ptr->num_palette < (1 << row_info->bit_depth) && + png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */ + { + /* Calculations moved outside switch in an attempt to stop different + * compiler warnings. 'padding' is in *bits* within the last byte, it is + * an 'int' because pixel_depth becomes an 'int' in the expression below, + * and this calculation is used because it avoids warnings that other + * forms produced on either GCC or MSVC. + */ + int padding = (-row_info->pixel_depth * row_info->width) & 7; + png_bytep rp = png_ptr->row_buf + row_info->rowbytes; + + switch (row_info->bit_depth) + { + case 1: + { + /* in this case, all bytes must be 0 so we don't need + * to unpack the pixels except for the rightmost one. + */ + for (; rp > png_ptr->row_buf; rp--) + { + if (*rp >> padding != 0) + png_ptr->num_palette_max = 1; + padding = 0; + } + + break; + } + + case 2: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 2) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 6) & 0x03); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 4: + { + for (; rp > png_ptr->row_buf; rp--) + { + int i = ((*rp >> padding) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + i = (((*rp >> padding) >> 4) & 0x0f); + + if (i > png_ptr->num_palette_max) + png_ptr->num_palette_max = i; + + padding = 0; + } + + break; + } + + case 8: + { + for (; rp > png_ptr->row_buf; rp--) + { + if (*rp > png_ptr->num_palette_max) + png_ptr->num_palette_max = (int) *rp; + } + + break; + } + + default: + break; + } + } +} +#endif /* CHECK_FOR_INVALID_INDEX */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED void PNGAPI -png_set_user_transform_info(png_structp png_ptr, png_voidp +png_set_user_transform_info(png_structrp png_ptr, png_voidp user_transform_ptr, int user_transform_depth, int user_transform_channels) { png_debug(1, "in png_set_user_transform_info"); if (png_ptr == NULL) return; + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + { + png_app_error(png_ptr, + "info change after png_start_read_image or png_read_update_info"); + return; + } +#endif + png_ptr->user_transform_ptr = user_transform_ptr; png_ptr->user_transform_depth = (png_byte)user_transform_depth; png_ptr->user_transform_channels = (png_byte)user_transform_channels; @@ -671,20 +843,20 @@ */ #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED png_voidp PNGAPI -png_get_user_transform_ptr(png_const_structp png_ptr) +png_get_user_transform_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) return (NULL); - return ((png_voidp)png_ptr->user_transform_ptr); + return png_ptr->user_transform_ptr; } #endif #ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED png_uint_32 PNGAPI -png_get_current_row_number(png_const_structp png_ptr) +png_get_current_row_number(png_const_structrp png_ptr) { - /* See the comments in png.h - this is the sub-image row when reading and + /* See the comments in png.h - this is the sub-image row when reading an * interlaced image. */ if (png_ptr != NULL) @@ -694,13 +866,12 @@ } png_byte PNGAPI -png_get_current_pass_number(png_const_structp png_ptr) +png_get_current_pass_number(png_const_structrp png_ptr) { if (png_ptr != NULL) return png_ptr->pass; return 8; /* invalid */ } -#endif /* PNG_USER_TRANSFORM_INFO_SUPPORTED */ -#endif /* PNG_READ_USER_TRANSFORM_SUPPORTED || - PNG_WRITE_USER_TRANSFORM_SUPPORTED */ -#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ +#endif /* USER_TRANSFORM_INFO */ +#endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */ +#endif /* READ || WRITE */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwio.c --- a/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwio.c Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwio.c Fri Apr 17 10:24:46 2015 -0700 @@ -29,8 +29,8 @@ * However, the following notice accompanied the original version of this * file and, per its terms, should not be removed: * - * Last changed in libpng 1.5.0 [January 6, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -58,11 +58,12 @@ */ void /* PRIVATE */ -png_write_data(png_structp png_ptr, png_const_bytep data, png_size_t length) +png_write_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) { /* NOTE: write_data_fn must not change the buffer! */ if (png_ptr->write_data_fn != NULL ) - (*(png_ptr->write_data_fn))(png_ptr, (png_bytep)data, length); + (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data), + length); else png_error(png_ptr, "Call to NULL write function"); @@ -74,7 +75,6 @@ * write_data function and use it at run time with png_set_write_fn(), rather * than changing the library. */ -#ifndef USE_FAR_KEYWORD void PNGCBAPI png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { @@ -88,64 +88,6 @@ if (check != length) png_error(png_ptr, "Write Error"); } -#else -/* This is the model-independent version. Since the standard I/O library - * can't handle far buffers in the medium and small models, we have to copy - * the data. - */ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -void PNGCBAPI -png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_uint_32 check; - png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ - png_FILE_p io_ptr; - - if (png_ptr == NULL) - return; - - /* Check if data really is near. If so, use usual code. */ - near_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - - if ((png_bytep)near_data == data) - { - check = fwrite(near_data, 1, length, io_ptr); - } - - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t written, remaining, err; - check = 0; - remaining = length; - - do - { - written = MIN(NEAR_BUF_SIZE, remaining); - png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ - err = fwrite(buf, 1, written, io_ptr); - - if (err != written) - break; - - else - check += err; - - data += written; - remaining -= written; - } - while (remaining != 0); - } - - if (check != length) - png_error(png_ptr, "Write Error"); -} - -#endif #endif /* This function is called to output any data pending writing (normally @@ -154,7 +96,7 @@ */ #ifdef PNG_WRITE_FLUSH_SUPPORTED void /* PRIVATE */ -png_flush(png_structp png_ptr) +png_flush(png_structrp png_ptr) { if (png_ptr->output_flush_fn != NULL) (*(png_ptr->output_flush_fn))(png_ptr); @@ -169,7 +111,7 @@ if (png_ptr == NULL) return; - io_ptr = (png_FILE_p)CVT_PTR((png_ptr->io_ptr)); + io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr)); fflush(io_ptr); } # endif @@ -205,7 +147,7 @@ * *FILE structure. */ void PNGAPI -png_set_write_fn(png_structp png_ptr, png_voidp io_ptr, +png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) { if (png_ptr == NULL) @@ -235,8 +177,11 @@ # else png_ptr->output_flush_fn = output_flush_fn; # endif -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ +#else + PNG_UNUSED(output_flush_fn) +#endif /* WRITE_FLUSH */ +#ifdef PNG_READ_SUPPORTED /* It is an error to read while writing a png file */ if (png_ptr->read_data_fn != NULL) { @@ -246,37 +191,6 @@ "Can't set both read_data_fn and write_data_fn in the" " same structure"); } -} - -#ifdef USE_FAR_KEYWORD -# ifdef _MSC_VER -void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) -{ - void *near_ptr; - void FAR *far_ptr; - FP_OFF(near_ptr) = FP_OFF(ptr); - far_ptr = (void FAR *)near_ptr; - - if (check != 0) - if (FP_SEG(ptr) != FP_SEG(far_ptr)) - png_error(png_ptr, "segment lost in conversion"); - - return(near_ptr); +#endif } -# else -void *png_far_to_near(png_structp png_ptr, png_voidp ptr, int check) -{ - void *near_ptr; - void FAR *far_ptr; - near_ptr = (void FAR *)ptr; - far_ptr = (void FAR *)near_ptr; - - if (check != 0) - if (far_ptr != ptr) - png_error(png_ptr, "segment lost in conversion"); - - return(near_ptr); -} -# endif -#endif -#endif /* PNG_WRITE_SUPPORTED */ +#endif /* WRITE */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwrite.c --- a/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwrite.c Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwrite.c Fri Apr 17 10:24:46 2015 -0700 @@ -29,8 +29,8 @@ * However, the following notice accompanied the original version of this * file and, per its terms, should not be removed: * - * Last changed in libpng 1.5.4 [July 7, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -40,9 +40,65 @@ */ #include "pngpriv.h" +#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +# include +#endif #ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED +/* Write out all the unknown chunks for the current given location */ +static void +write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, + unsigned int where) +{ + if (info_ptr->unknown_chunks_num != 0) + { + png_const_unknown_chunkp up; + + png_debug(5, "writing extra chunks"); + + for (up = info_ptr->unknown_chunks; + up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; + ++up) + if ((up->location & where) != 0) + { + /* If per-chunk unknown chunk handling is enabled use it, otherwise + * just write the chunks the application has set. + */ +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + int keep = png_handle_as_unknown(png_ptr, up->name); + + /* NOTE: this code is radically different from the read side in the + * matter of handling an ancillary unknown chunk. In the read side + * the default behavior is to discard it, in the code below the default + * behavior is to write it. Critical chunks are, however, only + * written if explicitly listed or if the default is set to write all + * unknown chunks. + * + * The default handling is also slightly weird - it is not possible to + * stop the writing of all unsafe-to-copy chunks! + * + * TODO: REVIEW: this would seem to be a bug. + */ + if (keep != PNG_HANDLE_CHUNK_NEVER && + ((up->name[3] & 0x20) /* safe-to-copy overrides everything */ || + keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_AS_DEFAULT && + png_ptr->unknown_default == PNG_HANDLE_CHUNK_ALWAYS))) +#endif + { + /* TODO: review, what is wrong with a zero length unknown chunk? */ + if (up->size == 0) + png_warning(png_ptr, "Writing zero-length unknown chunk"); + + png_write_chunk(png_ptr, up->name, up->data, up->size); + } + } + } +} +#endif /* WRITE_UNKNOWN_CHUNKS */ + /* Writes all the PNG information. This is the suggested way to use the * library. If you have a new chunk to add, make a function to write it, * and put it in the correct location here. If you want the chunk written @@ -53,21 +109,21 @@ * them in png_write_end(), and compressing them. */ void PNGAPI -png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) +png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) { png_debug(1, "in png_write_info_before_PLTE"); if (png_ptr == NULL || info_ptr == NULL) return; - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) { /* Write PNG signature */ png_write_sig(png_ptr); #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ - (png_ptr->mng_features_permitted)) + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \ + png_ptr->mng_features_permitted != 0) { png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); png_ptr->mng_features_permitted = 0; @@ -79,75 +135,88 @@ info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, info_ptr->filter_type, #ifdef PNG_WRITE_INTERLACING_SUPPORTED - info_ptr->interlace_type); + info_ptr->interlace_type #else - 0); + 0 #endif + ); + /* The rest of these check to see if the valid field has the appropriate * flag set, and if it does, writes the chunk. + * + * 1.6.0: COLORSPACE support controls the writing of these chunks too, and + * the chunks will be written if the WRITE routine is there and information + * is available in the COLORSPACE. (See png_colorspace_sync_info in png.c + * for where the valid flags get set.) + * + * Under certain circumstances the colorspace can be invalidated without + * syncing the info_struct 'valid' flags; this happens if libpng detects and + * error and calls png_error while the color space is being set, yet the + * application continues writing the PNG. So check the 'invalid' flag here + * too. */ -#ifdef PNG_WRITE_gAMA_SUPPORTED - if (info_ptr->valid & PNG_INFO_gAMA) - png_write_gAMA_fixed(png_ptr, info_ptr->gamma); -#endif -#ifdef PNG_WRITE_sRGB_SUPPORTED - if (info_ptr->valid & PNG_INFO_sRGB) - png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent); +#ifdef PNG_GAMMA_SUPPORTED +# ifdef PNG_WRITE_gAMA_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) != 0 && + (info_ptr->valid & PNG_INFO_gAMA) != 0) + png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); +# endif #endif -#ifdef PNG_WRITE_iCCP_SUPPORTED - if (info_ptr->valid & PNG_INFO_iCCP) - png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE, - (png_charp)info_ptr->iccp_profile, (int)info_ptr->iccp_proflen); -#endif +#ifdef PNG_COLORSPACE_SUPPORTED + /* Write only one of sRGB or an ICC profile. If a profile was supplied + * and it matches one of the known sRGB ones issue a warning. + */ +# ifdef PNG_WRITE_iCCP_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->valid & PNG_INFO_iCCP) != 0) + { +# ifdef PNG_WRITE_sRGB_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sRGB) != 0) + png_app_warning(png_ptr, + "profile matches sRGB but writing iCCP instead"); +# endif + + png_write_iCCP(png_ptr, info_ptr->iccp_name, + info_ptr->iccp_profile); + } +# ifdef PNG_WRITE_sRGB_SUPPORTED + else +# endif +# endif + +# ifdef PNG_WRITE_sRGB_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->valid & PNG_INFO_sRGB) != 0) + png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); +# endif /* WRITE_sRGB */ +#endif /* COLORSPACE */ + #ifdef PNG_WRITE_sBIT_SUPPORTED - if (info_ptr->valid & PNG_INFO_sBIT) + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); #endif -#ifdef PNG_WRITE_cHRM_SUPPORTED - if (info_ptr->valid & PNG_INFO_cHRM) - png_write_cHRM_fixed(png_ptr, - info_ptr->x_white, info_ptr->y_white, - info_ptr->x_red, info_ptr->y_red, - info_ptr->x_green, info_ptr->y_green, - info_ptr->x_blue, info_ptr->y_blue); + +#ifdef PNG_COLORSPACE_SUPPORTED +# ifdef PNG_WRITE_cHRM_SUPPORTED + if ((info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) == 0 && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) != 0 && + (info_ptr->valid & PNG_INFO_cHRM) != 0) + png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); +# endif #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - up++) - { - int keep = png_handle_as_unknown(png_ptr, up->name); + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); +#endif - if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && - !(up->location & PNG_HAVE_PLTE) && - !(up->location & PNG_HAVE_IDAT) && - !(up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - if (up->size == 0) - png_warning(png_ptr, "Writing zero-length unknown chunk"); - - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } -#endif png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; } } void PNGAPI -png_write_info(png_structp png_ptr, png_infop info_ptr) +png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) { #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) int i; @@ -160,19 +229,19 @@ png_write_info_before_PLTE(png_ptr, info_ptr); - if (info_ptr->valid & PNG_INFO_PLTE) + if ((info_ptr->valid & PNG_INFO_PLTE) != 0) png_write_PLTE(png_ptr, info_ptr->palette, (png_uint_32)info_ptr->num_palette); - else if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + else if ((info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) !=0) png_error(png_ptr, "Valid palette required for paletted images"); #ifdef PNG_WRITE_tRNS_SUPPORTED - if (info_ptr->valid & PNG_INFO_tRNS) + if ((info_ptr->valid & PNG_INFO_tRNS) !=0) { #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel (in tRNS) */ - if ((png_ptr->transformations & PNG_INVERT_ALPHA) && + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 && info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { int j; @@ -186,42 +255,42 @@ } #endif #ifdef PNG_WRITE_bKGD_SUPPORTED - if (info_ptr->valid & PNG_INFO_bKGD) + if ((info_ptr->valid & PNG_INFO_bKGD) != 0) png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); #endif #ifdef PNG_WRITE_hIST_SUPPORTED - if (info_ptr->valid & PNG_INFO_hIST) + if ((info_ptr->valid & PNG_INFO_hIST) != 0) png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); #endif #ifdef PNG_WRITE_oFFs_SUPPORTED - if (info_ptr->valid & PNG_INFO_oFFs) + if ((info_ptr->valid & PNG_INFO_oFFs) != 0) png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, info_ptr->offset_unit_type); #endif #ifdef PNG_WRITE_pCAL_SUPPORTED - if (info_ptr->valid & PNG_INFO_pCAL) + if ((info_ptr->valid & PNG_INFO_pCAL) != 0) png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, info_ptr->pcal_units, info_ptr->pcal_params); #endif #ifdef PNG_WRITE_sCAL_SUPPORTED - if (info_ptr->valid & PNG_INFO_sCAL) + if ((info_ptr->valid & PNG_INFO_sCAL) != 0) png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, info_ptr->scal_s_width, info_ptr->scal_s_height); #endif /* sCAL */ #ifdef PNG_WRITE_pHYs_SUPPORTED - if (info_ptr->valid & PNG_INFO_pHYs) + if ((info_ptr->valid & PNG_INFO_pHYs) != 0) png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); #endif /* pHYs */ #ifdef PNG_WRITE_tIME_SUPPORTED - if (info_ptr->valid & PNG_INFO_tIME) + if ((info_ptr->valid & PNG_INFO_tIME) != 0) { png_write_tIME(png_ptr, &(info_ptr->mod_time)); png_ptr->mode |= PNG_WROTE_tIME; @@ -229,7 +298,7 @@ #endif /* tIME */ #ifdef PNG_WRITE_sPLT_SUPPORTED - if (info_ptr->valid & PNG_INFO_sPLT) + if ((info_ptr->valid & PNG_INFO_sPLT) != 0) for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); #endif /* sPLT */ @@ -251,11 +320,14 @@ info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else - png_warning(png_ptr, "Unable to write international text"); + png_warning(png_ptr, "Unable to write international text"); #endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } /* If we want a compressed text chunk */ @@ -264,13 +336,12 @@ #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0, - info_ptr->text[i].compression); + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) @@ -291,29 +362,7 @@ #endif /* tEXt */ #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - up++) - { - int keep = png_handle_as_unknown(png_ptr, up->name); - if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && - (up->location & PNG_HAVE_PLTE) && - !(up->location & PNG_HAVE_IDAT) && - !(up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_PLTE); #endif } @@ -323,16 +372,21 @@ * comments, I suggest writing them here, and compressing them. */ void PNGAPI -png_write_end(png_structp png_ptr, png_infop info_ptr) +png_write_end(png_structrp png_ptr, png_inforp info_ptr) { png_debug(1, "in png_write_end"); if (png_ptr == NULL) return; - if (!(png_ptr->mode & PNG_HAVE_IDAT)) + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) png_error(png_ptr, "No IDATs written into file"); +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + if (png_ptr->num_palette_max > png_ptr->num_palette) + png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); +#endif + /* See if user wants us to write information chunks */ if (info_ptr != NULL) { @@ -341,8 +395,8 @@ #endif #ifdef PNG_WRITE_tIME_SUPPORTED /* Check to see if user has supplied a time chunk */ - if ((info_ptr->valid & PNG_INFO_tIME) && - !(png_ptr->mode & PNG_WROTE_tIME)) + if ((info_ptr->valid & PNG_INFO_tIME) != 0 && + (png_ptr->mode & PNG_WROTE_tIME) == 0) png_write_tIME(png_ptr, &(info_ptr->mod_time)); #endif @@ -363,11 +417,14 @@ info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); + /* Mark this chunk as written */ + if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; + else + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write international text"); #endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) @@ -375,13 +432,12 @@ #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, 0, - info_ptr->text[i].compression); + info_ptr->text[i].text, info_ptr->text[i].compression); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write compressed text"); #endif - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) @@ -390,37 +446,16 @@ /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0); + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else png_warning(png_ptr, "Unable to write uncompressed text"); #endif - - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } } #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks_num) - { - png_unknown_chunk *up; - - png_debug(5, "writing extra chunks"); - - for (up = info_ptr->unknown_chunks; - up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; - up++) - { - int keep = png_handle_as_unknown(png_ptr, up->name); - if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && - (up->location & PNG_AFTER_IDAT) && - ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || - (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) - { - png_write_chunk(png_ptr, up->name, up->data, up->size); - } - } - } + write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); #endif } @@ -428,6 +463,7 @@ /* Write end of PNG file */ png_write_IEND(png_ptr); + /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, * and restored again in libpng-1.2.30, may cause some applications that * do not set png_ptr->output_flush_fn to crash. If your application @@ -443,9 +479,8 @@ } #ifdef PNG_CONVERT_tIME_SUPPORTED -/* "tm" structure is not supported on WindowsCE */ void PNGAPI -png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm FAR * ttime) +png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) { png_debug(1, "in png_convert_from_struct_tm"); @@ -474,103 +509,75 @@ png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) { -#ifdef PNG_USER_MEM_SUPPORTED - return (png_create_write_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, NULL, NULL, NULL)); +#ifndef PNG_USER_MEM_SUPPORTED + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, NULL, NULL, NULL); +#else + return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, + warn_fn, NULL, NULL, NULL); } /* Alternate initialize png_ptr structure, and allocate any memory needed */ -static void png_reset_filter_heuristics(png_structp png_ptr); /* forward decl */ - PNG_FUNCTION(png_structp,PNGAPI png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { -#endif /* PNG_USER_MEM_SUPPORTED */ - volatile int png_cleanup_needed = 0; -#ifdef PNG_SETJMP_SUPPORTED - volatile -#endif - png_structp png_ptr; -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf tmp_jmpbuf; -#endif -#endif - - png_debug(1, "in png_create_write_struct"); + png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* USER_MEM */ + if (png_ptr != NULL) + { + /* Set the zlib control values to defaults; they can be overridden by the + * application after the struct has been created. + */ + png_ptr->zbuffer_size = PNG_ZBUF_SIZE; -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr = (png_structp)png_create_struct_2(PNG_STRUCT_PNG, - (png_malloc_ptr)malloc_fn, (png_voidp)mem_ptr); -#else - png_ptr = (png_structp)png_create_struct(PNG_STRUCT_PNG); -#endif /* PNG_USER_MEM_SUPPORTED */ - if (png_ptr == NULL) - return (NULL); + /* The 'zlib_strategy' setting is irrelevant because png_default_claim in + * pngwutil.c defaults it according to whether or not filters will be + * used, and ignores this setting. + */ + png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; + png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_mem_level = 8; + png_ptr->zlib_window_bits = 15; + png_ptr->zlib_method = 8; - /* Added at libpng-1.2.6 */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - png_ptr->user_width_max = PNG_USER_WIDTH_MAX; - png_ptr->user_height_max = PNG_USER_HEIGHT_MAX; +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED + png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; + png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_text_mem_level = 8; + png_ptr->zlib_text_window_bits = 15; + png_ptr->zlib_text_method = 8; +#endif /* WRITE_COMPRESSED_TEXT */ + + /* This is a highly dubious configuration option; by default it is off, + * but it may be appropriate for private builds that are testing + * extensions not conformant to the current specification, or of + * applications that must not fail to write at all costs! + */ +#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + /* In stable builds only warn if an application error can be completely + * handled. + */ + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; #endif -#ifdef PNG_SETJMP_SUPPORTED -/* Applications that neglect to set up their own setjmp() and then - encounter a png_error() will longjmp here. Since the jmpbuf is - then meaningless we abort instead of returning. */ -#ifdef USE_FAR_KEYWORD - if (setjmp(tmp_jmpbuf)) -#else - if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */ -#endif -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf)); -#endif - PNG_ABORT(); + /* App warnings are warnings in release (or release candidate) builds but + * are errors during development. + */ +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; #endif -#ifdef PNG_USER_MEM_SUPPORTED - png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn); -#endif /* PNG_USER_MEM_SUPPORTED */ - png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); - - if (!png_user_version_check(png_ptr, user_png_ver)) - png_cleanup_needed = 1; - - /* Initialize zbuf - compression buffer */ - png_ptr->zbuf_size = PNG_ZBUF_SIZE; - - if (!png_cleanup_needed) - { - png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr, - png_ptr->zbuf_size); - if (png_ptr->zbuf == NULL) - png_cleanup_needed = 1; + /* TODO: delay this, it can be done in png_init_io() (if the app doesn't + * do it itself) avoiding setting the default function if it is not + * required. + */ + png_set_write_fn(png_ptr, NULL, NULL, NULL); } - if (png_cleanup_needed) - { - /* Clean up PNG structure and deallocate any memory. */ - png_free(png_ptr, png_ptr->zbuf); - png_ptr->zbuf = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, - (png_free_ptr)free_fn, (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - return (NULL); - } - - png_set_write_fn(png_ptr, NULL, NULL, NULL); - -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - png_reset_filter_heuristics(png_ptr); -#endif - - return (png_ptr); + return png_ptr; } @@ -580,7 +587,7 @@ * "write" the image seven times. */ void PNGAPI -png_write_rows(png_structp png_ptr, png_bytepp row, +png_write_rows(png_structrp png_ptr, png_bytepp row, png_uint_32 num_rows) { png_uint_32 i; /* row counter */ @@ -602,7 +609,7 @@ * if you are writing an interlaced image. */ void PNGAPI -png_write_image(png_structp png_ptr, png_bytepp image) +png_write_image(png_structrp png_ptr, png_bytepp image) { png_uint_32 i; /* row index */ int pass, num_pass; /* pass variables */ @@ -632,10 +639,78 @@ } } +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Performs intrapixel differencing */ +static void +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_write_intrapixel"); + + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((*rp - *(rp + 1)) & 0xff); + *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff); + } + } + +#ifdef PNG_WRITE_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; + + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp + 1) = (png_byte)(red & 0xff); + *(rp + 4) = (png_byte)((blue >> 8) & 0xff); + *(rp + 5) = (png_byte)(blue & 0xff); + } + } +#endif /* WRITE_16BIT */ + } +} +#endif /* MNG_FEATURES */ + /* Called by user to write a row of image data */ void PNGAPI -png_write_row(png_structp png_ptr, png_const_bytep row) +png_write_row(png_structrp png_ptr, png_const_bytep row) { + /* 1.5.6: moved from png_struct to be a local structure: */ + png_row_info row_info; + if (png_ptr == NULL) return; @@ -646,44 +721,44 @@ if (png_ptr->row_number == 0 && png_ptr->pass == 0) { /* Make sure we wrote the header info */ - if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) + if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) png_error(png_ptr, "png_write_info was never called before png_write_row"); /* Check for transforms that have been set but were defined out */ #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) - if (png_ptr->transformations & PNG_INVERT_MONO) + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) - if (png_ptr->transformations & PNG_FILLER) + if ((png_ptr->transformations & PNG_FILLER) != 0) png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ defined(PNG_READ_PACKSWAP_SUPPORTED) - if (png_ptr->transformations & PNG_PACKSWAP) + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) - if (png_ptr->transformations & PNG_PACK) + if ((png_ptr->transformations & PNG_PACK) != 0) png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) - if (png_ptr->transformations & PNG_SHIFT) + if ((png_ptr->transformations & PNG_SHIFT) != 0) png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) - if (png_ptr->transformations & PNG_BGR) + if ((png_ptr->transformations & PNG_BGR) != 0) png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) - if (png_ptr->transformations & PNG_SWAP_BYTES) + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); #endif @@ -692,12 +767,13 @@ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced and not interested in row, return */ - if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) + if (png_ptr->interlaced != 0 && + (png_ptr->transformations & PNG_INTERLACE) != 0) { switch (png_ptr->pass) { case 0: - if (png_ptr->row_number & 0x07) + if ((png_ptr->row_number & 0x07) != 0) { png_write_finish_row(png_ptr); return; @@ -705,7 +781,7 @@ break; case 1: - if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) + if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5) { png_write_finish_row(png_ptr); return; @@ -721,7 +797,7 @@ break; case 3: - if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) + if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3) { png_write_finish_row(png_ptr); return; @@ -737,7 +813,7 @@ break; case 5: - if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) + if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2) { png_write_finish_row(png_ptr); return; @@ -745,7 +821,7 @@ break; case 6: - if (!(png_ptr->row_number & 0x01)) + if ((png_ptr->row_number & 0x01) == 0) { png_write_finish_row(png_ptr); return; @@ -759,36 +835,31 @@ #endif /* Set up row info for transformations */ - png_ptr->row_info.color_type = png_ptr->color_type; - png_ptr->row_info.width = png_ptr->usr_width; - png_ptr->row_info.channels = png_ptr->usr_channels; - png_ptr->row_info.bit_depth = png_ptr->usr_bit_depth; - png_ptr->row_info.pixel_depth = (png_byte)(png_ptr->row_info.bit_depth * - png_ptr->row_info.channels); + row_info.color_type = png_ptr->color_type; + row_info.width = png_ptr->usr_width; + row_info.channels = png_ptr->usr_channels; + row_info.bit_depth = png_ptr->usr_bit_depth; + row_info.pixel_depth = (png_byte)(row_info.bit_depth * row_info.channels); + row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); - png_ptr->row_info.rowbytes = PNG_ROWBYTES(png_ptr->row_info.pixel_depth, - png_ptr->row_info.width); - - png_debug1(3, "row_info->color_type = %d", png_ptr->row_info.color_type); - png_debug1(3, "row_info->width = %u", png_ptr->row_info.width); - png_debug1(3, "row_info->channels = %d", png_ptr->row_info.channels); - png_debug1(3, "row_info->bit_depth = %d", png_ptr->row_info.bit_depth); - png_debug1(3, "row_info->pixel_depth = %d", png_ptr->row_info.pixel_depth); - png_debug1(3, "row_info->rowbytes = %lu", - (unsigned long)png_ptr->row_info.rowbytes); + png_debug1(3, "row_info->color_type = %d", row_info.color_type); + png_debug1(3, "row_info->width = %u", row_info.width); + png_debug1(3, "row_info->channels = %d", row_info.channels); + png_debug1(3, "row_info->bit_depth = %d", row_info.bit_depth); + png_debug1(3, "row_info->pixel_depth = %d", row_info.pixel_depth); + png_debug1(3, "row_info->rowbytes = %lu", (unsigned long)row_info.rowbytes); /* Copy user's row into buffer, leaving room for filter byte. */ - png_memcpy(png_ptr->row_buf + 1, row, png_ptr->row_info.rowbytes); + memcpy(png_ptr->row_buf + 1, row, row_info.rowbytes); #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Handle interlacing */ if (png_ptr->interlaced && png_ptr->pass < 6 && - (png_ptr->transformations & PNG_INTERLACE)) + (png_ptr->transformations & PNG_INTERLACE) != 0) { - png_do_write_interlace(&(png_ptr->row_info), - png_ptr->row_buf + 1, png_ptr->pass); + png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); /* This should always get caught above, but still ... */ - if (!(png_ptr->row_info.width)) + if (row_info.width == 0) { png_write_finish_row(png_ptr); return; @@ -798,10 +869,17 @@ #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED /* Handle other transformations */ - if (png_ptr->transformations) - png_do_write_transformations(png_ptr); + if (png_ptr->transformations != 0) + png_do_write_transformations(png_ptr, &row_info); #endif + /* At this point the row_info pixel depth must match the 'transformed' depth, + * which is also the output depth. + */ + if (row_info.pixel_depth != png_ptr->pixel_depth || + row_info.pixel_depth != png_ptr->transformed_pixel_depth) + png_error(png_ptr, "internal write transform logic error"); + #ifdef PNG_MNG_FEATURES_SUPPORTED /* Write filter_method 64 (intrapixel differencing) only if * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and @@ -812,16 +890,24 @@ * 4. The filter_method is 64 and * 5. The color_type is RGB or RGBA */ - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ - png_do_write_intrapixel(&(png_ptr->row_info), png_ptr->row_buf + 1); + png_do_write_intrapixel(&row_info, png_ptr->row_buf + 1); } #endif +/* Added at libpng-1.5.10 */ +#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Check for out-of-range palette index */ + if (row_info.color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, &row_info); +#endif + /* Find a filter if necessary, filter the row and write it out. */ - png_write_find_filter(png_ptr, &(png_ptr->row_info)); + png_write_find_filter(png_ptr, &row_info); if (png_ptr->write_row_fn != NULL) (*(png_ptr->write_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); @@ -830,7 +916,7 @@ #ifdef PNG_WRITE_FLUSH_SUPPORTED /* Set the automatic flush interval or 0 to turn flushing off */ void PNGAPI -png_set_flush(png_structp png_ptr, int nrows) +png_set_flush(png_structrp png_ptr, int nrows) { png_debug(1, "in png_set_flush"); @@ -842,10 +928,8 @@ /* Flush the current output buffers now */ void PNGAPI -png_write_flush(png_structp png_ptr) +png_write_flush(png_structrp png_ptr) { - int wrote_IDAT; - png_debug(1, "in png_write_flush"); if (png_ptr == NULL) @@ -855,146 +939,41 @@ if (png_ptr->row_number >= png_ptr->num_rows) return; - do - { - int ret; - - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_SYNC_FLUSH); - wrote_IDAT = 0; - - /* Check for compression errors */ - if (ret != Z_OK) - { - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - - else - png_error(png_ptr, "zlib error"); - } - - if (!(png_ptr->zstream.avail_out)) - { - /* Write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - wrote_IDAT = 1; - } - } while (wrote_IDAT == 1); - - /* If there is any data left to be output, write it into a new IDAT */ - if (png_ptr->zbuf_size != png_ptr->zstream.avail_out) - { - /* Write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, - png_ptr->zbuf_size - png_ptr->zstream.avail_out); - } + png_compress_IDAT(png_ptr, NULL, 0, Z_SYNC_FLUSH); png_ptr->flush_rows = 0; png_flush(png_ptr); } -#endif /* PNG_WRITE_FLUSH_SUPPORTED */ - -/* Free all memory used by the write */ -void PNGAPI -png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) -{ - png_structp png_ptr = NULL; - png_infop info_ptr = NULL; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn = NULL; - png_voidp mem_ptr = NULL; -#endif - - png_debug(1, "in png_destroy_write_struct"); +#endif /* WRITE_FLUSH */ - if (png_ptr_ptr != NULL) - { - png_ptr = *png_ptr_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; -#endif - } - -#ifdef PNG_USER_MEM_SUPPORTED - if (png_ptr != NULL) - { - free_fn = png_ptr->free_fn; - mem_ptr = png_ptr->mem_ptr; - } +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */ #endif - if (info_ptr_ptr != NULL) - info_ptr = *info_ptr_ptr; - - if (info_ptr != NULL) - { - if (png_ptr != NULL) - { - png_free_data(png_ptr, info_ptr, PNG_FREE_ALL, -1); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_ptr->num_chunk_list) - { - png_free(png_ptr, png_ptr->chunk_list); - png_ptr->num_chunk_list = 0; - } -#endif - } - -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)info_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)info_ptr); -#endif - *info_ptr_ptr = NULL; - } - - if (png_ptr != NULL) - { - png_write_destroy(png_ptr); -#ifdef PNG_USER_MEM_SUPPORTED - png_destroy_struct_2((png_voidp)png_ptr, (png_free_ptr)free_fn, - (png_voidp)mem_ptr); -#else - png_destroy_struct((png_voidp)png_ptr); -#endif - *png_ptr_ptr = NULL; - } -} - - -/* Free any memory used in png_ptr struct (old method) */ -void /* PRIVATE */ -png_write_destroy(png_structp png_ptr) +/* Free any memory used in png_ptr struct without freeing the struct itself. */ +static void +png_write_destroy(png_structrp png_ptr) { -#ifdef PNG_SETJMP_SUPPORTED - jmp_buf tmp_jmp; /* Save jump buffer */ -#endif - png_error_ptr error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - png_error_ptr warning_fn; -#endif - png_voidp error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_free_ptr free_fn; -#endif - png_debug(1, "in png_write_destroy"); /* Free any memory zlib uses */ - if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED) + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) deflateEnd(&png_ptr->zstream); /* Free our memory. png_free checks NULL for us. */ - png_free(png_ptr, png_ptr->zbuf); + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); png_free(png_ptr, png_ptr->row_buf); + png_ptr->row_buf = NULL; #ifdef PNG_WRITE_FILTER_SUPPORTED png_free(png_ptr, png_ptr->prev_row); png_free(png_ptr, png_ptr->sub_row); png_free(png_ptr, png_ptr->up_row); png_free(png_ptr, png_ptr->avg_row); png_free(png_ptr, png_ptr->paeth_row); + png_ptr->prev_row = NULL; + png_ptr->sub_row = NULL; + png_ptr->up_row = NULL; + png_ptr->avg_row = NULL; + png_ptr->paeth_row = NULL; #endif #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED @@ -1002,41 +981,51 @@ png_reset_filter_heuristics(png_ptr); png_free(png_ptr, png_ptr->filter_costs); png_free(png_ptr, png_ptr->inv_filter_costs); + png_ptr->filter_costs = NULL; + png_ptr->inv_filter_costs = NULL; #endif -#ifdef PNG_SETJMP_SUPPORTED - /* Reset structure */ - png_memcpy(tmp_jmp, png_ptr->longjmp_buffer, png_sizeof(jmp_buf)); +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + png_free(png_ptr, png_ptr->chunk_list); + png_ptr->chunk_list = NULL; #endif - error_fn = png_ptr->error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - warning_fn = png_ptr->warning_fn; -#endif - error_ptr = png_ptr->error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - free_fn = png_ptr->free_fn; -#endif - - png_memset(png_ptr, 0, png_sizeof(png_struct)); + /* The error handling and memory handling information is left intact at this + * point: the jmp_buf may still have to be freed. See png_destroy_png_struct + * for how this happens. + */ +} - png_ptr->error_fn = error_fn; -#ifdef PNG_WARNINGS_SUPPORTED - png_ptr->warning_fn = warning_fn; -#endif - png_ptr->error_ptr = error_ptr; -#ifdef PNG_USER_MEM_SUPPORTED - png_ptr->free_fn = free_fn; -#endif +/* Free all memory used by the write. + * In libpng 1.6.0 this API changed quietly to no longer accept a NULL value for + * *png_ptr_ptr. Prior to 1.6.0 it would accept such a value and it would free + * the passed in info_structs but it would quietly fail to free any of the data + * inside them. In 1.6.0 it quietly does nothing (it has to be quiet because it + * has no png_ptr.) + */ +void PNGAPI +png_destroy_write_struct(png_structpp png_ptr_ptr, png_infopp info_ptr_ptr) +{ + png_debug(1, "in png_destroy_write_struct"); -#ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->longjmp_buffer, tmp_jmp, png_sizeof(jmp_buf)); -#endif + if (png_ptr_ptr != NULL) + { + png_structrp png_ptr = *png_ptr_ptr; + + if (png_ptr != NULL) /* added in libpng 1.6.0 */ + { + png_destroy_info_struct(png_ptr, info_ptr_ptr); + + *png_ptr_ptr = NULL; + png_write_destroy(png_ptr); + png_destroy_png_struct(png_ptr); + } + } } /* Allow the application to select one or more row filters to use. */ void PNGAPI -png_set_filter(png_structp png_ptr, int method, int filters) +png_set_filter(png_structrp png_ptr, int method, int filters) { png_debug(1, "in png_set_filter"); @@ -1044,7 +1033,7 @@ return; #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && (method == PNG_INTRAPIXEL_DIFFERENCING)) method = PNG_FILTER_TYPE_BASE; @@ -1056,8 +1045,9 @@ #ifdef PNG_WRITE_FILTER_SUPPORTED case 5: case 6: - case 7: png_warning(png_ptr, "Unknown row filter for method 0"); -#endif /* PNG_WRITE_FILTER_SUPPORTED */ + case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); + /* FALL THROUGH */ +#endif /* WRITE_FILTER */ case PNG_FILTER_VALUE_NONE: png_ptr->do_filter = PNG_FILTER_NONE; break; @@ -1078,8 +1068,8 @@ png_ptr->do_filter = (png_byte)filters; break; #else default: - png_warning(png_ptr, "Unknown row filter for method 0"); -#endif /* PNG_WRITE_FILTER_SUPPORTED */ + png_app_error(png_ptr, "Unknown row filter for method 0"); +#endif /* WRITE_FILTER */ } /* If we have allocated the row_buf, this means we have already started @@ -1094,14 +1084,16 @@ if (png_ptr->row_buf != NULL) { #ifdef PNG_WRITE_FILTER_SUPPORTED - if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) + if ((png_ptr->do_filter & PNG_FILTER_SUB) != 0 && + png_ptr->sub_row == NULL) { png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, (png_ptr->rowbytes + 1)); png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; } - if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) + if ((png_ptr->do_filter & PNG_FILTER_UP) != 0 && + png_ptr->up_row == NULL) { if (png_ptr->prev_row == NULL) { @@ -1118,7 +1110,8 @@ } } - if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) + if ((png_ptr->do_filter & PNG_FILTER_AVG) != 0 && + png_ptr->avg_row == NULL) { if (png_ptr->prev_row == NULL) { @@ -1135,7 +1128,7 @@ } } - if ((png_ptr->do_filter & PNG_FILTER_PAETH) && + if ((png_ptr->do_filter & PNG_FILTER_PAETH) != 0 && png_ptr->paeth_row == NULL) { if (png_ptr->prev_row == NULL) @@ -1153,7 +1146,7 @@ } if (png_ptr->do_filter == PNG_NO_FILTERS) -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ png_ptr->do_filter = PNG_FILTER_NONE; } } @@ -1171,7 +1164,7 @@ #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ /* Convenience reset API. */ static void -png_reset_filter_heuristics(png_structp png_ptr) +png_reset_filter_heuristics(png_structrp png_ptr) { /* Clear out any old values in the 'weights' - this must be done because if * the app calls set_filter_heuristics multiple times with different @@ -1204,7 +1197,7 @@ } static int -png_init_filter_heuristics(png_structp png_ptr, int heuristic_method, +png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method, int num_weights) { if (png_ptr == NULL) @@ -1224,7 +1217,7 @@ if (num_weights > 0) { png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_byte) * num_weights)); + (png_uint_32)((sizeof (png_byte)) * num_weights)); /* To make sure that the weighting starts out fairly */ for (i = 0; i < num_weights; i++) @@ -1233,10 +1226,10 @@ } png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + (png_uint_32)((sizeof (png_uint_16)) * num_weights)); png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * num_weights)); + (png_uint_32)((sizeof (png_uint_16)) * num_weights)); for (i = 0; i < num_weights; i++) { @@ -1254,10 +1247,10 @@ if (png_ptr->filter_costs == NULL) { png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, - (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST)); + (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); } for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) @@ -1287,7 +1280,7 @@ /* Provide floating and fixed point APIs */ #ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI -png_set_filter_heuristics(png_structp png_ptr, int heuristic_method, +png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, int num_weights, png_const_doublep filter_weights, png_const_doublep filter_costs) { @@ -1296,7 +1289,7 @@ /* The internal API allocates all the arrays and ensures that the elements of * those arrays are set to the default value. */ - if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) + if (png_init_filter_heuristics(png_ptr, heuristic_method, num_weights) == 0) return; /* If using the weighted method copy in the weights. */ @@ -1342,7 +1335,7 @@ #ifdef PNG_FIXED_POINT_SUPPORTED void PNGAPI -png_set_filter_heuristics_fixed(png_structp png_ptr, int heuristic_method, +png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, int num_weights, png_const_fixed_point_p filter_weights, png_const_fixed_point_p filter_costs) { @@ -1351,7 +1344,7 @@ /* The internal API allocates all the arrays and ensures that the elements of * those arrays are set to the default value. */ - if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) + if (png_init_filter_heuristics(png_ptr, heuristic_method, num_weights) == 0) return; /* If using the weighted method copy in the weights. */ @@ -1405,40 +1398,40 @@ } } #endif /* FIXED_POINT */ -#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ +#endif /* WRITE_WEIGHTED_FILTER */ void PNGAPI -png_set_compression_level(png_structp png_ptr, int level) +png_set_compression_level(png_structrp png_ptr, int level) { png_debug(1, "in png_set_compression_level"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_LEVEL; png_ptr->zlib_level = level; } void PNGAPI -png_set_compression_mem_level(png_structp png_ptr, int mem_level) +png_set_compression_mem_level(png_structrp png_ptr, int mem_level) { png_debug(1, "in png_set_compression_mem_level"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL; png_ptr->zlib_mem_level = mem_level; } void PNGAPI -png_set_compression_strategy(png_structp png_ptr, int strategy) +png_set_compression_strategy(png_structrp png_ptr, int strategy) { png_debug(1, "in png_set_compression_strategy"); if (png_ptr == NULL) return; + /* The flag setting here prevents the libpng dynamic selection of strategy. + */ png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_STRATEGY; png_ptr->zlib_strategy = strategy; } @@ -1447,80 +1440,81 @@ * smaller value of window_bits if it can do so safely. */ void PNGAPI -png_set_compression_window_bits(png_structp png_ptr, int window_bits) +png_set_compression_window_bits(png_structrp png_ptr, int window_bits) { if (png_ptr == NULL) return; + /* Prior to 1.6.0 this would warn but then set the window_bits value, this + * meant that negative window bits values could be selected which would cause + * libpng to write a non-standard PNG file with raw deflate or gzip + * compressed IDAT or ancillary chunks. Such files can be read and there is + * no warning on read, so this seems like a very bad idea. + */ if (window_bits > 15) + { png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } else if (window_bits < 8) + { png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } -#ifndef WBITS_8_OK - /* Avoid libpng bug with 256-byte windows */ - if (window_bits == 8) - { - png_warning(png_ptr, "Compression window is being reset to 512"); - window_bits = 9; - } - -#endif - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS; png_ptr->zlib_window_bits = window_bits; } void PNGAPI -png_set_compression_method(png_structp png_ptr, int method) +png_set_compression_method(png_structrp png_ptr, int method) { png_debug(1, "in png_set_compression_method"); if (png_ptr == NULL) return; + /* This would produce an invalid PNG file if it worked, but it doesn't and + * deflate will fault it, so it is harmless to just warn here. + */ if (method != 8) png_warning(png_ptr, "Only compression method 8 is supported by PNG"); - png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD; png_ptr->zlib_method = method; } /* The following were added to libpng-1.5.4 */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED void PNGAPI -png_set_text_compression_level(png_structp png_ptr, int level) +png_set_text_compression_level(png_structrp png_ptr, int level) { png_debug(1, "in png_set_text_compression_level"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_LEVEL; png_ptr->zlib_text_level = level; } void PNGAPI -png_set_text_compression_mem_level(png_structp png_ptr, int mem_level) +png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) { png_debug(1, "in png_set_text_compression_mem_level"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL; png_ptr->zlib_text_mem_level = mem_level; } void PNGAPI -png_set_text_compression_strategy(png_structp png_ptr, int strategy) +png_set_text_compression_strategy(png_structrp png_ptr, int strategy) { png_debug(1, "in png_set_text_compression_strategy"); if (png_ptr == NULL) return; - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_STRATEGY; png_ptr->zlib_text_strategy = strategy; } @@ -1528,32 +1522,28 @@ * smaller value of window_bits if it can do so safely. */ void PNGAPI -png_set_text_compression_window_bits(png_structp png_ptr, int window_bits) +png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) { if (png_ptr == NULL) return; if (window_bits > 15) + { png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + window_bits = 15; + } else if (window_bits < 8) + { png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + window_bits = 8; + } -#ifndef WBITS_8_OK - /* Avoid libpng bug with 256-byte windows */ - if (window_bits == 8) - { - png_warning(png_ptr, "Text compression window is being reset to 512"); - window_bits = 9; - } - -#endif - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS; png_ptr->zlib_text_window_bits = window_bits; } void PNGAPI -png_set_text_compression_method(png_structp png_ptr, int method) +png_set_text_compression_method(png_structrp png_ptr, int method) { png_debug(1, "in png_set_text_compression_method"); @@ -1563,14 +1553,13 @@ if (method != 8) png_warning(png_ptr, "Only compression method 8 is supported by PNG"); - png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_METHOD; png_ptr->zlib_text_method = method; } -#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ +#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ /* end of API added to libpng-1.5.4 */ void PNGAPI -png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) +png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) { if (png_ptr == NULL) return; @@ -1580,7 +1569,7 @@ #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED void PNGAPI -png_set_write_user_transform_fn(png_structp png_ptr, png_user_transform_ptr +png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr write_user_transform_fn) { png_debug(1, "in png_set_write_user_transform_fn"); @@ -1596,88 +1585,899 @@ #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI -png_write_png(png_structp png_ptr, png_infop info_ptr, +png_write_png(png_structrp png_ptr, png_inforp info_ptr, int transforms, voidp params) { if (png_ptr == NULL || info_ptr == NULL) return; + if ((info_ptr->valid & PNG_INFO_IDAT) == 0) + { + png_app_error(png_ptr, "no rows for png_write_image to write"); + return; + } + /* Write the file header information. */ png_write_info(png_ptr, info_ptr); /* ------ these transformations don't touch the info structure ------- */ + /* Invert monochrome pixels */ + if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) #ifdef PNG_WRITE_INVERT_SUPPORTED - /* Invert monochrome pixels */ - if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); #endif -#ifdef PNG_WRITE_SHIFT_SUPPORTED /* Shift the pixels up to a legal bit depth and fill in * as appropriate to correctly scale the image. */ - if ((transforms & PNG_TRANSFORM_SHIFT) - && (info_ptr->valid & PNG_INFO_sBIT)) - png_set_shift(png_ptr, &info_ptr->sig_bit); + if ((transforms & PNG_TRANSFORM_SHIFT) != 0) +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((info_ptr->valid & PNG_INFO_sBIT) != 0) + png_set_shift(png_ptr, &info_ptr->sig_bit); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); #endif + /* Pack pixels into bytes */ + if ((transforms & PNG_TRANSFORM_PACKING) != 0) #ifdef PNG_WRITE_PACK_SUPPORTED - /* Pack pixels into bytes */ - if (transforms & PNG_TRANSFORM_PACKING) - png_set_packing(png_ptr); + png_set_packing(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); #endif + /* Swap location of alpha bytes from ARGB to RGBA */ + if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED - /* Swap location of alpha bytes from ARGB to RGBA */ - if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); #endif + /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into + * RGB, note that the code expects the input color type to be G or RGB; no + * alpha channel. + */ + if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER| + PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0) + { #ifdef PNG_WRITE_FILLER_SUPPORTED - /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */ - if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) - png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0) + { + if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_app_error(png_ptr, + "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported"); - else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); -#endif + /* Continue if ignored - this is the pre-1.6.10 behavior */ + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + } -#ifdef PNG_WRITE_BGR_SUPPORTED + else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported"); +#endif + } + /* Flip BGR pixels to RGB */ - if (transforms & PNG_TRANSFORM_BGR) + if ((transforms & PNG_TRANSFORM_BGR) != 0) +#ifdef PNG_WRITE_BGR_SUPPORTED png_set_bgr(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); #endif + /* Swap bytes of 16-bit files to most significant byte first */ + if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) #ifdef PNG_WRITE_SWAP_SUPPORTED - /* Swap bytes of 16-bit files to most significant byte first */ - if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); #endif + /* Swap bits of 1, 2, 4 bit packed pixel formats */ + if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) #ifdef PNG_WRITE_PACKSWAP_SUPPORTED - /* Swap bits of 1, 2, 4 bit packed pixel formats */ - if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); #endif + /* Invert the alpha channel from opacity to transparency */ + if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - /* Invert the alpha channel from opacity to transparency */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); +#else + png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); #endif /* ----------------------- end of transformations ------------------- */ /* Write the bits */ - if (info_ptr->valid & PNG_INFO_IDAT) - png_write_image(png_ptr, info_ptr->row_pointers); + png_write_image(png_ptr, info_ptr->row_pointers); /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); - PNG_UNUSED(transforms) /* Quiet compiler warnings */ PNG_UNUSED(params) } #endif -#endif /* PNG_WRITE_SUPPORTED */ + + +#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */ +/* Initialize the write structure - general purpose utility. */ +static int +png_image_write_init(png_imagep image) +{ + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, + png_safe_error, png_safe_warning); + + if (png_ptr != NULL) + { + png_infop info_ptr = png_create_info_struct(png_ptr); + + if (info_ptr != NULL) + { + png_controlp control = png_voidcast(png_controlp, + png_malloc_warn(png_ptr, (sizeof *control))); + + if (control != NULL) + { + memset(control, 0, (sizeof *control)); + + control->png_ptr = png_ptr; + control->info_ptr = info_ptr; + control->for_write = 1; + + image->opaque = control; + return 1; + } + + /* Error clean up */ + png_destroy_info_struct(png_ptr, &info_ptr); + } + + png_destroy_write_struct(&png_ptr, NULL); + } + + return png_image_error(image, "png_image_write_: out of memory"); +} + +/* Arguments to png_image_write_main: */ +typedef struct +{ + /* Arguments: */ + png_imagep image; + png_const_voidp buffer; + png_int_32 row_stride; + png_const_voidp colormap; + int convert_to_8bit; + /* Local variables: */ + png_const_voidp first_row; + ptrdiff_t row_bytes; + png_voidp local_row; +} png_image_write_control; + +/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to + * do any necessary byte swapping. The component order is defined by the + * png_image format value. + */ +static int +png_write_image_16bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); + png_uint_16p row_end; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + int aindex = 0; + png_uint_32 y = image->height; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else +# endif + aindex = channels; + } + + else + png_error(png_ptr, "png_write_image: internal call error"); + + /* Work out the output row end and count over this, note that the increment + * above to 'row' means that row_end can actually be beyond the end of the + * row; this is correct. + */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_uint_16p out_ptr = output_row; + + while (out_ptr < row_end) + { + const png_uint_16 alpha = in_ptr[aindex]; + png_uint_32 reciprocal = 0; + int c; + + out_ptr[aindex] = alpha; + + /* Calculate a reciprocal. The correct calculation is simply + * component/alpha*65535 << 15. (I.e. 15 bits of precision); this + * allows correct rounding by adding .5 before the shift. 'reciprocal' + * is only initialized when required. + */ + if (alpha > 0 && alpha < 65535) + reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; + + c = channels; + do /* always at least one channel */ + { + png_uint_16 component = *in_ptr++; + + /* The following gives 65535 for an alpha of 0, which is fine, + * otherwise if 0/0 is represented as some other value there is more + * likely to be a discontinuity which will probably damage + * compression when moving from a fully transparent area to a + * nearly transparent one. (The assumption here is that opaque + * areas tend not to be 0 intensity.) + */ + if (component >= alpha) + component = 65535; + + /* component 0 && alpha < 65535) + { + png_uint_32 calc = component * reciprocal; + calc += 16384; /* round to nearest */ + component = (png_uint_16)(calc >> 15); + } + + *out_ptr++ = component; + } + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } + + png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + + return 1; +} + +/* Given 16-bit input (1 to 4 channels) write 8-bit output. If an alpha channel + * is present it must be removed from the components, the components are then + * written in sRGB encoding. No components are added or removed. + * + * Calculate an alpha reciprocal to reverse pre-multiplication. As above the + * calculation can be done to 15 bits of accuracy; however, the output needs to + * be scaled in the range 0..255*65535, so include that scaling here. + */ +#define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) + +static png_byte +png_unpremultiply(png_uint_32 component, png_uint_32 alpha, + png_uint_32 reciprocal/*from the above macro*/) +{ + /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 + * is represented as some other value there is more likely to be a + * discontinuity which will probably damage compression when moving from a + * fully transparent area to a nearly transparent one. (The assumption here + * is that opaque areas tend not to be 0 intensity.) + * + * There is a rounding problem here; if alpha is less than 128 it will end up + * as 0 when scaled to 8 bits. To avoid introducing spurious colors into the + * output change for this too. + */ + if (component >= alpha || alpha < 128) + return 255; + + /* component 0) + { + /* The test is that alpha/257 (rounded) is less than 255, the first value + * that becomes 255 is 65407. + * NOTE: this must agree with the PNG_DIV257 macro (which must, therefore, + * be exact!) [Could also test reciprocal != 0] + */ + if (alpha < 65407) + { + component *= reciprocal; + component += 64; /* round to nearest */ + component >>= 7; + } + + else + component *= 255; + + /* Convert the component to sRGB. */ + return (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + else + return 0; +} + +static int +png_write_image_8bit(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + + png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, + display->first_row); + png_bytep output_row = png_voidcast(png_bytep, display->local_row); + png_uint_32 y = image->height; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; + + if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + { + png_bytep row_end; + int aindex; + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + aindex = -1; + ++input_row; /* To point to the first component */ + ++output_row; + } + + else +# endif + aindex = channels; + + /* Use row_end in place of a loop counter: */ + row_end = output_row + image->width * (channels+1); + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_16 alpha = in_ptr[aindex]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + int c; + + /* Scale and write the alpha channel. */ + out_ptr[aindex] = alphabyte; + + if (alphabyte > 0 && alphabyte < 255) + reciprocal = UNP_RECIPROCAL(alpha); + + c = channels; + do /* always at least one channel */ + *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); + while (--c > 0); + + /* Skip to next component (skip the intervening alpha channel) */ + ++in_ptr; + ++out_ptr; + } /* while out_ptr < row_end */ + + png_write_row(png_ptr, png_voidcast(png_const_bytep, + display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } /* while y */ + } + + else + { + /* No alpha channel, so the row_end really is the end of the row and it + * is sufficient to loop over the components one by one. + */ + png_bytep row_end = output_row + image->width * channels; + + while (y-- > 0) + { + png_const_uint_16p in_ptr = input_row; + png_bytep out_ptr = output_row; + + while (out_ptr < row_end) + { + png_uint_32 component = *in_ptr++; + + component *= 255; + *out_ptr++ = (png_byte)PNG_sRGB_FROM_LINEAR(component); + } + + png_write_row(png_ptr, output_row); + input_row += display->row_bytes/(sizeof (png_uint_16)); + } + } + + return 1; +} + +static void +png_image_set_PLTE(png_image_write_control *display) +{ + const png_imagep image = display->image; + const void *cmap = display->colormap; + const int entries = image->colormap_entries > 256 ? 256 : + (int)image->colormap_entries; + + /* NOTE: the caller must check for cmap != NULL and entries != 0 */ + const png_uint_32 format = image->format; + const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); + +# if defined(PNG_FORMAT_BGR_SUPPORTED) &&\ + defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED) + const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else +# define afirst 0 +# endif + +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; +# else +# define bgr 0 +# endif + + int i, num_trans; + png_color palette[256]; + png_byte tRNS[256]; + + memset(tRNS, 255, (sizeof tRNS)); + memset(palette, 0, (sizeof palette)); + + for (i=num_trans=0; i= 3) /* RGB */ + { + palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[(2 ^ bgr)]); + palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[1]); + palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * + entry[bgr]); + } + + else /* Gray */ + palette[i].blue = palette[i].red = palette[i].green = + (png_byte)PNG_sRGB_FROM_LINEAR(255 * *entry); + } + + else /* alpha */ + { + png_uint_16 alpha = entry[afirst ? 0 : channels-1]; + png_byte alphabyte = (png_byte)PNG_DIV257(alpha); + png_uint_32 reciprocal = 0; + + /* Calculate a reciprocal, as in the png_write_image_8bit code above + * this is designed to produce a value scaled to 255*65535 when + * divided by 128 (i.e. asr 7). + */ + if (alphabyte > 0 && alphabyte < 255) + reciprocal = (((0xffff*0xff)<<7)+(alpha>>1))/alpha; + + tRNS[i] = alphabyte; + if (alphabyte < 255) + num_trans = i+1; + + if (channels >= 3) /* RGB */ + { + palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], + alpha, reciprocal); + palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, + reciprocal); + palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, + reciprocal); + } + + else /* gray */ + palette[i].blue = palette[i].red = palette[i].green = + png_unpremultiply(entry[afirst], alpha, reciprocal); + } + } + + else /* Color-map has sRGB values */ + { + png_const_bytep entry = png_voidcast(png_const_bytep, cmap); + + entry += i * channels; + + switch (channels) + { + case 4: + tRNS[i] = entry[afirst ? 0 : 3]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 3: + palette[i].blue = entry[afirst + (2 ^ bgr)]; + palette[i].green = entry[afirst + 1]; + palette[i].red = entry[afirst + bgr]; + break; + + case 2: + tRNS[i] = entry[1 ^ afirst]; + if (tRNS[i] < 255) + num_trans = i+1; + /* FALL THROUGH */ + case 1: + palette[i].blue = palette[i].red = palette[i].green = + entry[afirst]; + break; + + default: + break; + } + } + } + +# ifdef afirst +# undef afirst +# endif +# ifdef bgr +# undef bgr +# endif + + png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, + entries); + + if (num_trans > 0) + png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, + num_trans, NULL); + + image->colormap_entries = entries; +} + +static int +png_image_write_main(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + png_imagep image = display->image; + png_structrp png_ptr = image->opaque->png_ptr; + png_inforp info_ptr = image->opaque->info_ptr; + png_uint_32 format = image->format; + + /* The following four ints are actually booleans */ + int colormap = (format & PNG_FORMAT_FLAG_COLORMAP); + int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */ + int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA); + int write_16bit = linear && !colormap && (display->convert_to_8bit == 0); + +# ifdef PNG_BENIGN_ERRORS_SUPPORTED + /* Make sure we error out on any bad situation */ + png_set_benign_errors(png_ptr, 0/*error*/); +# endif + + /* Default the 'row_stride' parameter if required. */ + if (display->row_stride == 0) + display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); + + /* Set the required transforms then write the rows in the correct order. */ + if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) + { + if (display->colormap != NULL && image->colormap_entries > 0) + { + png_uint_32 entries = image->colormap_entries; + + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), + PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + png_image_set_PLTE(display); + } + + else + png_error(image->opaque->png_ptr, + "no color-map for color-mapped image"); + } + + else + png_set_IHDR(png_ptr, info_ptr, image->width, image->height, + write_16bit ? 16 : 8, + ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + + ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + /* Counter-intuitively the data transformations must be called *after* + * png_write_info, not before as in the read code, but the 'set' functions + * must still be called before. Just set the color space information, never + * write an interlaced image. + */ + + if (write_16bit != 0) + { + /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); + + if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_cHRM_fixed(png_ptr, info_ptr, + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000 + ); + } + + else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); + + /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit + * space must still be gamma encoded. + */ + else + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); + + /* Write the file header. */ + png_write_info(png_ptr, info_ptr); + + /* Now set up the data transformations (*after* the header is written), + * remove the handled transformations from the 'format' flags for checking. + * + * First check for a little endian system if writing 16 bit files. + */ + if (write_16bit != 0) + { + PNG_CONST png_uint_16 le = 0x0001; + + if ((*(png_const_bytep) & le) != 0) + png_set_swap(png_ptr); + } + +# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED + if ((format & PNG_FORMAT_FLAG_BGR) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0) + png_set_bgr(png_ptr); + format &= ~PNG_FORMAT_FLAG_BGR; + } +# endif + +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + { + if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0) + png_set_swap_alpha(png_ptr); + format &= ~PNG_FORMAT_FLAG_AFIRST; + } +# endif + + /* If there are 16 or fewer color-map entries we wrote a lower bit depth + * above, but the application data is still byte packed. + */ + if (colormap != 0 && image->colormap_entries <= 16) + png_set_packing(png_ptr); + + /* That should have handled all (both) the transforms. */ + if ((format & ~(png_uint_32)(PNG_FORMAT_FLAG_COLOR | PNG_FORMAT_FLAG_LINEAR | + PNG_FORMAT_FLAG_ALPHA | PNG_FORMAT_FLAG_COLORMAP)) != 0) + png_error(png_ptr, "png_write_image: unsupported transformation"); + + { + png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); + ptrdiff_t row_bytes = display->row_stride; + + if (linear != 0) + row_bytes *= (sizeof (png_uint_16)); + + if (row_bytes < 0) + row += (image->height-1) * (-row_bytes); + + display->first_row = row; + display->row_bytes = row_bytes; + } + + /* Apply 'fast' options if the flag is set. */ + if ((image->flags & PNG_IMAGE_FLAG_FAST) != 0) + { + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); + /* NOTE: determined by experiment using pngstest, this reflects some + * balance between the time to write the image once and the time to read + * it about 50 times. The speed-up in pngstest was about 10-20% of the + * total (user) time on a heavily loaded system. + */ + png_set_compression_level(png_ptr, 3); + } + + /* Check for the cases that currently require a pre-transform on the row + * before it is written. This only applies when the input is 16-bit and + * either there is an alpha channel or it is converted to 8-bit. + */ + if ((linear != 0 && alpha != 0 ) || + (colormap == 0 && display->convert_to_8bit != 0)) + { + png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr))); + int result; + + display->local_row = row; + if (write_16bit != 0) + result = png_safe_execute(image, png_write_image_16bit, display); + else + result = png_safe_execute(image, png_write_image_8bit, display); + display->local_row = NULL; + + png_free(png_ptr, row); + + /* Skip the 'write_end' on error: */ + if (result == 0) + return 0; + } + + /* Otherwise this is the case where the input is in a format currently + * supported by the rest of the libpng write code; call it directly. + */ + else + { + png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); + ptrdiff_t row_bytes = display->row_bytes; + png_uint_32 y = image->height; + + while (y-- > 0) + { + png_write_row(png_ptr, row); + row += row_bytes; + } + } + + png_write_end(png_ptr, info_ptr); + return 1; +} + +int PNGAPI +png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, + const void *buffer, png_int_32 row_stride, const void *colormap) +{ + /* Write the image to the given (FILE*). */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file != NULL) + { + if (png_image_write_init(image) != 0) + { + png_image_write_control display; + int result; + + /* This is slightly evil, but png_init_io doesn't do anything other + * than this and we haven't changed the standard IO functions so + * this saves a 'safe' function. + */ + image->opaque->png_ptr->io_ptr = file; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.convert_to_8bit = convert_to_8bit; + + result = png_safe_execute(image, png_image_write_main, &display); + png_image_free(image); + return result; + } + + else + return 0; + } + + else + return png_image_error(image, + "png_image_write_to_stdio: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} + +int PNGAPI +png_image_write_to_file(png_imagep image, const char *file_name, + int convert_to_8bit, const void *buffer, png_int_32 row_stride, + const void *colormap) +{ + /* Write the image to the named file. */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (file_name != NULL) + { + FILE *fp = fopen(file_name, "wb"); + + if (fp != NULL) + { + if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, + row_stride, colormap) != 0) + { + int error; /* from fflush/fclose */ + + /* Make sure the file is flushed correctly. */ + if (fflush(fp) == 0 && ferror(fp) == 0) + { + if (fclose(fp) == 0) + return 1; + + error = errno; /* from fclose */ + } + + else + { + error = errno; /* from fflush or ferror */ + (void)fclose(fp); + } + + (void)remove(file_name); + /* The image has already been cleaned up; this is just used to + * set the error (because the original write succeeded). + */ + return png_image_error(image, strerror(error)); + } + + else + { + /* Clean up: just the opened file. */ + (void)fclose(fp); + (void)remove(file_name); + return 0; + } + } + + else + return png_image_error(image, strerror(errno)); + } + + else + return png_image_error(image, + "png_image_write_to_file: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} +#endif /* STDIO */ +#endif /* SIMPLIFIED_WRITE */ +#endif /* WRITE */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwtran.c --- a/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwtran.c Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwtran.c Fri Apr 17 10:24:46 2015 -0700 @@ -29,8 +29,8 @@ * However, the following notice accompanied the original version of this * file and, per its terms, should not be removed: * - * Last changed in libpng 1.5.4 [July 7, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -42,90 +42,14 @@ #include "pngpriv.h" #ifdef PNG_WRITE_SUPPORTED - #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED -/* Transform the data according to the user's wishes. The order of - * transformations is significant. - */ -void /* PRIVATE */ -png_do_write_transformations(png_structp png_ptr) -{ - png_debug(1, "in png_do_write_transformations"); - - if (png_ptr == NULL) - return; - -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - if (png_ptr->transformations & PNG_USER_TRANSFORM) - if (png_ptr->write_user_transform_fn != NULL) - (*(png_ptr->write_user_transform_fn)) /* User write transform - function */ - (png_ptr, /* png_ptr */ - &(png_ptr->row_info), /* row_info: */ - /* png_uint_32 width; width of row */ - /* png_size_t rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#endif - -#ifdef PNG_WRITE_FILLER_SUPPORTED - if (png_ptr->transformations & PNG_FILLER) - png_do_strip_channel(&(png_ptr->row_info), png_ptr->row_buf + 1, - !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); -#endif - -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED - if (png_ptr->transformations & PNG_PACKSWAP) - png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_PACK_SUPPORTED - if (png_ptr->transformations & PNG_PACK) - png_do_pack(&(png_ptr->row_info), png_ptr->row_buf + 1, - (png_uint_32)png_ptr->bit_depth); -#endif - -#ifdef PNG_WRITE_SWAP_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_BYTES) - png_do_swap(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_SHIFT_SUPPORTED - if (png_ptr->transformations & PNG_SHIFT) - png_do_shift(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif - -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_SWAP_ALPHA) - png_do_write_swap_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - png_do_write_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_BGR_SUPPORTED - if (png_ptr->transformations & PNG_BGR) - png_do_bgr(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_INVERT_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_MONO) - png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif -} #ifdef PNG_WRITE_PACK_SUPPORTED /* Pack pixels into bytes. Pass the true bit depth in bit_depth. The * row_info bit depth should be 8 (one pixel per byte). The channels * should be 1 (this only happens on grayscale and paletted images). */ -void /* PRIVATE */ +static void png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) { png_debug(1, "in png_do_pack"); @@ -270,7 +194,7 @@ * would pass 3 as bit_depth, and this routine would translate the * data to 0 to 15. */ -void /* PRIVATE */ +static void png_do_shift(png_row_infop row_info, png_bytep row, png_const_color_8p bit_depth) { @@ -281,7 +205,7 @@ int shift_start[4], shift_dec[4]; int channels = 0; - if (row_info->color_type & PNG_COLOR_MASK_COLOR) + if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) { shift_start[channels] = row_info->bit_depth - bit_depth->red; shift_dec[channels] = bit_depth->red; @@ -303,7 +227,7 @@ channels++; } - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) { shift_start[channels] = row_info->bit_depth - bit_depth->alpha; shift_dec[channels] = bit_depth->alpha; @@ -315,7 +239,7 @@ { png_bytep bp = row; png_size_t i; - png_byte mask; + unsigned int mask; png_size_t row_bytes = row_info->rowbytes; if (bit_depth->gray == 1 && row_info->bit_depth == 2) @@ -329,20 +253,22 @@ for (i = 0; i < row_bytes; i++, bp++) { - png_uint_16 v; int j; + unsigned int v, out; v = *bp; - *bp = 0; + out = 0; for (j = shift_start[0]; j > -shift_dec[0]; j -= shift_dec[0]) { if (j > 0) - *bp |= (png_byte)((v << j) & 0xff); + out |= v << j; else - *bp |= (png_byte)((v >> (-j)) & mask); + out |= (v >> (-j)) & mask; } + + *bp = (png_byte)(out & 0xff); } } @@ -355,21 +281,23 @@ for (i = 0; i < istop; i++, bp++) { - png_uint_16 v; + const unsigned int c = i%channels; int j; - int c = (int)(i%channels); + unsigned int v, out; v = *bp; - *bp = 0; + out = 0; for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) { if (j > 0) - *bp |= (png_byte)((v << j) & 0xff); + out |= v << j; else - *bp |= (png_byte)((v >> (-j)) & 0xff); + out |= v >> (-j); } + + *bp = (png_byte)(out & 0xff); } } @@ -381,22 +309,22 @@ for (bp = row, i = 0; i < istop; i++) { - int c = (int)(i%channels); - png_uint_16 value, v; + const unsigned int c = i%channels; int j; + unsigned int value, v; - v = (png_uint_16)(((png_uint_16)(*bp) << 8) + *(bp + 1)); + v = png_get_uint_16(bp); value = 0; for (j = shift_start[c]; j > -shift_dec[c]; j -= shift_dec[c]) { if (j > 0) - value |= (png_uint_16)((v << j) & (png_uint_16)0xffff); + value |= v << j; else - value |= (png_uint_16)((v >> (-j)) & (png_uint_16)0xffff); + value |= v >> (-j); } - *bp++ = (png_byte)(value >> 8); + *bp++ = (png_byte)((value >> 8) & 0xff); *bp++ = (png_byte)(value & 0xff); } } @@ -405,7 +333,7 @@ #endif #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_swap_alpha"); @@ -453,7 +381,7 @@ *(dp++) = save[1]; } } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ +#endif /* WRITE_16BIT */ } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -492,14 +420,14 @@ *(dp++) = save[1]; } } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ +#endif /* WRITE_16BIT */ } } } #endif #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -void /* PRIVATE */ +static void png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_invert_alpha"); @@ -549,7 +477,7 @@ *(dp++) = (png_byte)(255 - *(sp++)); } } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ +#endif /* WRITE_16BIT */ } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -587,75 +515,88 @@ *(dp++) = (png_byte)(255 - *(sp++)); } } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ +#endif /* WRITE_16BIT */ } } } #endif -#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing */ +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ void /* PRIVATE */ -png_do_write_intrapixel(png_row_infop row_info, png_bytep row) +png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) { - png_debug(1, "in png_do_write_intrapixel"); + png_debug(1, "in png_do_write_transformations"); + + if (png_ptr == NULL) + return; - if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) - { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + if (png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* User write transform + function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; - - else - return; +#ifdef PNG_WRITE_FILLER_SUPPORTED + if ((png_ptr->transformations & PNG_FILLER) != 0) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); +#endif - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((*rp - *(rp + 1)) & 0xff); - *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff); - } - } +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif -#ifdef PNG_WRITE_16BIT_SUPPORTED - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; +#ifdef PNG_WRITE_PACK_SUPPORTED + if ((png_ptr->transformations & PNG_PACK) != 0) + png_do_pack(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; +#ifdef PNG_WRITE_SWAP_SUPPORTED +# ifdef PNG_16BIT_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + png_do_swap(row_info, png_ptr->row_buf + 1); +# endif +#endif - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; - - else - return; +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if ((png_ptr->transformations & PNG_SHIFT) != 0) + png_do_shift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp + 1) = (png_byte)(red & 0xff); - *(rp + 4) = (png_byte)((blue >> 8) & 0xff); - *(rp + 5) = (png_byte)(blue & 0xff); - } - } -#endif /* PNG_WRITE_16BIT_SUPPORTED */ - } +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) + png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) + png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_BGR_SUPPORTED + if ((png_ptr->transformations & PNG_BGR) != 0) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_SUPPORTED + if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif } -#endif /* PNG_MNG_FEATURES_SUPPORTED */ -#endif /* PNG_WRITE_SUPPORTED */ +#endif /* WRITE_TRANSFORMS */ +#endif /* WRITE */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwutil.c --- a/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwutil.c Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/share/native/libsplashscreen/libpng/pngwutil.c Fri Apr 17 10:24:46 2015 -0700 @@ -29,8 +29,8 @@ * However, the following notice accompanied the original version of this * file and, per its terms, should not be removed: * - * Last changed in libpng 1.5.4 [July 7, 2011] - * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * Last changed in libpng 1.6.15 [November 20, 2014] + * Copyright (c) 1998-2014 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * @@ -57,23 +57,6 @@ buf[3] = (png_byte)(i & 0xff); } -#ifdef PNG_SAVE_INT_32_SUPPORTED -/* The png_save_int_32 function assumes integers are stored in two's - * complement format. If this isn't the case, then this routine needs to - * be modified to write data in two's complement format. Note that, - * the following works correctly even if png_int_32 has more than 32 bits - * (compare the more complex code required on read for sign extention.) - */ -void PNGAPI -png_save_int_32(png_bytep buf, png_int_32 i) -{ - buf[0] = (png_byte)((i >> 24) & 0xff); - buf[1] = (png_byte)((i >> 16) & 0xff); - buf[2] = (png_byte)((i >> 8) & 0xff); - buf[3] = (png_byte)(i & 0xff); -} -#endif - /* Place a 16-bit number into a buffer in PNG byte order. * The parameter is declared unsigned int, not png_uint_16, * just to avoid potential problems on pre-ANSI C compilers. @@ -93,7 +76,7 @@ * bytes have already been written. */ void PNGAPI -png_write_sig(png_structp png_ptr) +png_write_sig(png_structrp png_ptr) { png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; @@ -110,39 +93,20 @@ png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; } -/* Write a PNG chunk all at once. The type is an array of ASCII characters - * representing the chunk name. The array must be at least 4 bytes in - * length, and does not need to be null terminated. To be safe, pass the - * pre-defined chunk names here, and if you need a new one, define it - * where the others are defined. The length is the length of the data. - * All the data must be present. If that is not possible, use the - * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() - * functions instead. - */ -void PNGAPI -png_write_chunk(png_structp png_ptr, png_const_bytep chunk_name, - png_const_bytep data, png_size_t length) -{ - if (png_ptr == NULL) - return; - - png_write_chunk_start(png_ptr, chunk_name, (png_uint_32)length); - png_write_chunk_data(png_ptr, data, (png_size_t)length); - png_write_chunk_end(png_ptr); -} - /* Write the start of a PNG chunk. The type is the chunk type. * The total_length is the sum of the lengths of all the data you will be * passing in png_write_chunk_data(). */ -void PNGAPI -png_write_chunk_start(png_structp png_ptr, png_const_bytep chunk_name, +static void +png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name, png_uint_32 length) { png_byte buf[8]; - png_debug2(0, "Writing %s chunk, length = %lu", chunk_name, - (unsigned long)length); +#if defined(PNG_DEBUG) && (PNG_DEBUG > 0) + PNG_CSTRING_FROM_CHUNK(buf, chunk_name); + png_debug2(0, "Writing %s chunk, length = %lu", buf, (unsigned long)length); +#endif if (png_ptr == NULL) return; @@ -156,16 +120,16 @@ /* Write the length and the chunk name */ png_save_uint_32(buf, length); - png_memcpy(buf + 4, chunk_name, 4); - png_write_data(png_ptr, buf, (png_size_t)8); + png_save_uint_32(buf + 4, chunk_name); + png_write_data(png_ptr, buf, 8); /* Put the chunk name into png_ptr->chunk_name */ - png_memcpy(png_ptr->chunk_name, chunk_name, 4); + png_ptr->chunk_name = chunk_name; /* Reset the crc and run it over the chunk name */ png_reset_crc(png_ptr); - png_calculate_crc(png_ptr, chunk_name, 4); + png_calculate_crc(png_ptr, buf + 4, 4); #ifdef PNG_IO_STATE_SUPPORTED /* Inform the I/O callback that chunk data will (possibly) be written. @@ -175,13 +139,20 @@ #endif } -/* Write the data of a PNG chunk started with png_write_chunk_start(). +void PNGAPI +png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, + png_uint_32 length) +{ + png_write_chunk_header(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), length); +} + +/* Write the data of a PNG chunk started with png_write_chunk_header(). * Note that multiple calls to this function are allowed, and that the * sum of the lengths from these calls *must* add up to the total_length - * given to png_write_chunk_start(). + * given to png_write_chunk_header(). */ void PNGAPI -png_write_chunk_data(png_structp png_ptr, png_const_bytep data, +png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) { /* Write the data, and run the CRC over it */ @@ -193,15 +164,15 @@ png_write_data(png_ptr, data, length); /* Update the CRC after writing the data, - * in case that the user I/O routine alters it. + * in case the user I/O routine alters it. */ png_calculate_crc(png_ptr, data, length); } } -/* Finish a chunk started with png_write_chunk_start(). */ +/* Finish a chunk started with png_write_chunk_header(). */ void PNGAPI -png_write_chunk_end(png_structp png_ptr) +png_write_chunk_end(png_structrp png_ptr) { png_byte buf[4]; @@ -220,468 +191,601 @@ png_write_data(png_ptr, buf, (png_size_t)4); } -/* Initialize the compressor for the appropriate type of compression. */ +/* Write a PNG chunk all at once. The type is an array of ASCII characters + * representing the chunk name. The array must be at least 4 bytes in + * length, and does not need to be null terminated. To be safe, pass the + * pre-defined chunk names here, and if you need a new one, define it + * where the others are defined. The length is the length of the data. + * All the data must be present. If that is not possible, use the + * png_write_chunk_start(), png_write_chunk_data(), and png_write_chunk_end() + * functions instead. + */ static void -png_zlib_claim(png_structp png_ptr, png_uint_32 state) +png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, + png_const_bytep data, png_size_t length) { - if (!(png_ptr->zlib_state & PNG_ZLIB_IN_USE)) + if (png_ptr == NULL) + return; + + /* On 64 bit architectures 'length' may not fit in a png_uint_32. */ + if (length > PNG_UINT_31_MAX) + png_error(png_ptr, "length exceeds PNG maximum"); + + png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); + png_write_chunk_data(png_ptr, data, length); + png_write_chunk_end(png_ptr); +} + +/* This is the API that calls the internal function above. */ +void PNGAPI +png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, + png_const_bytep data, png_size_t length) +{ + png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, + length); +} + +/* This is used below to find the size of an image to pass to png_deflate_claim, + * so it only needs to be accurate if the size is less than 16384 bytes (the + * point at which a lower LZ window size can be used.) + */ +static png_alloc_size_t +png_image_size(png_structrp png_ptr) +{ + /* Only return sizes up to the maximum of a png_uint_32; do this by limiting + * the width and height used to 15 bits. + */ + png_uint_32 h = png_ptr->height; + + if (png_ptr->rowbytes < 32768 && h < 32768) { - /* If already initialized for 'state' do not re-init. */ - if (png_ptr->zlib_state != state) + if (png_ptr->interlaced != 0) { - int ret = Z_OK; - png_const_charp who = "-"; - - /* If actually initialized for another state do a deflateEnd. */ - if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED) - { - ret = deflateEnd(&png_ptr->zstream); - who = "end"; - png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED; - } - - /* zlib itself detects an incomplete state on deflateEnd */ - if (ret == Z_OK) switch (state) + /* Interlacing makes the image larger because of the replication of + * both the filter byte and the padding to a byte boundary. + */ + png_uint_32 w = png_ptr->width; + unsigned int pd = png_ptr->pixel_depth; + png_alloc_size_t cb_base; + int pass; + + for (cb_base=0, pass=0; pass<=6; ++pass) { -# ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED - case PNG_ZLIB_FOR_TEXT: - ret = deflateInit2(&png_ptr->zstream, - png_ptr->zlib_text_level, png_ptr->zlib_text_method, - png_ptr->zlib_text_window_bits, - png_ptr->zlib_text_mem_level, png_ptr->zlib_text_strategy); - who = "text"; - break; -# endif - - case PNG_ZLIB_FOR_IDAT: - ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, - png_ptr->zlib_method, png_ptr->zlib_window_bits, - png_ptr->zlib_mem_level, png_ptr->zlib_strategy); - who = "IDAT"; - break; - - default: - png_error(png_ptr, "invalid zlib state"); + png_uint_32 pw = PNG_PASS_COLS(w, pass); + + if (pw > 0) + cb_base += (PNG_ROWBYTES(pd, pw)+1) * PNG_PASS_ROWS(h, pass); } - if (ret == Z_OK) - png_ptr->zlib_state = state; - - else /* an error in deflateEnd or deflateInit2 */ - { - size_t pos = 0; - char msg[64]; - - pos = png_safecat(msg, sizeof msg, pos, - "zlib failed to initialize compressor ("); - pos = png_safecat(msg, sizeof msg, pos, who); - - switch (ret) - { - case Z_VERSION_ERROR: - pos = png_safecat(msg, sizeof msg, pos, ") version error"); - break; - - case Z_STREAM_ERROR: - pos = png_safecat(msg, sizeof msg, pos, ") stream error"); - break; - - case Z_MEM_ERROR: - pos = png_safecat(msg, sizeof msg, pos, ") memory error"); - break; - - default: - pos = png_safecat(msg, sizeof msg, pos, ") unknown error"); - break; - } - - png_error(png_ptr, msg); - } + return cb_base; } - /* Here on success, claim the zstream: */ - png_ptr->zlib_state |= PNG_ZLIB_IN_USE; + else + return (png_ptr->rowbytes+1) * h; } else - png_error(png_ptr, "zstream already in use (internal error)"); + return 0xffffffffU; } -/* The opposite: release the stream. It is also reset, this API will warn on - * error but will not fail. - */ +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* This is the code to hack the first two bytes of the deflate stream (the + * deflate header) to correct the windowBits value to match the actual data + * size. Note that the second argument is the *uncompressed* size but the + * first argument is the *compressed* data (and it must be deflate + * compressed.) + */ static void -png_zlib_release(png_structp png_ptr) +optimize_cmf(png_bytep data, png_alloc_size_t data_size) { - if (png_ptr->zlib_state & PNG_ZLIB_IN_USE) + /* Optimize the CMF field in the zlib stream. The resultant zlib stream is + * still compliant to the stream specification. + */ + if (data_size <= 16384) /* else windowBits must be 15 */ { - int ret = deflateReset(&png_ptr->zstream); - - png_ptr->zlib_state &= ~PNG_ZLIB_IN_USE; - - if (ret != Z_OK) + unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) { - png_const_charp err; - PNG_WARNING_PARAMETERS(p) - - switch (ret) + unsigned int z_cinfo; + unsigned int half_z_window_size; + + z_cinfo = z_cmf >> 4; + half_z_window_size = 1U << (z_cinfo + 7); + + if (data_size <= half_z_window_size) /* else no change */ { - case Z_VERSION_ERROR: - err = "version"; - break; - - case Z_STREAM_ERROR: - err = "stream"; - break; - - case Z_MEM_ERROR: - err = "memory"; - break; - - default: - err = "unknown"; - break; + unsigned int tmp; + + do + { + half_z_window_size >>= 1; + --z_cinfo; + } + while (z_cinfo > 0 && data_size <= half_z_window_size); + + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + + data[0] = (png_byte)z_cmf; + tmp = data[1] & 0xe0; + tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; + data[1] = (png_byte)tmp; } - - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, ret); - png_warning_parameter(p, 2, err); - - if (png_ptr->zstream.msg) - err = png_ptr->zstream.msg; - else - err = "[no zlib message]"; - - png_warning_parameter(p, 3, err); - - png_formatted_warning(png_ptr, p, - "zlib failed to reset compressor: @1(@2): @3"); } } - - else - png_warning(png_ptr, "zstream not in use (internal error)"); +} +#endif /* WRITE_OPTIMIZE_CMF */ + +/* Initialize the compressor for the appropriate type of compression. */ +static int +png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, + png_alloc_size_t data_size) +{ + if (png_ptr->zowner != 0) + { +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) + char msg[64]; + + PNG_STRING_FROM_CHUNK(msg, owner); + msg[4] = ':'; + msg[5] = ' '; + PNG_STRING_FROM_CHUNK(msg+6, png_ptr->zowner); + /* So the message that results is " using zstream"; this is an + * internal error, but is very useful for debugging. i18n requirements + * are minimal. + */ + (void)png_safecat(msg, (sizeof msg), 10, " using zstream"); +#endif +#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_warning(png_ptr, msg); + + /* Attempt sane error recovery */ + if (png_ptr->zowner == png_IDAT) /* don't steal from IDAT */ + { + png_ptr->zstream.msg = PNGZ_MSG_CAST("in use by IDAT"); + return Z_STREAM_ERROR; + } + + png_ptr->zowner = 0; +#else + png_error(png_ptr, msg); +#endif + } + + { + int level = png_ptr->zlib_level; + int method = png_ptr->zlib_method; + int windowBits = png_ptr->zlib_window_bits; + int memLevel = png_ptr->zlib_mem_level; + int strategy; /* set below */ + int ret; /* zlib return code */ + + if (owner == png_IDAT) + { + if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0) + strategy = png_ptr->zlib_strategy; + + else if (png_ptr->do_filter != PNG_FILTER_NONE) + strategy = PNG_Z_DEFAULT_STRATEGY; + + else + strategy = PNG_Z_DEFAULT_NOFILTER_STRATEGY; + } + + else + { +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + level = png_ptr->zlib_text_level; + method = png_ptr->zlib_text_method; + windowBits = png_ptr->zlib_text_window_bits; + memLevel = png_ptr->zlib_text_mem_level; + strategy = png_ptr->zlib_text_strategy; +#else + /* If customization is not supported the values all come from the + * IDAT values except for the strategy, which is fixed to the + * default. (This is the pre-1.6.0 behavior too, although it was + * implemented in a very different way.) + */ + strategy = Z_DEFAULT_STRATEGY; +#endif + } + + /* Adjust 'windowBits' down if larger than 'data_size'; to stop this + * happening just pass 32768 as the data_size parameter. Notice that zlib + * requires an extra 262 bytes in the window in addition to the data to be + * able to see the whole of the data, so if data_size+262 takes us to the + * next windowBits size we need to fix up the value later. (Because even + * though deflate needs the extra window, inflate does not!) + */ + if (data_size <= 16384) + { + /* IMPLEMENTATION NOTE: this 'half_window_size' stuff is only here to + * work round a Microsoft Visual C misbehavior which, contrary to C-90, + * widens the result of the following shift to 64-bits if (and, + * apparently, only if) it is used in a test. + */ + unsigned int half_window_size = 1U << (windowBits-1); + + while (data_size + 262 <= half_window_size) + { + half_window_size >>= 1; + --windowBits; + } + } + + /* Check against the previous initialized values, if any. */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 && + (png_ptr->zlib_set_level != level || + png_ptr->zlib_set_method != method || + png_ptr->zlib_set_window_bits != windowBits || + png_ptr->zlib_set_mem_level != memLevel || + png_ptr->zlib_set_strategy != strategy)) + { + if (deflateEnd(&png_ptr->zstream) != Z_OK) + png_warning(png_ptr, "deflateEnd failed (ignored)"); + + png_ptr->flags &= ~PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* For safety clear out the input and output pointers (currently zlib + * doesn't use them on Init, but it might in the future). + */ + png_ptr->zstream.next_in = NULL; + png_ptr->zstream.avail_in = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->zstream.avail_out = 0; + + /* Now initialize if required, setting the new parameters, otherwise just + * to a simple reset to the previous parameters. + */ + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + ret = deflateReset(&png_ptr->zstream); + + else + { + ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, + memLevel, strategy); + + if (ret == Z_OK) + png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; + } + + /* The return code is from either deflateReset or deflateInit2; they have + * pretty much the same set of error codes. + */ + if (ret == Z_OK) + png_ptr->zowner = owner; + + else + png_zstream_error(png_ptr, ret); + + return ret; + } +} + +/* Clean up (or trim) a linked list of compression buffers. */ +void /* PRIVATE */ +png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) +{ + png_compression_bufferp list = *listp; + + if (list != NULL) + { + *listp = NULL; + + do + { + png_compression_bufferp next = list->next; + + png_free(png_ptr, list); + list = next; + } + while (list != NULL); + } } #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED /* This pair of functions encapsulates the operation of (a) compressing a * text string, and (b) issuing it later as a series of chunk data writes. * The compression_state structure is shared context for these functions - * set up by the caller in order to make the whole mess thread-safe. + * set up by the caller to allow access to the relevant local variables. + * + * compression_buffer (new in 1.6.0) is just a linked list of zbuffer_size + * temporary buffers. From 1.6.0 it is retained in png_struct so that it will + * be correctly freed in the event of a write error (previous implementations + * just leaked memory.) */ - typedef struct { - png_const_bytep input; /* The uncompressed input data */ - png_size_t input_len; /* Its length */ - int num_output_ptr; /* Number of output pointers used */ - int max_output_ptr; /* Size of output_ptr */ - png_bytep *output_ptr; /* Array of pointers to output */ + png_const_bytep input; /* The uncompressed input data */ + png_alloc_size_t input_len; /* Its length */ + png_uint_32 output_len; /* Final compressed length */ + png_byte output[1024]; /* First block of output */ } compression_state; -/* Compress given text into storage in the png_ptr structure */ -static int /* PRIVATE */ -png_text_compress(png_structp png_ptr, - png_const_charp text, png_size_t text_len, int compression, - compression_state *comp) +static void +png_text_compress_init(compression_state *comp, png_const_bytep input, + png_alloc_size_t input_len) +{ + comp->input = input; + comp->input_len = input_len; + comp->output_len = 0; +} + +/* Compress the data in the compression state input */ +static int +png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, + compression_state *comp, png_uint_32 prefix_len) { int ret; - comp->num_output_ptr = 0; - comp->max_output_ptr = 0; - comp->output_ptr = NULL; - comp->input = NULL; - comp->input_len = text_len; - - /* We may just want to pass the text right through */ - if (compression == PNG_TEXT_COMPRESSION_NONE) - { - comp->input = (png_const_bytep)text; - return((int)text_len); - } - - if (compression >= PNG_TEXT_COMPRESSION_LAST) - { - PNG_WARNING_PARAMETERS(p) - - png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, - compression); - png_formatted_warning(png_ptr, p, "Unknown compression type @1"); - } - - /* We can't write the chunk until we find out how much data we have, - * which means we need to run the compressor first and save the - * output. This shouldn't be a problem, as the vast majority of - * comments should be reasonable, but we will set up an array of - * malloc'd pointers to be sure. + /* To find the length of the output it is necessary to first compress the + * input. The result is buffered rather than using the two-pass algorithm + * that is used on the inflate side; deflate is assumed to be slower and a + * PNG writer is assumed to have more memory available than a PNG reader. * - * If we knew the application was well behaved, we could simplify this - * greatly by assuming we can always malloc an output buffer large - * enough to hold the compressed text ((1001 * text_len / 1000) + 12) - * and malloc this directly. The only time this would be a bad idea is - * if we can't malloc more than 64K and we have 64K of random input - * data, or if the input string is incredibly large (although this - * wouldn't cause a failure, just a slowdown due to swapping). + * IMPLEMENTATION NOTE: the zlib API deflateBound() can be used to find an + * upper limit on the output size, but it is always bigger than the input + * size so it is likely to be more efficient to use this linked-list + * approach. + */ + ret = png_deflate_claim(png_ptr, chunk_name, comp->input_len); + + if (ret != Z_OK) + return ret; + + /* Set up the compression buffers, we need a loop here to avoid overflowing a + * uInt. Use ZLIB_IO_MAX to limit the input. The output is always limited + * by the output buffer size, so there is no need to check that. Since this + * is ANSI-C we know that an 'int', hence a uInt, is always at least 16 bits + * in size. */ - png_zlib_claim(png_ptr, PNG_ZLIB_FOR_TEXT); - - /* Set up the compression buffers */ - /* TODO: the following cast hides a potential overflow problem. */ - png_ptr->zstream.avail_in = (uInt)text_len; - - /* NOTE: assume zlib doesn't overwrite the input */ - png_ptr->zstream.next_in = (Bytef *)text; - png_ptr->zstream.avail_out = png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; - - /* This is the same compression loop as in png_write_row() */ - do { - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); - - if (ret != Z_OK) + png_compression_bufferp *end = &png_ptr->zbuffer_list; + png_alloc_size_t input_len = comp->input_len; /* may be zero! */ + png_uint_32 output_len; + + /* zlib updates these for us: */ + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(comp->input); + png_ptr->zstream.avail_in = 0; /* Set below */ + png_ptr->zstream.next_out = comp->output; + png_ptr->zstream.avail_out = (sizeof comp->output); + + output_len = png_ptr->zstream.avail_out; + + do { - /* Error */ - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - - else - png_error(png_ptr, "zlib error"); - } - - /* Check to see if we need more room */ - if (!(png_ptr->zstream.avail_out)) - { - /* Make sure the output array has room */ - if (comp->num_output_ptr >= comp->max_output_ptr) + uInt avail_in = ZLIB_IO_MAX; + + if (avail_in > input_len) + avail_in = (uInt)input_len; + + input_len -= avail_in; + + png_ptr->zstream.avail_in = avail_in; + + if (png_ptr->zstream.avail_out == 0) { - int old_max; - - old_max = comp->max_output_ptr; - comp->max_output_ptr = comp->num_output_ptr + 4; - if (comp->output_ptr != NULL) + png_compression_buffer *next; + + /* Chunk data is limited to 2^31 bytes in length, so the prefix + * length must be counted here. + */ + if (output_len + prefix_len > PNG_UINT_31_MAX) + { + ret = Z_MEM_ERROR; + break; + } + + /* Need a new (malloc'ed) buffer, but there may be one present + * already. + */ + next = *end; + if (next == NULL) { - png_bytepp old_ptr; - - old_ptr = comp->output_ptr; - - comp->output_ptr = (png_bytepp)png_malloc(png_ptr, - (png_alloc_size_t) - (comp->max_output_ptr * png_sizeof(png_charpp))); - - png_memcpy(comp->output_ptr, old_ptr, old_max - * png_sizeof(png_charp)); - - png_free(png_ptr, old_ptr); + next = png_voidcast(png_compression_bufferp, png_malloc_base + (png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + + if (next == NULL) + { + ret = Z_MEM_ERROR; + break; + } + + /* Link in this buffer (so that it will be freed later) */ + next->next = NULL; + *end = next; } - else - comp->output_ptr = (png_bytepp)png_malloc(png_ptr, - (png_alloc_size_t) - (comp->max_output_ptr * png_sizeof(png_charp))); + + png_ptr->zstream.next_out = next->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; + output_len += png_ptr->zstream.avail_out; + + /* Move 'end' to the next buffer pointer. */ + end = &next->next; } - /* Save the data */ - comp->output_ptr[comp->num_output_ptr] = - (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)png_ptr->zbuf_size); - - png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, - png_ptr->zbuf_size); - - comp->num_output_ptr++; - - /* and reset the buffer */ - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; + /* Compress the data */ + ret = deflate(&png_ptr->zstream, + input_len > 0 ? Z_NO_FLUSH : Z_FINISH); + + /* Claw back input data that was not consumed (because avail_in is + * reset above every time round the loop). + */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; /* safety */ } - /* Continue until we don't have any more to compress */ - } while (png_ptr->zstream.avail_in); - - /* Finish the compression */ - do - { - /* Tell zlib we are finished */ - ret = deflate(&png_ptr->zstream, Z_FINISH); - - if (ret == Z_OK) + while (ret == Z_OK); + + /* There may be some space left in the last output buffer. This needs to + * be subtracted from output_len. + */ + output_len -= png_ptr->zstream.avail_out; + png_ptr->zstream.avail_out = 0; /* safety */ + comp->output_len = output_len; + + /* Now double check the output length, put in a custom message if it is + * too long. Otherwise ensure the z_stream::msg pointer is set to + * something. + */ + if (output_len + prefix_len >= PNG_UINT_31_MAX) { - /* Check to see if we need more room */ - if (!(png_ptr->zstream.avail_out)) - { - /* Check to make sure our output array has room */ - if (comp->num_output_ptr >= comp->max_output_ptr) - { - int old_max; - - old_max = comp->max_output_ptr; - comp->max_output_ptr = comp->num_output_ptr + 4; - if (comp->output_ptr != NULL) - { - png_bytepp old_ptr; - - old_ptr = comp->output_ptr; - - /* This could be optimized to realloc() */ - comp->output_ptr = (png_bytepp)png_malloc(png_ptr, - (png_alloc_size_t)(comp->max_output_ptr * - png_sizeof(png_charp))); - - png_memcpy(comp->output_ptr, old_ptr, - old_max * png_sizeof(png_charp)); - - png_free(png_ptr, old_ptr); - } - - else - comp->output_ptr = (png_bytepp)png_malloc(png_ptr, - (png_alloc_size_t)(comp->max_output_ptr * - png_sizeof(png_charp))); - } - - /* Save the data */ - comp->output_ptr[comp->num_output_ptr] = - (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)png_ptr->zbuf_size); - - png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf, - png_ptr->zbuf_size); - - comp->num_output_ptr++; - - /* and reset the buffer pointers */ - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; - } + png_ptr->zstream.msg = PNGZ_MSG_CAST("compressed data too long"); + ret = Z_MEM_ERROR; } - else if (ret != Z_STREAM_END) + + else + png_zstream_error(png_ptr, ret); + + /* Reset zlib for another zTXt/iTXt or image data */ + png_ptr->zowner = 0; + + /* The only success case is Z_STREAM_END, input_len must be 0; if not this + * is an internal error. + */ + if (ret == Z_STREAM_END && input_len == 0) { - /* We got an error */ - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - - else - png_error(png_ptr, "zlib error"); +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + /* Fix up the deflate header, if required */ + optimize_cmf(comp->output, comp->input_len); +#endif + /* But Z_OK is returned, not Z_STREAM_END; this allows the claim + * function above to return Z_STREAM_END on an error (though it never + * does in the current versions of zlib.) + */ + return Z_OK; } - } while (ret != Z_STREAM_END); - - /* Text length is number of buffers plus last buffer */ - text_len = png_ptr->zbuf_size * comp->num_output_ptr; - - if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) - text_len += png_ptr->zbuf_size - (png_size_t)png_ptr->zstream.avail_out; - - return((int)text_len); + + else + return ret; + } } /* Ship the compressed text out via chunk writes */ -static void /* PRIVATE */ -png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) +static void +png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) { - int i; - - /* Handle the no-compression case */ - if (comp->input) + png_uint_32 output_len = comp->output_len; + png_const_bytep output = comp->output; + png_uint_32 avail = (sizeof comp->output); + png_compression_buffer *next = png_ptr->zbuffer_list; + + for (;;) { - png_write_chunk_data(png_ptr, comp->input, comp->input_len); - - return; + if (avail > output_len) + avail = output_len; + + png_write_chunk_data(png_ptr, output, avail); + + output_len -= avail; + + if (output_len == 0 || next == NULL) + break; + + avail = png_ptr->zbuffer_size; + output = next->output; + next = next->next; } -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - if (comp->input_len >= 2 && comp->input_len < 16384) + /* This is an internal error; 'next' must have been NULL! */ + if (output_len > 0) + png_error(png_ptr, "error writing ancillary chunked compressed data"); +} +#endif /* WRITE_COMPRESSED_TEXT */ + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The 'new_key' buffer must be 80 characters in size (for the keyword plus a + * trailing '\0'). If this routine returns 0 then there was no keyword, or a + * valid one could not be generated, and the caller must png_error. + */ +static png_uint_32 +png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) +{ + png_const_charp orig_key = key; + png_uint_32 key_len = 0; + int bad_character = 0; + int space = 1; + + png_debug(1, "in png_check_keyword"); + + if (key == NULL) { - unsigned int z_cmf; /* zlib compression method and flags */ - - /* Optimize the CMF field in the zlib stream. This hack of the zlib - * stream is compliant to the stream specification. - */ - - if (comp->num_output_ptr) - z_cmf = comp->output_ptr[0][0]; - else - z_cmf = png_ptr->zbuf[0]; - - if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + *new_key = 0; + return 0; + } + + while (*key && key_len < 79) + { + png_byte ch = (png_byte)(0xff & *key++); + + if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) + *new_key++ = ch, ++key_len, space = 0; + + else if (space == 0) { - unsigned int z_cinfo; - unsigned int half_z_window_size; - png_size_t uncompressed_text_size = comp->input_len; - - z_cinfo = z_cmf >> 4; - half_z_window_size = 1 << (z_cinfo + 7); - - while (uncompressed_text_size <= half_z_window_size && - half_z_window_size >= 256) - { - z_cinfo--; - half_z_window_size >>= 1; - } - - z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); - - if (comp->num_output_ptr) - { - - if (comp->output_ptr[0][0] != z_cmf) - { - int tmp; - - comp->output_ptr[0][0] = (png_byte)z_cmf; - tmp = comp->output_ptr[0][1] & 0xe0; - tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; - comp->output_ptr[0][1] = (png_byte)tmp; - } - } - else - { - int tmp; - - png_ptr->zbuf[0] = (png_byte)z_cmf; - tmp = png_ptr->zbuf[1] & 0xe0; - tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; - png_ptr->zbuf[1] = (png_byte)tmp; - } + /* A space or an invalid character when one wasn't seen immediately + * before; output just a space. + */ + *new_key++ = 32, ++key_len, space = 1; + + /* If the character was not a space then it is invalid. */ + if (ch != 32) + bad_character = ch; } - else - png_error(png_ptr, - "Invalid zlib compression method or flags in non-IDAT chunk"); + else if (bad_character == 0) + bad_character = ch; /* just skip it, record the first error */ } -#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ - - /* Write saved output buffers, if any */ - for (i = 0; i < comp->num_output_ptr; i++) + + if (key_len > 0 && space != 0) /* trailing space */ { - png_write_chunk_data(png_ptr, comp->output_ptr[i], - (png_size_t)png_ptr->zbuf_size); - - png_free(png_ptr, comp->output_ptr[i]); + --key_len, --new_key; + if (bad_character == 0) + bad_character = 32; } - if (comp->max_output_ptr != 0) - png_free(png_ptr, comp->output_ptr); - - /* Write anything left in zbuf */ - if (png_ptr->zstream.avail_out < (png_uint_32)png_ptr->zbuf_size) - png_write_chunk_data(png_ptr, png_ptr->zbuf, - (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out)); - - /* Reset zlib for another zTXt/iTXt or image data */ - png_zlib_release(png_ptr); + /* Terminate the keyword */ + *new_key = 0; + + if (key_len == 0) + return 0; + +#ifdef PNG_WARNINGS_SUPPORTED + /* Try to only output one warning per keyword: */ + if (*key != 0) /* keyword too long */ + png_warning(png_ptr, "keyword truncated"); + + else if (bad_character != 0) + { + PNG_WARNING_PARAMETERS(p) + + png_warning_parameter(p, 1, orig_key); + png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); + + png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); + } +#endif /* WARNINGS */ + + return key_len; } -#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ +#endif /* WRITE_TEXT || WRITE_pCAL || WRITE_iCCP || WRITE_sPLT */ /* Write the IHDR chunk, and update the png_struct with the necessary * information. Note that the rest of this code depends upon this * information being correct. */ void /* PRIVATE */ -png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, +png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, int compression_type, int filter_type, int interlace_type) { - PNG_IHDR; - png_byte buf[13]; /* Buffer to store the IHDR info */ png_debug(1, "in png_write_IHDR"); @@ -772,8 +876,8 @@ */ if ( #ifdef PNG_MNG_FEATURES_SUPPORTED - !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && - ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) && (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && @@ -823,14 +927,9 @@ buf[12] = (png_byte)interlace_type; /* Write the chunk */ - png_write_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); - - /* Initialize zlib with PNG info */ - png_ptr->zstream.zalloc = png_zalloc; - png_ptr->zstream.zfree = png_zfree; - png_ptr->zstream.opaque = (voidpf)png_ptr; - - if (!(png_ptr->do_filter)) + png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); + + if ((png_ptr->do_filter) == PNG_NO_FILTERS) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || png_ptr->bit_depth < 8) @@ -840,55 +939,6 @@ png_ptr->do_filter = PNG_ALL_FILTERS; } - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY)) - { - if (png_ptr->do_filter != PNG_FILTER_NONE) - png_ptr->zlib_strategy = Z_FILTERED; - - else - png_ptr->zlib_strategy = Z_DEFAULT_STRATEGY; - } - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_LEVEL)) - png_ptr->zlib_level = Z_DEFAULT_COMPRESSION; - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL)) - png_ptr->zlib_mem_level = 8; - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS)) - png_ptr->zlib_window_bits = 15; - - if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) - png_ptr->zlib_method = 8; - -#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED -#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_STRATEGY)) - png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY; - - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_LEVEL)) - png_ptr->zlib_text_level = png_ptr->zlib_level; - - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL)) - png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level; - - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS)) - png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits; - - if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_METHOD)) - png_ptr->zlib_text_method = png_ptr->zlib_method; -#else - png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY; - png_ptr->zlib_text_level = png_ptr->zlib_level; - png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level; - png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits; - png_ptr->zlib_text_method = png_ptr->zlib_method; -#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ -#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ - - /* Record that the compressor has not yet been initialized. */ - png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED; - png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */ } @@ -897,10 +947,9 @@ * structure. */ void /* PRIVATE */ -png_write_PLTE(png_structp png_ptr, png_const_colorp palette, +png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, png_uint_32 num_pal) { - PNG_PLTE; png_uint_32 i; png_const_colorp pal_ptr; png_byte buf[3]; @@ -909,7 +958,7 @@ if (( #ifdef PNG_MNG_FEATURES_SUPPORTED - !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 && #endif num_pal == 0) || num_pal > 256) { @@ -925,7 +974,7 @@ } } - if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) + if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) { png_warning(png_ptr, "Ignoring request to write a PLTE chunk in grayscale PNG"); @@ -936,7 +985,7 @@ png_ptr->num_palette = (png_uint_16)num_pal; png_debug1(3, "num_palette = %d", png_ptr->num_palette); - png_write_chunk_start(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); + png_write_chunk_header(png_ptr, png_PLTE, (png_uint_32)(num_pal * 3)); #ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0, pal_ptr = palette; i < num_pal; i++, pal_ptr++) @@ -966,127 +1015,192 @@ png_ptr->mode |= PNG_HAVE_PLTE; } -/* Write an IDAT chunk */ +/* This is similar to png_text_compress, above, except that it does not require + * all of the data at once and, instead of buffering the compressed result, + * writes it as IDAT chunks. Unlike png_text_compress it *can* png_error out + * because it calls the write interface. As a result it does its own error + * reporting and does not return an error code. In the event of error it will + * just call png_error. The input data length may exceed 32-bits. The 'flush' + * parameter is exactly the same as that to deflate, with the following + * meanings: + * + * Z_NO_FLUSH: normal incremental output of compressed data + * Z_SYNC_FLUSH: do a SYNC_FLUSH, used by png_write_flush + * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up + * + * The routine manages the acquire and release of the png_ptr->zstream by + * checking and (at the end) clearing png_ptr->zowner; it does some sanity + * checks on the 'mode' flags while doing this. + */ void /* PRIVATE */ -png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) +png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, + png_alloc_size_t input_len, int flush) { - PNG_IDAT; - - png_debug(1, "in png_write_IDAT"); - -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - if (!(png_ptr->mode & PNG_HAVE_IDAT) && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + if (png_ptr->zowner != png_IDAT) { - /* Optimize the CMF field in the zlib stream. This hack of the zlib - * stream is compliant to the stream specification. + /* First time. Ensure we have a temporary buffer for compression and + * trim the buffer list if it has more than one entry to free memory. + * If 'WRITE_COMPRESSED_TEXT' is not set the list will never have been + * created at this point, but the check here is quick and safe. */ - unsigned int z_cmf = data[0]; /* zlib compression method and flags */ - - if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + if (png_ptr->zbuffer_list == NULL) { - /* Avoid memory underflows and multiplication overflows. - * - * The conditions below are practically always satisfied; - * however, they still must be checked. - */ - if (length >= 2 && - png_ptr->height < 16384 && png_ptr->width < 16384) - { - /* Compute the maximum possible length of the datastream */ - - /* Number of pixels, plus for each row a filter byte - * and possibly a padding byte, so increase the maximum - * size to account for these. - */ - unsigned int z_cinfo; - unsigned int half_z_window_size; - png_uint_32 uncompressed_idat_size = png_ptr->height * - ((png_ptr->width * - png_ptr->channels * png_ptr->bit_depth + 15) >> 3); - - /* If it's interlaced, each block of 8 rows is sent as up to - * 14 rows, i.e., 6 additional rows, each with a filter byte - * and possibly a padding byte - */ - if (png_ptr->interlaced) - uncompressed_idat_size += ((png_ptr->height + 7)/8) * - (png_ptr->bit_depth < 8 ? 12 : 6); - - z_cinfo = z_cmf >> 4; - half_z_window_size = 1 << (z_cinfo + 7); - - while (uncompressed_idat_size <= half_z_window_size && - half_z_window_size >= 256) - { - z_cinfo--; - half_z_window_size >>= 1; - } - - z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); - - if (data[0] != z_cmf) - { - int tmp; - data[0] = (png_byte)z_cmf; - tmp = data[1] & 0xe0; - tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; - data[1] = (png_byte)tmp; - } - } + png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, + png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + png_ptr->zbuffer_list->next = NULL; } else - png_error(png_ptr, - "Invalid zlib compression method or flags in IDAT"); + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list->next); + + /* It is a terminal error if we can't claim the zstream. */ + if (png_deflate_claim(png_ptr, png_IDAT, png_image_size(png_ptr)) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + /* The output state is maintained in png_ptr->zstream, so it must be + * initialized here after the claim. + */ + png_ptr->zstream.next_out = png_ptr->zbuffer_list->output; + png_ptr->zstream.avail_out = png_ptr->zbuffer_size; } -#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ - - png_write_chunk(png_ptr, png_IDAT, data, length); - png_ptr->mode |= PNG_HAVE_IDAT; - - /* Prior to 1.5.4 this code was replicated in every caller (except at the - * end, where it isn't technically necessary). Since this function has - * flushed the data we can safely reset the zlib output buffer here. + + /* Now loop reading and writing until all the input is consumed or an error + * terminates the operation. The _out values are maintained across calls to + * this function, but the input must be reset each time. */ - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; + png_ptr->zstream.next_in = PNGZ_INPUT_CAST(input); + png_ptr->zstream.avail_in = 0; /* set below */ + for (;;) + { + int ret; + + /* INPUT: from the row data */ + uInt avail = ZLIB_IO_MAX; + + if (avail > input_len) + avail = (uInt)input_len; /* safe because of the check */ + + png_ptr->zstream.avail_in = avail; + input_len -= avail; + + ret = deflate(&png_ptr->zstream, input_len > 0 ? Z_NO_FLUSH : flush); + + /* Include as-yet unconsumed input */ + input_len += png_ptr->zstream.avail_in; + png_ptr->zstream.avail_in = 0; + + /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note + * that these two zstream fields are preserved across the calls, therefore + * there is no need to set these up on entry to the loop. + */ + if (png_ptr->zstream.avail_out == 0) + { + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size; + + /* Write an IDAT containing the data then reset the buffer. The + * first IDAT may need deflate header optimization. + */ +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->mode |= PNG_HAVE_IDAT; + + png_ptr->zstream.next_out = data; + png_ptr->zstream.avail_out = size; + + /* For SYNC_FLUSH or FINISH it is essential to keep calling zlib with + * the same flush parameter until it has finished output, for NO_FLUSH + * it doesn't matter. + */ + if (ret == Z_OK && flush != Z_NO_FLUSH) + continue; + } + + /* The order of these checks doesn't matter much; it just affects which + * possible error might be detected if multiple things go wrong at once. + */ + if (ret == Z_OK) /* most likely return code! */ + { + /* If all the input has been consumed then just return. If Z_FINISH + * was used as the flush parameter something has gone wrong if we get + * here. + */ + if (input_len == 0) + { + if (flush == Z_FINISH) + png_error(png_ptr, "Z_OK on Z_FINISH with output space"); + + return; + } + } + + else if (ret == Z_STREAM_END && flush == Z_FINISH) + { + /* This is the end of the IDAT data; any pending output must be + * flushed. For small PNG files we may still be at the beginning. + */ + png_bytep data = png_ptr->zbuffer_list->output; + uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; + +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +#endif + + png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_ptr->zstream.avail_out = 0; + png_ptr->zstream.next_out = NULL; + png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; + + png_ptr->zowner = 0; /* Release the stream */ + return; + } + + else + { + /* This is an error condition. */ + png_zstream_error(png_ptr, ret); + png_error(png_ptr, png_ptr->zstream.msg); + } + } } /* Write an IEND chunk */ void /* PRIVATE */ -png_write_IEND(png_structp png_ptr) +png_write_IEND(png_structrp png_ptr) { - PNG_IEND; - png_debug(1, "in png_write_IEND"); - png_write_chunk(png_ptr, png_IEND, NULL, (png_size_t)0); + png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0); png_ptr->mode |= PNG_HAVE_IEND; } #ifdef PNG_WRITE_gAMA_SUPPORTED /* Write a gAMA chunk */ void /* PRIVATE */ -png_write_gAMA_fixed(png_structp png_ptr, png_fixed_point file_gamma) +png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) { - PNG_gAMA; png_byte buf[4]; png_debug(1, "in png_write_gAMA"); /* file_gamma is saved in 1/100,000ths */ png_save_uint_32(buf, (png_uint_32)file_gamma); - png_write_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); + png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); } #endif #ifdef PNG_WRITE_sRGB_SUPPORTED /* Write a sRGB chunk */ void /* PRIVATE */ -png_write_sRGB(png_structp png_ptr, int srgb_intent) +png_write_sRGB(png_structrp png_ptr, int srgb_intent) { - PNG_sRGB; png_byte buf[1]; png_debug(1, "in png_write_sRGB"); @@ -1096,104 +1210,79 @@ "Invalid sRGB rendering intent specified"); buf[0]=(png_byte)srgb_intent; - png_write_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); + png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); } #endif #ifdef PNG_WRITE_iCCP_SUPPORTED /* Write an iCCP chunk */ void /* PRIVATE */ -png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type, - png_const_charp profile, int profile_len) +png_write_iCCP(png_structrp png_ptr, png_const_charp name, + png_const_bytep profile) { - PNG_iCCP; - png_size_t name_len; - png_charp new_name; + png_uint_32 name_len; + png_uint_32 profile_len; + png_byte new_name[81]; /* 1 byte for the compression byte */ compression_state comp; - int embedded_profile_len = 0; + png_uint_32 temp; png_debug(1, "in png_write_iCCP"); - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - comp.input_len = 0; - - if ((name_len = png_check_keyword(png_ptr, name, &new_name)) == 0) - return; - - if (compression_type != PNG_COMPRESSION_TYPE_BASE) - png_warning(png_ptr, "Unknown compression type in iCCP chunk"); - + /* These are all internal problems: the profile should have been checked + * before when it was stored. + */ if (profile == NULL) - profile_len = 0; - - if (profile_len > 3) - embedded_profile_len = - ((*( (png_const_bytep)profile ))<<24) | - ((*( (png_const_bytep)profile + 1))<<16) | - ((*( (png_const_bytep)profile + 2))<< 8) | - ((*( (png_const_bytep)profile + 3)) ); - - if (embedded_profile_len < 0) + png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */ + + profile_len = png_get_uint_32(profile); + + if (profile_len < 132) + png_error(png_ptr, "ICC profile too short"); + + temp = (png_uint_32) (*(profile+8)); + if (temp > 3 && (profile_len & 0x03)) + png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)"); + { - png_warning(png_ptr, - "Embedded profile length in iCCP chunk is negative"); - - png_free(png_ptr, new_name); - return; + png_uint_32 embedded_profile_len = png_get_uint_32(profile); + + if (profile_len != embedded_profile_len) + png_error(png_ptr, "Profile length does not match profile"); } - if (profile_len < embedded_profile_len) - { - png_warning(png_ptr, - "Embedded profile length too large in iCCP chunk"); - - png_free(png_ptr, new_name); - return; - } - - if (profile_len > embedded_profile_len) - { - png_warning(png_ptr, - "Truncating profile to actual length in iCCP chunk"); - - profile_len = embedded_profile_len; - } - - if (profile_len) - profile_len = png_text_compress(png_ptr, profile, - (png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp); + name_len = png_check_keyword(png_ptr, name, new_name); + + if (name_len == 0) + png_error(png_ptr, "iCCP: invalid keyword"); + + new_name[++name_len] = PNG_COMPRESSION_TYPE_BASE; /* Make sure we include the NULL after the name and the compression type */ - png_write_chunk_start(png_ptr, png_iCCP, - (png_uint_32)(name_len + profile_len + 2)); - - new_name[name_len + 1] = 0x00; - - png_write_chunk_data(png_ptr, (png_bytep)new_name, - (png_size_t)(name_len + 2)); - - if (profile_len) - { - comp.input_len = profile_len; - png_write_compressed_data_out(png_ptr, &comp); - } + ++name_len; + + png_text_compress_init(&comp, profile, profile_len); + + /* Allow for keyword terminator and compression byte */ + if (png_text_compress(png_ptr, png_iCCP, &comp, name_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + + png_write_chunk_header(png_ptr, png_iCCP, name_len + comp.output_len); + + png_write_chunk_data(png_ptr, new_name, name_len); + + png_write_compressed_data_out(png_ptr, &comp); png_write_chunk_end(png_ptr); - png_free(png_ptr, new_name); } #endif #ifdef PNG_WRITE_sPLT_SUPPORTED /* Write a sPLT chunk */ void /* PRIVATE */ -png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette) +png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) { - PNG_sPLT; - png_size_t name_len; - png_charp new_name; + png_uint_32 name_len; + png_byte new_name[80]; png_byte entrybuf[10]; png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); png_size_t palette_size = entry_size * spalette->nentries; @@ -1204,11 +1293,13 @@ png_debug(1, "in png_write_sPLT"); - if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0) - return; + name_len = png_check_keyword(png_ptr, spalette->name, new_name); + + if (name_len == 0) + png_error(png_ptr, "sPLT: invalid keyword"); /* Make sure we include the NULL after the name */ - png_write_chunk_start(png_ptr, png_sPLT, + png_write_chunk_header(png_ptr, png_sPLT, (png_uint_32)(name_len + 2 + palette_size)); png_write_chunk_data(png_ptr, (png_bytep)new_name, @@ -1238,7 +1329,7 @@ png_save_uint_16(entrybuf + 8, ep->frequency); } - png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); + png_write_chunk_data(png_ptr, entrybuf, entry_size); } #else ep=spalette->entries; @@ -1262,28 +1353,26 @@ png_save_uint_16(entrybuf + 8, ep[i].frequency); } - png_write_chunk_data(png_ptr, entrybuf, (png_size_t)entry_size); + png_write_chunk_data(png_ptr, entrybuf, entry_size); } #endif png_write_chunk_end(png_ptr); - png_free(png_ptr, new_name); } #endif #ifdef PNG_WRITE_sBIT_SUPPORTED /* Write the sBIT chunk */ void /* PRIVATE */ -png_write_sBIT(png_structp png_ptr, png_const_color_8p sbit, int color_type) +png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) { - PNG_sBIT; png_byte buf[4]; png_size_t size; png_debug(1, "in png_write_sBIT"); /* Make sure we don't depend upon the order of PNG_COLOR_8 */ - if (color_type & PNG_COLOR_MASK_COLOR) + if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { png_byte maxbits; @@ -1316,7 +1405,7 @@ size = 1; } - if (color_type & PNG_COLOR_MASK_ALPHA) + if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) { if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) { @@ -1327,53 +1416,42 @@ buf[size++] = sbit->alpha; } - png_write_chunk(png_ptr, png_sBIT, buf, size); + png_write_complete_chunk(png_ptr, png_sBIT, buf, size); } #endif #ifdef PNG_WRITE_cHRM_SUPPORTED /* Write the cHRM chunk */ void /* PRIVATE */ -png_write_cHRM_fixed(png_structp png_ptr, png_fixed_point white_x, - png_fixed_point white_y, png_fixed_point red_x, png_fixed_point red_y, - png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, - png_fixed_point blue_y) +png_write_cHRM_fixed(png_structrp png_ptr, const png_xy *xy) { - PNG_cHRM; png_byte buf[32]; png_debug(1, "in png_write_cHRM"); /* Each value is saved in 1/100,000ths */ -#ifdef PNG_CHECK_cHRM_SUPPORTED - if (png_check_cHRM_fixed(png_ptr, white_x, white_y, red_x, red_y, - green_x, green_y, blue_x, blue_y)) -#endif - { - png_save_uint_32(buf, (png_uint_32)white_x); - png_save_uint_32(buf + 4, (png_uint_32)white_y); - - png_save_uint_32(buf + 8, (png_uint_32)red_x); - png_save_uint_32(buf + 12, (png_uint_32)red_y); - - png_save_uint_32(buf + 16, (png_uint_32)green_x); - png_save_uint_32(buf + 20, (png_uint_32)green_y); - - png_save_uint_32(buf + 24, (png_uint_32)blue_x); - png_save_uint_32(buf + 28, (png_uint_32)blue_y); - - png_write_chunk(png_ptr, png_cHRM, buf, (png_size_t)32); - } + png_save_int_32(buf, xy->whitex); + png_save_int_32(buf + 4, xy->whitey); + + png_save_int_32(buf + 8, xy->redx); + png_save_int_32(buf + 12, xy->redy); + + png_save_int_32(buf + 16, xy->greenx); + png_save_int_32(buf + 20, xy->greeny); + + png_save_int_32(buf + 24, xy->bluex); + png_save_int_32(buf + 28, xy->bluey); + + png_write_complete_chunk(png_ptr, png_cHRM, buf, 32); } #endif #ifdef PNG_WRITE_tRNS_SUPPORTED /* Write the tRNS chunk */ void /* PRIVATE */ -png_write_tRNS(png_structp png_ptr, png_const_bytep trans_alpha, +png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, png_const_color_16p tran, int num_trans, int color_type) { - PNG_tRNS; png_byte buf[6]; png_debug(1, "in png_write_tRNS"); @@ -1382,12 +1460,14 @@ { if (num_trans <= 0 || num_trans > (int)png_ptr->num_palette) { - png_warning(png_ptr, "Invalid number of transparent colors specified"); + png_app_warning(png_ptr, + "Invalid number of transparent colors specified"); return; } /* Write the chunk out as it is */ - png_write_chunk(png_ptr, png_tRNS, trans_alpha, (png_size_t)num_trans); + png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, + (png_size_t)num_trans); } else if (color_type == PNG_COLOR_TYPE_GRAY) @@ -1395,14 +1475,14 @@ /* One 16 bit value */ if (tran->gray >= (1 << png_ptr->bit_depth)) { - png_warning(png_ptr, + png_app_warning(png_ptr, "Ignoring attempt to write tRNS chunk out-of-range for bit_depth"); return; } png_save_uint_16(buf, tran->gray); - png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)2); + png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)2); } else if (color_type == PNG_COLOR_TYPE_RGB) @@ -1412,22 +1492,22 @@ png_save_uint_16(buf + 2, tran->green); png_save_uint_16(buf + 4, tran->blue); #ifdef PNG_WRITE_16BIT_SUPPORTED - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) #else - if (buf[0] | buf[2] | buf[4]) + if ((buf[0] | buf[2] | buf[4]) != 0) #endif { - png_warning(png_ptr, + png_app_warning(png_ptr, "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); return; } - png_write_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); + png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); } else { - png_warning(png_ptr, "Can't write tRNS with an alpha channel"); + png_app_warning(png_ptr, "Can't write tRNS with an alpha channel"); } } #endif @@ -1435,9 +1515,8 @@ #ifdef PNG_WRITE_bKGD_SUPPORTED /* Write the background chunk */ void /* PRIVATE */ -png_write_bKGD(png_structp png_ptr, png_const_color_16p back, int color_type) +png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) { - PNG_bKGD; png_byte buf[6]; png_debug(1, "in png_write_bKGD"); @@ -1446,8 +1525,8 @@ { if ( #ifdef PNG_MNG_FEATURES_SUPPORTED - (png_ptr->num_palette || - (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && + (png_ptr->num_palette != 0 || + (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) && #endif back->index >= png_ptr->num_palette) { @@ -1456,18 +1535,18 @@ } buf[0] = back->index; - png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); } - else if (color_type & PNG_COLOR_MASK_COLOR) + else if ((color_type & PNG_COLOR_MASK_COLOR) != 0) { png_save_uint_16(buf, back->red); png_save_uint_16(buf + 2, back->green); png_save_uint_16(buf + 4, back->blue); #ifdef PNG_WRITE_16BIT_SUPPORTED - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) #else - if (buf[0] | buf[2] | buf[4]) + if ((buf[0] | buf[2] | buf[4]) != 0) #endif { png_warning(png_ptr, @@ -1476,7 +1555,7 @@ return; } - png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); } else @@ -1490,7 +1569,7 @@ } png_save_uint_16(buf, back->gray); - png_write_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); } } #endif @@ -1498,9 +1577,8 @@ #ifdef PNG_WRITE_hIST_SUPPORTED /* Write the histogram */ void /* PRIVATE */ -png_write_hIST(png_structp png_ptr, png_const_uint_16p hist, int num_hist) +png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) { - PNG_hIST; int i; png_byte buf[3]; @@ -1515,7 +1593,7 @@ return; } - png_write_chunk_start(png_ptr, png_hIST, (png_uint_32)(num_hist * 2)); + png_write_chunk_header(png_ptr, png_hIST, (png_uint_32)(num_hist * 2)); for (i = 0; i < num_hist; i++) { @@ -1527,236 +1605,93 @@ } #endif -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ - defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) -/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, - * and if invalid, correct the keyword rather than discarding the entire - * chunk. The PNG 1.0 specification requires keywords 1-79 characters in - * length, forbids leading or trailing whitespace, multiple internal spaces, - * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. - * - * The new_key is allocated to hold the corrected keyword and must be freed - * by the calling routine. This avoids problems with trying to write to - * static keywords without having to have duplicate copies of the strings. - */ -png_size_t /* PRIVATE */ -png_check_keyword(png_structp png_ptr, png_const_charp key, png_charpp new_key) -{ - png_size_t key_len; - png_const_charp ikp; - png_charp kp, dp; - int kflag; - int kwarn=0; - - png_debug(1, "in png_check_keyword"); - - *new_key = NULL; - - if (key == NULL || (key_len = png_strlen(key)) == 0) - { - png_warning(png_ptr, "zero length keyword"); - return ((png_size_t)0); - } - - png_debug1(2, "Keyword to be checked is '%s'", key); - - *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2)); - - if (*new_key == NULL) - { - png_warning(png_ptr, "Out of memory while procesing keyword"); - return ((png_size_t)0); - } - - /* Replace non-printing characters with a blank and print a warning */ - for (ikp = key, dp = *new_key; *ikp != '\0'; ikp++, dp++) - { - if ((png_byte)*ikp < 0x20 || - ((png_byte)*ikp > 0x7E && (png_byte)*ikp < 0xA1)) - { - PNG_WARNING_PARAMETERS(p) - - png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_02x, - (png_byte)*ikp); - png_formatted_warning(png_ptr, p, "invalid keyword character 0x@1"); - *dp = ' '; - } - - else - { - *dp = *ikp; - } - } - *dp = '\0'; - - /* Remove any trailing white space. */ - kp = *new_key + key_len - 1; - if (*kp == ' ') - { - png_warning(png_ptr, "trailing spaces removed from keyword"); - - while (*kp == ' ') - { - *(kp--) = '\0'; - key_len--; - } - } - - /* Remove any leading white space. */ - kp = *new_key; - if (*kp == ' ') - { - png_warning(png_ptr, "leading spaces removed from keyword"); - - while (*kp == ' ') - { - kp++; - key_len--; - } - } - - png_debug1(2, "Checking for multiple internal spaces in '%s'", kp); - - /* Remove multiple internal spaces. */ - for (kflag = 0, dp = *new_key; *kp != '\0'; kp++) - { - if (*kp == ' ' && kflag == 0) - { - *(dp++) = *kp; - kflag = 1; - } - - else if (*kp == ' ') - { - key_len--; - kwarn = 1; - } - - else - { - *(dp++) = *kp; - kflag = 0; - } - } - *dp = '\0'; - if (kwarn) - png_warning(png_ptr, "extra interior spaces removed from keyword"); - - if (key_len == 0) - { - png_free(png_ptr, *new_key); - png_warning(png_ptr, "Zero length keyword"); - } - - if (key_len > 79) - { - png_warning(png_ptr, "keyword length must be 1 - 79 characters"); - (*new_key)[79] = '\0'; - key_len = 79; - } - - return (key_len); -} -#endif - #ifdef PNG_WRITE_tEXt_SUPPORTED /* Write a tEXt chunk */ void /* PRIVATE */ -png_write_tEXt(png_structp png_ptr, png_const_charp key, png_const_charp text, +png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, png_size_t text_len) { - PNG_tEXt; - png_size_t key_len; - png_charp new_key; + png_uint_32 key_len; + png_byte new_key[80]; png_debug(1, "in png_write_tEXt"); - if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0) - return; + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "tEXt: invalid keyword"); if (text == NULL || *text == '\0') text_len = 0; else - text_len = png_strlen(text); + text_len = strlen(text); + + if (text_len > PNG_UINT_31_MAX - (key_len+1)) + png_error(png_ptr, "tEXt: text too long"); /* Make sure we include the 0 after the key */ - png_write_chunk_start(png_ptr, png_tEXt, - (png_uint_32)(key_len + text_len + 1)); + png_write_chunk_header(png_ptr, png_tEXt, + (png_uint_32)/*checked above*/(key_len + text_len + 1)); /* * We leave it to the application to meet PNG-1.0 requirements on the * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, - (png_size_t)(key_len + 1)); - - if (text_len) - png_write_chunk_data(png_ptr, (png_const_bytep)text, - (png_size_t)text_len); + png_write_chunk_data(png_ptr, new_key, key_len + 1); + + if (text_len != 0) + png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); png_write_chunk_end(png_ptr); - png_free(png_ptr, new_key); } #endif #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write a compressed text chunk */ void /* PRIVATE */ -png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text, - png_size_t text_len, int compression) +png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, + int compression) { - PNG_zTXt; - png_size_t key_len; - png_byte buf; - png_charp new_key; + png_uint_32 key_len; + png_byte new_key[81]; compression_state comp; png_debug(1, "in png_write_zTXt"); - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - comp.input_len = 0; - - if ((key_len = png_check_keyword(png_ptr, key, &new_key)) == 0) + if (compression == PNG_TEXT_COMPRESSION_NONE) { - png_free(png_ptr, new_key); - return; - } - - if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE) - { - png_write_tEXt(png_ptr, new_key, text, (png_size_t)0); - png_free(png_ptr, new_key); + png_write_tEXt(png_ptr, key, text, 0); return; } - text_len = png_strlen(text); + if (compression != PNG_TEXT_COMPRESSION_zTXt) + png_error(png_ptr, "zTXt: invalid compression type"); + + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "zTXt: invalid keyword"); + + /* Add the compression method and 1 for the keyword separator. */ + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; /* Compute the compressed data; do it now for the length */ - text_len = png_text_compress(png_ptr, text, text_len, compression, - &comp); + png_text_compress_init(&comp, (png_const_bytep)text, + text == NULL ? 0 : strlen(text)); + + if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); /* Write start of chunk */ - png_write_chunk_start(png_ptr, png_zTXt, - (png_uint_32)(key_len+text_len + 2)); + png_write_chunk_header(png_ptr, png_zTXt, key_len + comp.output_len); /* Write key */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, - (png_size_t)(key_len + 1)); - - png_free(png_ptr, new_key); - - buf = (png_byte)compression; - - /* Write compression */ - png_write_chunk_data(png_ptr, &buf, (png_size_t)1); + png_write_chunk_data(png_ptr, new_key, key_len); /* Write the compressed data */ - comp.input_len = text_len; png_write_compressed_data_out(png_ptr, &comp); /* Close the chunk */ @@ -1767,104 +1702,109 @@ #ifdef PNG_WRITE_iTXt_SUPPORTED /* Write an iTXt chunk */ void /* PRIVATE */ -png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key, +png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, png_const_charp lang, png_const_charp lang_key, png_const_charp text) { - PNG_iTXt; - png_size_t lang_len, key_len, lang_key_len, text_len; - png_charp new_lang; - png_charp new_key = NULL; - png_byte cbuf[2]; + png_uint_32 key_len, prefix_len; + png_size_t lang_len, lang_key_len; + png_byte new_key[82]; compression_state comp; png_debug(1, "in png_write_iTXt"); - comp.num_output_ptr = 0; - comp.max_output_ptr = 0; - comp.output_ptr = NULL; - comp.input = NULL; - - if ((key_len = png_check_keyword(png_ptr, key, &new_key)) == 0) - return; - - if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang)) == 0) + key_len = png_check_keyword(png_ptr, key, new_key); + + if (key_len == 0) + png_error(png_ptr, "iTXt: invalid keyword"); + + /* Set the compression flag */ + switch (compression) { - png_warning(png_ptr, "Empty language field in iTXt chunk"); - new_lang = NULL; - lang_len = 0; + case PNG_ITXT_COMPRESSION_NONE: + case PNG_TEXT_COMPRESSION_NONE: + compression = new_key[++key_len] = 0; /* no compression */ + break; + + case PNG_TEXT_COMPRESSION_zTXt: + case PNG_ITXT_COMPRESSION_zTXt: + compression = new_key[++key_len] = 1; /* compressed */ + break; + + default: + png_error(png_ptr, "iTXt: invalid compression"); } - if (lang_key == NULL) - lang_key_len = 0; - - else - lang_key_len = png_strlen(lang_key); - - if (text == NULL) - text_len = 0; - - else - text_len = png_strlen(text); - - /* Compute the compressed data; do it now for the length */ - text_len = png_text_compress(png_ptr, text, text_len, compression - 2, - &comp); - - - /* Make sure we include the compression flag, the compression byte, - * and the NULs after the key, lang, and lang_key parts - */ - - png_write_chunk_start(png_ptr, png_iTXt, (png_uint_32)( - 5 /* comp byte, comp flag, terminators for key, lang and lang_key */ - + key_len - + lang_len - + lang_key_len - + text_len)); + new_key[++key_len] = PNG_COMPRESSION_TYPE_BASE; + ++key_len; /* for the keywod separator */ /* We leave it to the application to meet PNG-1.0 requirements on the * contents of the text. PNG-1.0 through PNG-1.2 discourage the use of - * any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them. + * any non-Latin-1 characters except for NEWLINE. ISO PNG, however, + * specifies that the text is UTF-8 and this really doesn't require any + * checking. + * * The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG. + * + * TODO: validate the language tag correctly (see the spec.) */ - png_write_chunk_data(png_ptr, (png_bytep)new_key, (png_size_t)(key_len + 1)); - - /* Set the compression flag */ - if (compression == PNG_ITXT_COMPRESSION_NONE || - compression == PNG_TEXT_COMPRESSION_NONE) - cbuf[0] = 0; - - else /* compression == PNG_ITXT_COMPRESSION_zTXt */ - cbuf[0] = 1; - - /* Set the compression method */ - cbuf[1] = 0; - - png_write_chunk_data(png_ptr, cbuf, (png_size_t)2); - - cbuf[0] = 0; - png_write_chunk_data(png_ptr, (new_lang ? (png_const_bytep)new_lang : cbuf), - (png_size_t)(lang_len + 1)); - - png_write_chunk_data(png_ptr, (lang_key ? (png_const_bytep)lang_key : cbuf), - (png_size_t)(lang_key_len + 1)); - - png_write_compressed_data_out(png_ptr, &comp); + if (lang == NULL) lang = ""; /* empty language is valid */ + lang_len = strlen(lang)+1; + if (lang_key == NULL) lang_key = ""; /* may be empty */ + lang_key_len = strlen(lang_key)+1; + if (text == NULL) text = ""; /* may be empty */ + + prefix_len = key_len; + if (lang_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_len); + + if (lang_key_len > PNG_UINT_31_MAX-prefix_len) + prefix_len = PNG_UINT_31_MAX; + else + prefix_len = (png_uint_32)(prefix_len + lang_key_len); + + png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); + + if (compression != 0) + { + if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) + png_error(png_ptr, png_ptr->zstream.msg); + } + + else + { + if (comp.input_len > PNG_UINT_31_MAX-prefix_len) + png_error(png_ptr, "iTXt: uncompressed text too long"); + + /* So the string will fit in a chunk: */ + comp.output_len = (png_uint_32)/*SAFE*/comp.input_len; + } + + png_write_chunk_header(png_ptr, png_iTXt, comp.output_len + prefix_len); + + png_write_chunk_data(png_ptr, new_key, key_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang, lang_len); + + png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); + + if (compression != 0) + png_write_compressed_data_out(png_ptr, &comp); + + else + png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.input_len); png_write_chunk_end(png_ptr); - - png_free(png_ptr, new_key); - png_free(png_ptr, new_lang); } #endif #ifdef PNG_WRITE_oFFs_SUPPORTED /* Write the oFFs chunk */ void /* PRIVATE */ -png_write_oFFs(png_structp png_ptr, png_int_32 x_offset, png_int_32 y_offset, +png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, int unit_type) { - PNG_oFFs; png_byte buf[9]; png_debug(1, "in png_write_oFFs"); @@ -1876,52 +1816,57 @@ png_save_int_32(buf + 4, y_offset); buf[8] = (png_byte)unit_type; - png_write_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); + png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); } #endif #ifdef PNG_WRITE_pCAL_SUPPORTED /* Write the pCAL chunk (described in the PNG extensions document) */ void /* PRIVATE */ -png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0, +png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params) { - PNG_pCAL; - png_size_t purpose_len, units_len, total_len; - png_uint_32p params_len; + png_uint_32 purpose_len; + png_size_t units_len, total_len; + png_size_tp params_len; png_byte buf[10]; - png_charp new_purpose; + png_byte new_purpose[80]; int i; png_debug1(1, "in png_write_pCAL (%d parameters)", nparams); if (type >= PNG_EQUATION_LAST) - png_warning(png_ptr, "Unrecognized equation type for pCAL chunk"); - - purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1; + png_error(png_ptr, "Unrecognized equation type for pCAL chunk"); + + purpose_len = png_check_keyword(png_ptr, purpose, new_purpose); + + if (purpose_len == 0) + png_error(png_ptr, "pCAL: invalid keyword"); + + ++purpose_len; /* terminator */ + png_debug1(3, "pCAL purpose length = %d", (int)purpose_len); - units_len = png_strlen(units) + (nparams == 0 ? 0 : 1); + units_len = strlen(units) + (nparams == 0 ? 0 : 1); png_debug1(3, "pCAL units length = %d", (int)units_len); total_len = purpose_len + units_len + 10; - params_len = (png_uint_32p)png_malloc(png_ptr, - (png_alloc_size_t)(nparams * png_sizeof(png_uint_32))); + params_len = (png_size_tp)png_malloc(png_ptr, + (png_alloc_size_t)(nparams * (sizeof (png_size_t)))); /* Find the length of each parameter, making sure we don't count the * null terminator for the last parameter. */ for (i = 0; i < nparams; i++) { - params_len[i] = png_strlen(params[i]) + (i == nparams - 1 ? 0 : 1); + params_len[i] = strlen(params[i]) + (i == nparams - 1 ? 0 : 1); png_debug2(3, "pCAL parameter %d length = %lu", i, (unsigned long)params_len[i]); - total_len += (png_size_t)params_len[i]; + total_len += params_len[i]; } png_debug1(3, "pCAL total length = %d", (int)total_len); - png_write_chunk_start(png_ptr, png_pCAL, (png_uint_32)total_len); - png_write_chunk_data(png_ptr, (png_const_bytep)new_purpose, - (png_size_t)purpose_len); + png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len); + png_write_chunk_data(png_ptr, new_purpose, purpose_len); png_save_int_32(buf, X0); png_save_int_32(buf + 4, X1); buf[8] = (png_byte)type; @@ -1929,12 +1874,9 @@ png_write_chunk_data(png_ptr, buf, (png_size_t)10); png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len); - png_free(png_ptr, new_purpose); - for (i = 0; i < nparams; i++) { - png_write_chunk_data(png_ptr, (png_const_bytep)params[i], - (png_size_t)params_len[i]); + png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]); } png_free(png_ptr, params_len); @@ -1945,17 +1887,16 @@ #ifdef PNG_WRITE_sCAL_SUPPORTED /* Write the sCAL chunk */ void /* PRIVATE */ -png_write_sCAL_s(png_structp png_ptr, int unit, png_const_charp width, +png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, png_const_charp height) { - PNG_sCAL; png_byte buf[64]; png_size_t wlen, hlen, total_len; png_debug(1, "in png_write_sCAL_s"); - wlen = png_strlen(width); - hlen = png_strlen(height); + wlen = strlen(width); + hlen = strlen(height); total_len = wlen + hlen + 2; if (total_len > 64) @@ -1965,22 +1906,21 @@ } buf[0] = (png_byte)unit; - png_memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ - png_memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ + memcpy(buf + 1, width, wlen + 1); /* Append the '\0' here */ + memcpy(buf + wlen + 2, height, hlen); /* Do NOT append the '\0' here */ png_debug1(3, "sCAL total length = %u", (unsigned int)total_len); - png_write_chunk(png_ptr, png_sCAL, buf, total_len); + png_write_complete_chunk(png_ptr, png_sCAL, buf, total_len); } #endif #ifdef PNG_WRITE_pHYs_SUPPORTED /* Write the pHYs chunk */ void /* PRIVATE */ -png_write_pHYs(png_structp png_ptr, png_uint_32 x_pixels_per_unit, +png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, int unit_type) { - PNG_pHYs; png_byte buf[9]; png_debug(1, "in png_write_pHYs"); @@ -1992,7 +1932,7 @@ png_save_uint_32(buf + 4, y_pixels_per_unit); buf[8] = (png_byte)unit_type; - png_write_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); + png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); } #endif @@ -2001,9 +1941,8 @@ * or png_convert_from_time_t(), or fill in the structure yourself. */ void /* PRIVATE */ -png_write_tIME(png_structp png_ptr, png_const_timep mod_time) +png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) { - PNG_tIME; png_byte buf[7]; png_debug(1, "in png_write_tIME"); @@ -2023,40 +1962,44 @@ buf[5] = mod_time->minute; buf[6] = mod_time->second; - png_write_chunk(png_ptr, png_tIME, buf, (png_size_t)7); + png_write_complete_chunk(png_ptr, png_tIME, buf, (png_size_t)7); } #endif /* Initializes the row writing capability of libpng */ void /* PRIVATE */ -png_write_start_row(png_structp png_ptr) +png_write_start_row(png_structrp png_ptr) { #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ - int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ - int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ - int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ - int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - png_size_t buf_size; + png_alloc_size_t buf_size; + int usr_pixel_depth; png_debug(1, "in png_write_start_row"); - buf_size = (png_size_t)(PNG_ROWBYTES( - png_ptr->usr_channels*png_ptr->usr_bit_depth, png_ptr->width) + 1); + usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth; + buf_size = PNG_ROWBYTES(usr_pixel_depth, png_ptr->width) + 1; + + /* 1.5.6: added to allow checking in the row write code. */ + png_ptr->transformed_pixel_depth = png_ptr->pixel_depth; + png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth; /* Set up row buffer */ - png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)buf_size); + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size); png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; @@ -2070,13 +2013,13 @@ } /* We only need to keep the previous row if we are using one of these. */ - if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) + if ((png_ptr->do_filter & + (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0) { /* Set up previous row buffer */ - png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, - (png_alloc_size_t)buf_size); - - if (png_ptr->do_filter & PNG_FILTER_UP) + png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size); + + if ((png_ptr->do_filter & PNG_FILTER_UP) != 0) { png_ptr->up_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); @@ -2084,7 +2027,7 @@ png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; } - if (png_ptr->do_filter & PNG_FILTER_AVG) + if ((png_ptr->do_filter & PNG_FILTER_AVG) != 0) { png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); @@ -2092,7 +2035,7 @@ png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; } - if (png_ptr->do_filter & PNG_FILTER_PAETH) + if ((png_ptr->do_filter & PNG_FILTER_PAETH) != 0) { png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); @@ -2100,13 +2043,13 @@ png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; } } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, we need to set up width and height of pass */ - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { - if (!(png_ptr->transformations & PNG_INTERLACE)) + if ((png_ptr->transformations & PNG_INTERLACE) == 0) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_pass_ystart[0]) / png_pass_yinc[0]; @@ -2128,34 +2071,28 @@ png_ptr->num_rows = png_ptr->height; png_ptr->usr_width = png_ptr->width; } - - png_zlib_claim(png_ptr, PNG_ZLIB_FOR_IDAT); - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - png_ptr->zstream.next_out = png_ptr->zbuf; } /* Internal use only. Called when finished processing a row of data. */ void /* PRIVATE */ -png_write_finish_row(png_structp png_ptr) +png_write_finish_row(png_structrp png_ptr) { #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ - int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ - int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* Start of interlace block in the y direction */ - int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* Offset to next interlace block in the y direction */ - int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; #endif - int ret; - png_debug(1, "in png_write_finish_row"); /* Next row */ @@ -2167,10 +2104,10 @@ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, go to next pass */ - if (png_ptr->interlaced) + if (png_ptr->interlaced != 0) { png_ptr->row_number = 0; - if (png_ptr->transformations & PNG_INTERLACE) + if ((png_ptr->transformations & PNG_INTERLACE) != 0) { png_ptr->pass++; } @@ -2195,7 +2132,7 @@ png_pass_ystart[png_ptr->pass]) / png_pass_yinc[png_ptr->pass]; - if (png_ptr->transformations & PNG_INTERLACE) + if ((png_ptr->transformations & PNG_INTERLACE) != 0) break; } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); @@ -2206,7 +2143,7 @@ if (png_ptr->pass < 7) { if (png_ptr->prev_row != NULL) - png_memset(png_ptr->prev_row, 0, + memset(png_ptr->prev_row, 0, (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* png_ptr->usr_bit_depth, png_ptr->width)) + 1); @@ -2217,42 +2154,7 @@ /* If we get here, we've just written the last row, so we need to flush the compressor */ - do - { - /* Tell the compressor we are done */ - ret = deflate(&png_ptr->zstream, Z_FINISH); - - /* Check for an error */ - if (ret == Z_OK) - { - /* Check to see if we need more room */ - if (!(png_ptr->zstream.avail_out)) - { - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - } - } - - else if (ret != Z_STREAM_END) - { - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - - else - png_error(png_ptr, "zlib error"); - } - } while (ret != Z_STREAM_END); - - /* Write any extra space */ - if (png_ptr->zstream.avail_out < png_ptr->zbuf_size) - { - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - - png_ptr->zstream.avail_out); - } - - png_zlib_release(png_ptr); - png_ptr->zstream.data_type = Z_BINARY; + png_compress_IDAT(png_ptr, NULL, 0, Z_FINISH); } #ifdef PNG_WRITE_INTERLACING_SUPPORTED @@ -2269,10 +2171,10 @@ /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* Start of interlace block */ - int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* Offset to next interlace block */ - int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; png_debug(1, "in png_do_write_interlace"); @@ -2416,7 +2318,7 @@ /* Move the pixel */ if (dp != sp) - png_memcpy(dp, sp, pixel_bytes); + memcpy(dp, sp, pixel_bytes); /* Next pixel */ dp += pixel_bytes; @@ -2440,14 +2342,16 @@ * been specified by the application, and then writes the row out with the * chosen filter. */ -static void png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row); +static void +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t row_bytes); #define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) #define PNG_HISHIFT 10 #define PNG_LOMASK ((png_uint_32)0xffffL) #define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) void /* PRIVATE */ -png_write_find_filter(png_structp png_ptr, png_row_infop row_info) +png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) { png_bytep best_row; #ifdef PNG_WRITE_FILTER_SUPPORTED @@ -2456,7 +2360,7 @@ png_byte filter_to_do = png_ptr->do_filter; png_size_t row_bytes = row_info->rowbytes; #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED - int num_p_filters = (int)png_ptr->num_prev_filters; + int num_p_filters = png_ptr->num_prev_filters; #endif png_debug(1, "in png_write_find_filter"); @@ -2507,7 +2411,7 @@ /* We don't need to test the 'no filter' case if this is the only filter * that has been chosen, as it doesn't actually do anything to the data. */ - if ((filter_to_do & PNG_FILTER_NONE) && filter_to_do != PNG_FILTER_NONE) + if ((filter_to_do & PNG_FILTER_NONE) != 0 && filter_to_do != PNG_FILTER_NONE) { png_bytep rp; png_uint_32 sum = 0; @@ -2583,7 +2487,7 @@ best_row = png_ptr->sub_row; } - else if (filter_to_do & PNG_FILTER_SUB) + else if ((filter_to_do & PNG_FILTER_SUB) != 0) { png_bytep rp, dp, lp; png_uint_32 sum = 0, lmins = mins; @@ -2704,7 +2608,7 @@ best_row = png_ptr->up_row; } - else if (filter_to_do & PNG_FILTER_UP) + else if ((filter_to_do & PNG_FILTER_UP) != 0) { png_bytep rp, dp, pp; png_uint_32 sum = 0, lmins = mins; @@ -2818,7 +2722,7 @@ best_row = png_ptr->avg_row; } - else if (filter_to_do & PNG_FILTER_AVG) + else if ((filter_to_do & PNG_FILTER_AVG) != 0) { png_bytep rp, dp, pp, lp; png_uint_32 sum = 0, lmins = mins; @@ -2920,7 +2824,7 @@ } /* Paeth filter */ - if (filter_to_do == PNG_FILTER_PAETH) + if ((filter_to_do == PNG_FILTER_PAETH) != 0) { png_bytep rp, dp, pp, cp, lp; png_size_t i; @@ -2959,7 +2863,7 @@ best_row = png_ptr->paeth_row; } - else if (filter_to_do & PNG_FILTER_PAETH) + else if ((filter_to_do & PNG_FILTER_PAETH) != 0) { png_bytep rp, dp, pp, cp, lp; png_uint_32 sum = 0, lmins = mins; @@ -3029,7 +2933,7 @@ pc = (p + pc) < 0 ? -(p + pc) : p + pc; #endif p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; -#else /* PNG_SLOW_PAETH */ +#else /* SLOW_PAETH */ p = a + b - c; pa = abs(p - a); pb = abs(p - b); @@ -3043,7 +2947,7 @@ else p = c; -#endif /* PNG_SLOW_PAETH */ +#endif /* SLOW_PAETH */ v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); @@ -3092,10 +2996,10 @@ best_row = png_ptr->paeth_row; } } -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ + /* Do the actual writing of the filtered row data from the chosen filter. */ - - png_write_filtered_row(png_ptr, best_row); + png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); #ifdef PNG_WRITE_FILTER_SUPPORTED #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED @@ -3112,74 +3016,20 @@ png_ptr->prev_filters[j] = best_row[0]; } #endif -#endif /* PNG_WRITE_FILTER_SUPPORTED */ +#endif /* WRITE_FILTER */ } /* Do the actual writing of a previously filtered row. */ static void -png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) +png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t full_row_length/*includes filter byte*/) { - png_size_t avail; - png_debug(1, "in png_write_filtered_row"); png_debug1(2, "filter = %d", filtered_row[0]); - /* Set up the zlib input buffer */ - - png_ptr->zstream.next_in = filtered_row; - png_ptr->zstream.avail_in = 0; - avail = png_ptr->row_info.rowbytes + 1; - /* Repeat until we have compressed all the data */ - do - { - int ret; /* Return of zlib */ - - /* Record the number of bytes available - zlib supports at least 65535 - * bytes at one step, depending on the size of the zlib type 'uInt', the - * maximum size zlib can write at once is ZLIB_IO_MAX (from pngpriv.h). - * Use this because on 16 bit systems 'rowbytes' can be up to 65536 (i.e. - * one more than 16 bits) and, in this case 'rowbytes+1' can overflow a - * uInt. ZLIB_IO_MAX can be safely reduced to cause zlib to be called - * with smaller chunks of data. - */ - if (png_ptr->zstream.avail_in == 0) - { - if (avail > ZLIB_IO_MAX) - { - png_ptr->zstream.avail_in = ZLIB_IO_MAX; - avail -= ZLIB_IO_MAX; - } - - else - { - /* So this will fit in the available uInt space: */ - png_ptr->zstream.avail_in = (uInt)avail; - avail = 0; - } - } - - /* Compress the data */ - ret = deflate(&png_ptr->zstream, Z_NO_FLUSH); - - /* Check for compression errors */ - if (ret != Z_OK) - { - if (png_ptr->zstream.msg != NULL) - png_error(png_ptr, png_ptr->zstream.msg); - - else - png_error(png_ptr, "zlib error"); - } - - /* See if it is time to write another IDAT */ - if (!(png_ptr->zstream.avail_out)) - { - /* Write the IDAT and reset the zlib output buffer */ - png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - } - /* Repeat until all data has been compressed */ - } while (avail > 0 || png_ptr->zstream.avail_in > 0); + + png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); /* Swap the current and previous rows */ if (png_ptr->prev_row != NULL) @@ -3202,6 +3052,6 @@ { png_write_flush(png_ptr); } -#endif +#endif /* WRITE_FLUSH */ } -#endif /* PNG_WRITE_SUPPORTED */ +#endif /* WRITE */ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/GtkFileDialogPeer.java Fri Apr 17 10:24:46 2015 -0700 @@ -29,6 +29,7 @@ import java.io.File; import java.io.FilenameFilter; import sun.awt.AWTAccessor; +import sun.misc.ManagedLocalsThread; /** * FileDialogPeer for the GtkFileChooser. @@ -111,13 +112,16 @@ XToolkit.awtLock(); try { if (b) { - Thread t = new Thread() { - public void run() { - showNativeDialog(); - fd.setVisible(false); - } + Runnable task = () -> { + showNativeDialog(); + fd.setVisible(false); }; - t.start(); + if (System.getSecurityManager() == null) { + new Thread(task).start(); + } else { + new ManagedLocalsThread(task).start(); + } + } else { quit(); fd.setVisible(false); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/InfoWindow.java Fri Apr 17 10:24:46 2015 -0700 @@ -29,6 +29,9 @@ import java.awt.event.*; import java.awt.peer.TrayIconPeer; import sun.awt.*; +import sun.misc.InnocuousThread; +import sun.misc.ManagedLocalsThread; + import java.awt.image.*; import java.text.BreakIterator; import java.util.concurrent.ArrayBlockingQueue; @@ -338,7 +341,7 @@ lineLabels[i].setBackground(Color.white); } - displayer.start(); + displayer.thread.start(); } public void display(String caption, String text, String messageType) { @@ -415,7 +418,7 @@ } public void dispose() { - displayer.interrupt(); + displayer.thread.interrupt(); super.dispose(); } @@ -444,16 +447,23 @@ } } - private class Displayer extends Thread { + private class Displayer implements Runnable { final int MAX_CONCURRENT_MSGS = 10; ArrayBlockingQueue messageQueue = new ArrayBlockingQueue(MAX_CONCURRENT_MSGS); boolean isDisplayed; + final Thread thread; Displayer() { - setDaemon(true); + if (System.getSecurityManager() == null) { + this.thread = new Thread(this); + } else { + this.thread = new ManagedLocalsThread(this); + } + this.thread.setDaemon(true); } + @Override public void run() { while (true) { Message msg = null; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11/XToolkit.java Fri Apr 17 10:24:46 2015 -0700 @@ -266,21 +266,26 @@ awtUnlock(); } PrivilegedAction a = () -> { - Thread shutdownThread = new Thread(ThreadGroupUtils.getRootThreadGroup(), "XToolkt-Shutdown-Thread") { - public void run() { - XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance(); - if (peer != null) { - peer.dispose(); - } - if (xs != null) { - ((XAWTXSettings)xs).dispose(); - } - freeXKB(); - if (log.isLoggable(PlatformLogger.Level.FINE)) { - dumpPeers(); - } - } - }; + Runnable r = () -> { + XSystemTrayPeer peer = XSystemTrayPeer.getPeerInstance(); + if (peer != null) { + peer.dispose(); + } + if (xs != null) { + ((XAWTXSettings)xs).dispose(); + } + freeXKB(); + if (log.isLoggable(PlatformLogger.Level.FINE)) { + dumpPeers(); + } + }; + String name = "XToolkt-Shutdown-Thread"; + Thread shutdownThread; + if (System.getSecurityManager() == null) { + shutdownThread = new Thread(ThreadGroupUtils.getRootThreadGroup(), r, name); + } else { + shutdownThread = new InnocuousThread(r, name); + } shutdownThread.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdownThread); return null; @@ -326,7 +331,13 @@ XWM.init(); toolkitThread = AccessController.doPrivileged((PrivilegedAction) () -> { - Thread thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), XToolkit.this, "AWT-XAWT"); + String name = "AWT-XAWT"; + Thread thread; + if (System.getSecurityManager() == null) { + thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), XToolkit.this, name); + } else { + thread = new InnocuousThread(XToolkit.this, name); + } thread.setContextClassLoader(null); thread.setPriority(Thread.NORM_PRIORITY + 1); thread.setDaemon(true); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java --- a/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/unix/classes/sun/awt/X11GraphicsDevice.java Fri Apr 17 10:24:46 2015 -0700 @@ -43,6 +43,7 @@ import sun.java2d.loops.SurfaceType; import sun.awt.util.ThreadGroupUtils; +import sun.misc.InnocuousThread; /** * This is an implementation of a GraphicsDevice object for a single @@ -428,7 +429,6 @@ // hook will have no effect) shutdownHookRegistered = true; PrivilegedAction a = () -> { - ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); Runnable r = () -> { Window old = getFullScreenWindow(); if (old != null) { @@ -436,7 +436,13 @@ setDisplayMode(origDisplayMode); } }; - Thread t = new Thread(rootTG, r,"Display-Change-Shutdown-Thread-"+screen); + String name = "Display-Change-Shutdown-Thread-" + screen; + Thread t; + if (System.getSecurityManager() == null) { + t = new Thread(ThreadGroupUtils.getRootThreadGroup(), r, name); + } else { + t = new InnocuousThread(r, name); + } t.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(t); return null; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java --- a/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,6 +25,8 @@ package sun.print; +import sun.misc.ManagedLocalsThread; + import java.io.BufferedReader; import java.io.FileInputStream; import java.io.InputStream; @@ -211,7 +213,12 @@ public PrintServiceLookupProvider() { // start the printer listener thread if (pollServices) { - PrinterChangeListener thr = new PrinterChangeListener(); + Thread thr; + if (System.getSecurityManager() == null) { + thr = new Thread(new PrinterChangeListener()); + } else { + thr = new ManagedLocalsThread(new PrinterChangeListener()); + } thr.setDaemon(true); thr.start(); IPPPrintService.debug_println(debugPrefix+"polling turned on"); @@ -934,8 +941,9 @@ } } - private class PrinterChangeListener extends Thread { + private class PrinterChangeListener implements Runnable { + @Override public void run() { int refreshSecs; while (true) { @@ -954,7 +962,7 @@ refreshSecs = minRefreshTime; } try { - sleep(refreshSecs * 1000); + Thread.sleep(refreshSecs * 1000); } catch (InterruptedException e) { break; } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c --- a/jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/unix/native/libsplashscreen/splashscreen_sys.c Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -281,9 +281,7 @@ /* for changing the visible shape of a window to an nonrectangular form */ void SplashUpdateShape(Splash * splash) { - if (!shapeSupported) - return; - if (!splash->maskRequired) { + if (splash->currentFrame < 0 || !shapeSupported || !splash->maskRequired) { return; } XShapeCombineRectangles(splash->display, splash->window, ShapeClip, 0, 0, @@ -324,6 +322,10 @@ void SplashRedrawWindow(Splash * splash) { + if (splash->currentFrame < 0) { + return; + } + XImage *ximage; // making this method redraw a part of the image does not make diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java --- a/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java Fri Apr 17 10:24:46 2015 -0700 @@ -41,6 +41,7 @@ import static sun.awt.shell.Win32ShellFolder2.*; import sun.awt.OSInfo; import sun.awt.util.ThreadGroupUtils; +import sun.misc.InnocuousThread; // NOTE: This class supersedes Win32ShellFolderManager, which was removed // from distribution after version 1.4.2. @@ -516,26 +517,22 @@ private static Thread comThread; private ComInvoker() { - super(1, 1, 0, TimeUnit.DAYS, new LinkedBlockingQueue()); + super(1, 1, 0, TimeUnit.DAYS, new LinkedBlockingQueue<>()); allowCoreThreadTimeOut(false); setThreadFactory(this); - final Runnable shutdownHook = new Runnable() { - public void run() { - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - shutdownNow(); - return null; - } - }); + final Runnable shutdownHook = () -> AccessController.doPrivileged((PrivilegedAction) () -> { + shutdownNow(); + return null; + }); + AccessController.doPrivileged((PrivilegedAction) () -> { + Thread t; + if (System.getSecurityManager() == null) { + t = new Thread(ThreadGroupUtils.getRootThreadGroup(), shutdownHook); + } else { + t = new InnocuousThread(shutdownHook); } - }; - AccessController.doPrivileged(new PrivilegedAction() { - public Void run() { - Runtime.getRuntime().addShutdownHook( - new Thread(shutdownHook) - ); - return null; - } + Runtime.getRuntime().addShutdownHook(t); + return null; }); } @@ -550,17 +547,22 @@ } } }; - comThread = AccessController.doPrivileged((PrivilegedAction) () -> { - /* 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. - */ - ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - Thread thread = new Thread(rootTG, comRun, "Swing-Shell"); - thread.setDaemon(true); - return thread; - } - ); + comThread = AccessController.doPrivileged((PrivilegedAction) () -> { + String name = "Swing-Shell"; + Thread thread; + if (System.getSecurityManager() == null) { + /* 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. + */ + thread = new Thread(ThreadGroupUtils.getRootThreadGroup(), comRun, name); + } else { + /* InnocuousThread is a member of a correct TG by default */ + thread = new InnocuousThread(comRun, name); + } + thread.setDaemon(true); + return thread; + }); return comThread; } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WFileDialogPeer.java Fri Apr 17 10:24:46 2015 -0700 @@ -36,6 +36,7 @@ import java.util.Vector; import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; +import sun.misc.ManagedLocalsThread; final class WFileDialogPeer extends WWindowPeer implements FileDialogPeer { @@ -97,12 +98,11 @@ @Override public void show() { - new Thread(new Runnable() { - @Override - public void run() { - _show(); - } - }).start(); + if (System.getSecurityManager() == null) { + new Thread(this::_show).start(); + } else { + new ManagedLocalsThread(this::_show).start(); + } } @Override diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPageDialogPeer.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,6 +25,8 @@ package sun.awt.windows; +import sun.misc.ManagedLocalsThread; + final class WPageDialogPeer extends WPrintDialogPeer { WPageDialogPeer(WPageDialog target) { @@ -39,20 +41,22 @@ @Override public void show() { - new Thread(new Runnable() { - @Override - public void run() { - // Call pageSetup even with no printer installed, this - // will display Windows error dialog and return false. - try { - ((WPrintDialog)target).setRetVal(_show()); - } catch (Exception e) { - // No exception should be thrown by native dialog code, - // but if it is we need to trap it so the thread does - // not hide is called and the thread doesn't hang. - } - ((WPrintDialog)target).setVisible(false); - } - }).start(); + Runnable runnable = () -> { + // Call pageSetup even with no printer installed, this + // will display Windows error dialog and return false. + try { + ((WPrintDialog)target).setRetVal(_show()); + } catch (Exception e) { + // No exception should be thrown by native dialog code, + // but if it is we need to trap it so the thread does + // not hide is called and the thread doesn't hang. + } + ((WPrintDialog)target).setVisible(false); + }; + if (System.getSecurityManager() == null) { + new Thread(runnable).start(); + } else { + new ManagedLocalsThread(runnable).start(); + } } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WPrintDialogPeer.java Fri Apr 17 10:24:46 2015 -0700 @@ -32,6 +32,7 @@ import java.util.Vector; import sun.awt.CausedFocusEvent; import sun.awt.AWTAccessor; +import sun.misc.ManagedLocalsThread; class WPrintDialogPeer extends WWindowPeer implements DialogPeer { @@ -67,19 +68,21 @@ @Override public void show() { - new Thread(new Runnable() { - @Override - public void run() { - try { - ((WPrintDialog)target).setRetVal(_show()); - } catch (Exception e) { - // No exception should be thrown by native dialog code, - // but if it is we need to trap it so the thread does - // not hide is called and the thread doesn't hang. - } - ((WPrintDialog)target).setVisible(false); + Runnable runnable = () -> { + try { + ((WPrintDialog)target).setRetVal(_show()); + } catch (Exception e) { + // No exception should be thrown by native dialog code, + // but if it is we need to trap it so the thread does + // not hide is called and the thread doesn't hang. } - }).start(); + ((WPrintDialog)target).setVisible(false); + }; + if (System.getSecurityManager() == null) { + new Thread(runnable).start(); + } else { + new ManagedLocalsThread(runnable).start(); + } } synchronized void setHWnd(long hwnd) { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java --- a/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java Fri Apr 17 10:24:46 2015 -0700 @@ -49,6 +49,7 @@ import sun.java2d.d3d.D3DRenderQueue; import sun.java2d.opengl.OGLRenderQueue; +import sun.misc.InnocuousThread; import sun.print.PrintJob2D; import java.awt.dnd.DragSource; @@ -247,11 +248,17 @@ */ AWTAutoShutdown.notifyToolkitThreadBusy(); - // Find a root TG and attach Appkit thread to it + // Find a root TG and attach toolkit thread to it ThreadGroup rootTG = AccessController.doPrivileged( (PrivilegedAction) ThreadGroupUtils::getRootThreadGroup); if (!startToolkitThread(this, rootTG)) { - Thread toolkitThread = new Thread(rootTG, this, "AWT-Windows"); + String name = "AWT-Windows"; + Thread toolkitThread; + if (System.getSecurityManager() == null) { + toolkitThread = new Thread(rootTG, this, name); + } else { + toolkitThread = new InnocuousThread(this, name); + } toolkitThread.setDaemon(true); toolkitThread.start(); } @@ -278,7 +285,12 @@ private void registerShutdownHook() { AccessController.doPrivileged((PrivilegedAction) () -> { - Thread shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), this::shutdown); + Thread shutdown; + if (System.getSecurityManager() == null) { + shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), this::shutdown); + } else { + shutdown = new InnocuousThread(this::shutdown); + } shutdown.setContextClassLoader(null); Runtime.getRuntime().addShutdownHook(shutdown); return null; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java --- a/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/windows/classes/sun/java2d/d3d/D3DScreenUpdateManager.java Fri Apr 17 10:24:46 2015 -0700 @@ -48,6 +48,7 @@ import sun.java2d.windows.GDIWindowSurfaceData; import sun.java2d.d3d.D3DSurfaceData.D3DWindowSurfaceData; import sun.java2d.windows.WindowsFlags; +import sun.misc.InnocuousThread; /** * This class handles rendering to the screen with the D3D pipeline. @@ -92,22 +93,25 @@ public D3DScreenUpdateManager() { done = false; - AccessController.doPrivileged( - (PrivilegedAction) () -> { - ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - Thread shutdown = new Thread(rootTG, () -> { - done = true; - wakeUpUpdateThread(); - }); - shutdown.setContextClassLoader(null); - try { - Runtime.getRuntime().addShutdownHook(shutdown); - } catch (Exception e) { - done = true; - } - return null; - } - ); + AccessController.doPrivileged((PrivilegedAction) () -> { + Runnable shutdownRunnable = () -> { + done = true; + wakeUpUpdateThread(); + }; + Thread shutdown; + if (System.getSecurityManager() == null) { + shutdown = new Thread(ThreadGroupUtils.getRootThreadGroup(), shutdownRunnable); + } else { + shutdown = new InnocuousThread(shutdownRunnable); + } + shutdown.setContextClassLoader(null); + try { + Runtime.getRuntime().addShutdownHook(shutdown); + } catch (Exception e) { + done = true; + } + return null; + }); } /** @@ -345,17 +349,21 @@ */ private synchronized void startUpdateThread() { if (screenUpdater == null) { - screenUpdater = AccessController.doPrivileged( - (PrivilegedAction) () -> { - ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup(); - Thread t = new Thread(rootTG, - D3DScreenUpdateManager.this, - "D3D Screen Updater"); - // REMIND: should it be higher? - t.setPriority(Thread.NORM_PRIORITY + 2); - t.setDaemon(true); - return t; - }); + screenUpdater = AccessController.doPrivileged((PrivilegedAction) () -> { + Thread t; + String name = "D3D Screen Updater"; + if (System.getSecurityManager() == null) { + t = new Thread(ThreadGroupUtils.getRootThreadGroup(), + D3DScreenUpdateManager.this, + name); + } else { + t = new InnocuousThread(D3DScreenUpdateManager.this, name); + } + // REMIND: should it be higher? + t.setPriority(Thread.NORM_PRIORITY + 2); + t.setDaemon(true); + return t; + }); screenUpdater.start(); } else { wakeUpUpdateThread(); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java --- a/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,6 +25,8 @@ package sun.print; +import sun.misc.ManagedLocalsThread; + import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; @@ -97,7 +99,12 @@ return; } // start the printer listener thread - PrinterChangeListener thr = new PrinterChangeListener(); + Thread thr; + if (System.getSecurityManager() == null) { + thr = new Thread(new PrinterChangeListener()); + } else { + thr = new ManagedLocalsThread(new PrinterChangeListener()); + } thr.setDaemon(true); thr.start(); } /* else condition ought to never happen! */ @@ -316,12 +323,13 @@ return defaultPrintService; } - class PrinterChangeListener extends Thread { + class PrinterChangeListener implements Runnable { long chgObj; PrinterChangeListener() { chgObj = notifyFirstPrinterChange(null); } + @Override public void run() { if (chgObj != -1) { while (true) { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/windows/native/libawt/windows/awt_InputTextInfor.cpp --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_InputTextInfor.cpp Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_InputTextInfor.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, 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 @@ -310,6 +310,8 @@ readingMergedClauseW = new jstring[cMergedClauseW]; } catch (std::bad_alloc&) { delete [] bndMergedClauseW; + delete [] bndClauseW; + delete [] readingClauseW; throw; } @@ -394,6 +396,8 @@ valMergedAttrW = new BYTE[cMergedAttrW]; } catch (std::bad_alloc&) { delete [] bndMergedAttrW; + delete [] bndAttrW; + delete [] valAttrW; throw; } bndMergedAttrW[0] = 0; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp --- a/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.desktop/windows/native/libawt/windows/awt_TrayIcon.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -709,7 +709,7 @@ { if (tooltip == NULL) { m_nid.szTip[0] = '\0'; - } else if (lstrlen(tooltip) > TRAY_ICON_TOOLTIP_MAX_SIZE) { + } else if (lstrlen(tooltip) >= TRAY_ICON_TOOLTIP_MAX_SIZE) { _tcsncpy(m_nid.szTip, tooltip, TRAY_ICON_TOOLTIP_MAX_SIZE); m_nid.szTip[TRAY_ICON_TOOLTIP_MAX_SIZE - 1] = '\0'; } else { @@ -814,7 +814,7 @@ if (caption[0] == '\0') { m_nid.szInfoTitle[0] = '\0'; - } else if (lstrlen(caption) > TRAY_ICON_BALLOON_TITLE_MAX_SIZE) { + } else if (lstrlen(caption) >= TRAY_ICON_BALLOON_TITLE_MAX_SIZE) { _tcsncpy(m_nid.szInfoTitle, caption, TRAY_ICON_BALLOON_TITLE_MAX_SIZE); m_nid.szInfoTitle[TRAY_ICON_BALLOON_TITLE_MAX_SIZE - 1] = '\0'; @@ -827,7 +827,7 @@ m_nid.szInfo[0] = ' '; m_nid.szInfo[1] = '\0'; - } else if (lstrlen(text) > TRAY_ICON_BALLOON_INFO_MAX_SIZE) { + } else if (lstrlen(text) >= TRAY_ICON_BALLOON_INFO_MAX_SIZE) { _tcsncpy(m_nid.szInfo, text, TRAY_ICON_BALLOON_INFO_MAX_SIZE); m_nid.szInfo[TRAY_ICON_BALLOON_INFO_MAX_SIZE - 1] = '\0'; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.logging/share/classes/java/util/logging/LogManager.java --- a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java Fri Apr 17 10:24:46 2015 -0700 @@ -34,6 +34,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import sun.misc.JavaAWTAccess; +import sun.misc.ManagedLocalsThread; import sun.misc.SharedSecrets; /** @@ -248,7 +249,7 @@ // This private class is used as a shutdown hook. // It does a "reset" to close all open handlers. - private class Cleaner extends Thread { + private class Cleaner extends ManagedLocalsThread { private Cleaner() { /* Set context class loader to null in order to avoid diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java --- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientCommunicatorAdmin.java Fri Apr 17 10:24:46 2015 -0700 @@ -30,6 +30,7 @@ import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; +import sun.misc.ManagedLocalsThread; public abstract class ClientCommunicatorAdmin { private static volatile long threadNo = 1; @@ -40,7 +41,11 @@ if (period > 0) { checker = new Checker(); - Thread t = new Thread(checker, "JMX client heartbeat " + ++threadNo); + Thread t = new ManagedLocalsThread( + checker, + "JMX client heartbeat " + (++threadNo) + ); + t.setDaemon(true); t.start(); } else diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java --- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java Fri Apr 17 10:24:46 2015 -0700 @@ -52,6 +52,7 @@ import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; import java.rmi.UnmarshalException; +import sun.misc.ManagedLocalsThread; public abstract class ClientNotifForwarder { @@ -90,10 +91,8 @@ throw new IllegalArgumentException("More than one command"); this.command = command; if (thread == null) { - thread = new Thread() { - - @Override - public void run() { + thread = new ManagedLocalsThread( + ()-> { while (true) { Runnable r; synchronized (LinearExecutor.this) { @@ -107,10 +106,10 @@ } r.run(); } - } - }; + }, + "ClientNotifForwarder-" + ++threadId + ); thread.setDaemon(true); - thread.setName("ClientNotifForwarder-" + ++threadId); thread.start(); } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java --- a/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/com/sun/jmx/remote/internal/ServerCommunicatorAdmin.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,9 +25,9 @@ package com.sun.jmx.remote.internal; -import java.io.IOException; import com.sun.jmx.remote.util.ClassLogger; +import sun.misc.ManagedLocalsThread; public abstract class ServerCommunicatorAdmin { public ServerCommunicatorAdmin(long timeout) { @@ -42,7 +42,7 @@ timestamp = 0; if (timeout < Long.MAX_VALUE) { Runnable timeoutTask = new Timeout(); - final Thread t = new Thread(timeoutTask); + final Thread t = new ManagedLocalsThread(timeoutTask); t.setName("JMX server connection timeout " + t.getId()); // If you change this name you will need to change a unit test // (NoServerTimeoutTest) diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/AttributeValueExp.java --- a/jdk/src/java.management/share/classes/javax/management/AttributeValueExp.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/AttributeValueExp.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -93,11 +93,10 @@ * * @return The ValueExp. * - * @exception BadAttributeValueExpException - * @exception InvalidApplicationException - * @exception BadStringOperationException - * @exception BadBinaryOpValueExpException - * + * @throws BadStringOperationException {@inheritDoc} + * @throws BadBinaryOpValueExpException {@inheritDoc} + * @throws BadAttributeValueExpException {@inheritDoc} + * @throws InvalidApplicationException {@inheritDoc} */ @Override public ValueExp apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException, diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/DescriptorKey.java --- a/jdk/src/java.management/share/classes/javax/management/DescriptorKey.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/DescriptorKey.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, 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 @@ -168,5 +168,9 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DescriptorKey { + /** + * Returns the descriptor key. + * @return the descriptor key + */ String value(); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/DynamicMBean.java --- a/jdk/src/java.management/share/classes/javax/management/DynamicMBean.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/DynamicMBean.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -43,7 +43,7 @@ * * @return The value of the attribute retrieved. * - * @exception AttributeNotFoundException + * @exception AttributeNotFoundException if specified attribute does not exist or cannot be retrieved * @exception MBeanException Wraps a java.lang.Exception thrown by the MBean's getter. * @exception ReflectionException Wraps a java.lang.Exception thrown while trying to invoke the getter. * @@ -58,8 +58,8 @@ * @param attribute The identification of the attribute to * be set and the value it is to be set to. * - * @exception AttributeNotFoundException - * @exception InvalidAttributeValueException + * @exception AttributeNotFoundException if specified attribute does not exist or cannot be retrieved + * @exception InvalidAttributeValueException if value specified is not valid for the attribute * @exception MBeanException Wraps a java.lang.Exception thrown by the MBean's setter. * @exception ReflectionException Wraps a java.lang.Exception thrown while trying to invoke the MBean's setter. * diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/ImmutableDescriptor.java --- a/jdk/src/java.management/share/classes/javax/management/ImmutableDescriptor.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/ImmutableDescriptor.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, 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 @@ -65,6 +65,8 @@ /** * Construct a descriptor containing the given fields and values. * + * @param fieldNames the field names + * @param fieldValues the field values * @throws IllegalArgumentException if either array is null, or * if the arrays have different sizes, or * if a field name is null or empty, or if the same field name @@ -81,6 +83,7 @@ * is {@code a=b=c} then the field name is {@code a} and its value * is {@code b=c}. * + * @param fields the field names * @throws IllegalArgumentException if the parameter is null, or * if a field name is empty, or if the same field name appears * more than once, or if one of the strings does not contain @@ -94,6 +97,7 @@ *

Construct a descriptor where the names and values of the fields * are the keys and values of the given Map.

* + * @param fields the field names and values * @throws IllegalArgumentException if the parameter is null, or * if a field name is null or empty, or if the same field name appears * more than once (which can happen because field names are not case diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/QueryExp.java --- a/jdk/src/java.management/share/classes/javax/management/QueryExp.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/QueryExp.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -53,10 +53,13 @@ * * @return True if the query was successfully applied to the MBean, false otherwise * - * @exception BadStringOperationException - * @exception BadBinaryOpValueExpException - * @exception BadAttributeValueExpException - * @exception InvalidApplicationException + * @throws BadStringOperationException when an invalid string + * operation is passed to a method for constructing a query + * @throws BadBinaryOpValueExpException when an invalid expression + * is passed to a method for constructing a query + * @throws BadAttributeValueExpException when an invalid MBean + * attribute is passed to a query constructing method + * @throws InvalidApplicationException when an invalid apply is attempted */ public boolean apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException, BadAttributeValueExpException, InvalidApplicationException ; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/StandardEmitterMBean.java --- a/jdk/src/java.management/share/classes/javax/management/StandardEmitterMBean.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/StandardEmitterMBean.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, 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 @@ -91,6 +91,7 @@ * that will have no effect on this object's * {@code getNotificationInfo()}.

* + * @param the implementation type of the MBean * @param implementation the implementation of the MBean interface. * @param mbeanInterface a Standard MBean interface. * @param emitter the object that will handle notifications. @@ -129,6 +130,7 @@ * that will have no effect on this object's * {@code getNotificationInfo()}.

* + * @param the implementation type of the MBean * @param implementation the implementation of the MBean interface. * @param mbeanInterface a Standard MBean interface. * @param isMXBean If true, the {@code mbeanInterface} parameter diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/StringValueExp.java --- a/jdk/src/java.management/share/classes/javax/management/StringValueExp.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/StringValueExp.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -95,11 +95,12 @@ * * @return The ValueExp. * - * @exception BadStringOperationException - * @exception BadBinaryOpValueExpException - * @exception BadAttributeValueExpException - * @exception InvalidApplicationException + * @throws BadStringOperationException {@inheritDoc} + * @throws BadBinaryOpValueExpException {@inheritDoc} + * @throws BadAttributeValueExpException {@inheritDoc} + * @throws InvalidApplicationException {@inheritDoc} */ + @Override public ValueExp apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException, BadAttributeValueExpException, InvalidApplicationException { return this; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/ValueExp.java --- a/jdk/src/java.management/share/classes/javax/management/ValueExp.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/ValueExp.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -80,10 +80,13 @@ * * @return The ValueExp. * - * @exception BadStringOperationException - * @exception BadBinaryOpValueExpException - * @exception BadAttributeValueExpException - * @exception InvalidApplicationException + * @throws BadStringOperationException when an invalid string + * operation is passed to a method for constructing a query + * @throws BadBinaryOpValueExpException when an invalid expression + * is passed to a method for constructing a query + * @throws BadAttributeValueExpException when an invalid MBean + * attribute is passed to a query constructing method + * @throws InvalidApplicationException when an invalid apply is attempted */ public ValueExp apply(ObjectName name) throws BadStringOperationException, BadBinaryOpValueExpException, diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanInfo.java --- a/jdk/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanInfo.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/modelmbean/ModelMBeanInfo.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, 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 @@ -307,6 +307,7 @@ /** * Creates and returns a copy of this object. + * @return a copy of this object */ public java.lang.Object clone(); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java --- a/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/monitor/Monitor.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -61,6 +61,7 @@ import javax.management.ObjectName; import javax.management.ReflectionException; import static javax.management.monitor.MonitorNotification.*; +import sun.misc.ManagedLocalsThread; /** * Defines the part common to all monitor MBeans. @@ -386,7 +387,7 @@ * * @return The name of the monitor MBean registered. * - * @exception Exception + * @exception Exception if something goes wrong */ public ObjectName preRegister(MBeanServer server, ObjectName name) throws Exception { @@ -415,7 +416,7 @@ *

* Stops the monitor. * - * @exception Exception + * @exception Exception if something goes wrong */ public void preDeregister() throws Exception { @@ -1636,12 +1637,12 @@ } public Thread newThread(Runnable r) { - Thread t = new Thread(group, - r, - namePrefix + - threadNumber.getAndIncrement() + - nameSuffix, - 0); + Thread t = new ManagedLocalsThread( + group, + r, + namePrefix + threadNumber.getAndIncrement() + nameSuffix + ); + t.setDaemon(true); if (t.getPriority() != Thread.NORM_PRIORITY) t.setPriority(Thread.NORM_PRIORITY); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/openmbean/ArrayType.java --- a/jdk/src/java.management/share/classes/javax/management/openmbean/ArrayType.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/openmbean/ArrayType.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2015, 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 @@ -793,6 +793,7 @@ * array type description = 3-dimension array of java.lang.String * } * + * @param the Java type that described instances must have * @param elementType the open type of element values contained * in the arrays described by this ArrayType * instance; must be an instance of either @@ -800,7 +801,7 @@ * TabularType or another ArrayType * with a SimpleType, CompositeType * or TabularType as its elementType. - * + * @return an {@code ArrayType} instance * @throws OpenDataException if elementType's className is not * one of the allowed Java class names for open * data. @@ -834,12 +835,14 @@ * array type description = 3-dimension array of int * } * + * @param the Java type that described instances must have * @param arrayClass a primitive array class such as {@code int[].class}, * {@code boolean[][].class}, etc. The {@link * #getElementOpenType()} method of the returned * {@code ArrayType} returns the {@link SimpleType} * corresponding to the wrapper type of the primitive * type of the array. + * @return an {@code ArrayType} instance * * @throws IllegalArgumentException if arrayClass is not * a primitive array. diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/javax/management/timer/Timer.java --- a/jdk/src/java.management/share/classes/javax/management/timer/Timer.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/javax/management/timer/Timer.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2015, 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 @@ -195,7 +195,7 @@ * * @return The name of the timer MBean registered. * - * @exception java.lang.Exception + * @exception java.lang.Exception if something goes wrong */ public ObjectName preRegister(MBeanServer server, ObjectName name) throws java.lang.Exception { @@ -217,7 +217,7 @@ *

* Stops the timer. * - * @exception java.lang.Exception + * @exception java.lang.Exception if something goes wrong */ public void preDeregister() throws java.lang.Exception { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java --- a/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.management/share/classes/sun/management/jdp/JdpController.java Fri Apr 17 10:24:46 2015 -0700 @@ -34,6 +34,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import sun.management.VMManagement; +import sun.misc.ManagedLocalsThread; /** * JdpController is responsible to create and manage a broadcast loop @@ -219,7 +220,7 @@ controller = new JDPControllerRunner(bcast, packet, pause); - Thread t = new Thread(controller, "JDP broadcaster"); + Thread t = new ManagedLocalsThread(controller, "JDP broadcaster"); t.setDaemon(true); t.start(); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java --- a/jdk/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java Fri Apr 17 10:24:46 2015 -0700 @@ -31,6 +31,7 @@ import java.util.Timer; import java.util.TimerTask; import java.lang.ref.WeakReference; +import sun.misc.ManagedLocalsThread; /* @@ -343,7 +344,7 @@ { if (timer == null) { timer = new Timer(true); // daemon - Thread flushThread = new Thread() { + Thread flushThread = new ManagedLocalsThread() { @Override public void run() { flushWorld(); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.prefs/share/classes/java/util/prefs/AbstractPreferences.java --- a/jdk/src/java.prefs/share/classes/java/util/prefs/AbstractPreferences.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.prefs/share/classes/java/util/prefs/AbstractPreferences.java Fri Apr 17 10:24:46 2015 -0700 @@ -29,6 +29,7 @@ import java.io.*; import java.security.AccessController; import java.security.PrivilegedAction; +import sun.misc.ManagedLocalsThread; // These imports needed only as a workaround for a JavaDoc bug import java.lang.Integer; import java.lang.Long; @@ -1470,7 +1471,7 @@ * A single background thread ("the event notification thread") monitors * the event queue and delivers events that are placed on the queue. */ - private static class EventDispatchThread extends Thread { + private static class EventDispatchThread extends ManagedLocalsThread { public void run() { while(true) { // Wait on eventQueue till an event is present diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java --- a/jdk/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java Fri Apr 17 10:24:46 2015 -0700 @@ -30,7 +30,7 @@ import java.security.PrivilegedAction; import java.security.PrivilegedExceptionAction; import java.security.PrivilegedActionException; - +import sun.misc.ManagedLocalsThread; import sun.util.logging.PlatformLogger; /** @@ -450,7 +450,7 @@ // Add shutdown hook to flush cached prefs on normal termination AccessController.doPrivileged(new PrivilegedAction() { public Void run() { - Runtime.getRuntime().addShutdownHook(new Thread() { + Runtime.getRuntime().addShutdownHook(new ManagedLocalsThread() { public void run() { syncTimer.cancel(); syncWorld(); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.smartcardio/share/classes/javax/smartcardio/Card.java --- a/jdk/src/java.smartcardio/share/classes/javax/smartcardio/Card.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.smartcardio/share/classes/javax/smartcardio/Card.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, 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 @@ -69,6 +69,7 @@ * Returns the CardChannel for the basic logical channel. The basic * logical channel has a channel number of 0. * + * @return the CardChannel for the basic logical channel * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission} @@ -82,6 +83,7 @@ * opened by issuing a MANAGE CHANNEL command that should use * the format [00 70 00 00 01]. * + * @return the logical channel which has been opened * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission} @@ -137,6 +139,7 @@ * * @param controlCode the control code of the command * @param command the command data + * @return the response from the terminal device * * @throws SecurityException if a SecurityManager exists and the * caller does not have the required diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.smartcardio/share/classes/javax/smartcardio/CardTerminal.java --- a/jdk/src/java.smartcardio/share/classes/javax/smartcardio/CardTerminal.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.smartcardio/share/classes/javax/smartcardio/CardTerminal.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, 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 @@ -83,6 +83,7 @@ * @throws SecurityException if a SecurityManager exists and the * caller does not have the required * {@linkplain CardPermission permission} + * @return the card the connection has been established with */ public abstract Card connect(String protocol) throws CardException; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.smartcardio/share/classes/javax/smartcardio/CardTerminals.java --- a/jdk/src/java.smartcardio/share/classes/javax/smartcardio/CardTerminals.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.smartcardio/share/classes/javax/smartcardio/CardTerminals.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2015, 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 @@ -105,6 +105,7 @@ * Returns the terminal with the specified name or null if no such * terminal exists. * + * @param name the terminal name * @return the terminal with the specified name or null if no such * terminal exists. * diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.transaction/share/classes/javax/transaction/InvalidTransactionException.java --- a/jdk/src/java.transaction/share/classes/javax/transaction/InvalidTransactionException.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.transaction/share/classes/javax/transaction/InvalidTransactionException.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -39,10 +39,17 @@ @SuppressWarnings("serial") // serialVersionUID intentionally omitted public class InvalidTransactionException extends java.rmi.RemoteException { + /** + * Constructs an {@code InvalidTransactionException}. + */ public InvalidTransactionException() { super(); } + /** + * Constructs an {@code InvalidTransactionException}. + * @param msg the detail message + */ public InvalidTransactionException(String msg) { super(msg); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.transaction/share/classes/javax/transaction/TransactionRequiredException.java --- a/jdk/src/java.transaction/share/classes/javax/transaction/TransactionRequiredException.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.transaction/share/classes/javax/transaction/TransactionRequiredException.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -38,10 +38,17 @@ @SuppressWarnings("serial") // serialVersionUID intentionally omitted public class TransactionRequiredException extends java.rmi.RemoteException { + /** + * Constructs a {@code TransactionRequiredException}. + */ public TransactionRequiredException() { super(); } + /** + * Constructs a {@code TransactionRequiredException}. + * @param msg the detail message + */ public TransactionRequiredException(String msg) { super(msg); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/java.transaction/share/classes/javax/transaction/TransactionRolledbackException.java --- a/jdk/src/java.transaction/share/classes/javax/transaction/TransactionRolledbackException.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/java.transaction/share/classes/javax/transaction/TransactionRolledbackException.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 1999, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2015, 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 @@ -41,10 +41,17 @@ @SuppressWarnings("serial") // serialVersionUID intentionally omitted public class TransactionRolledbackException extends java.rmi.RemoteException { + /** + * Constructs a {@code TransactionRolledbackException}. + */ public TransactionRolledbackException() { super(); } + /** + * Constructs a {@code TransactionRolledbackException}. + * @param msg the detail message + */ public TransactionRolledbackException(String msg) { super(msg); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AWTEventMonitor.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,1526 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util; + +import java.util.*; +import java.awt.*; +import java.awt.event.*; +import javax.accessibility.*; +import javax.swing.*; +import javax.swing.event.*; +import sun.awt.AWTPermissions; + +/** + *

The {@code AWTEventMonitor} implements a suite of listeners that are + * conditionally installed on every AWT component instance in the Java + * Virtual Machine. The events captured by these listeners are made + * available through a unified set of listeners supported by {@code AWTEventMonitor}. + * With this, all the individual events on each of the AWT component + * instances are funneled into one set of listeners broken down by category + * (see {@link EventID} for the categories). + *

This class depends upon {@link EventQueueMonitor}, which provides the base + * level support for capturing the top-level containers as they are created. + */ + +@jdk.Exported +public class AWTEventMonitor { + + static private boolean runningOnJDK1_4 = false; + + /** + * The current component with keyboard focus. + * + * @see #getComponentWithFocus + * + * @deprecated This field is unused; to get the component with focus use the + * getComponentWithFocus method. + */ + @Deprecated + static protected Component componentWithFocus = null; + + static private Component componentWithFocus_private = null; + + // Low-level listeners + /** + * The current list of registered ComponentListener classes. + * + * @see #addComponentListener + * @see #removeComponentListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected ComponentListener componentListener = null; + + static private ComponentListener componentListener_private = null; + + /** + * The current list of registered ContainerListener classes. + * + * @see #addContainerListener + * @see #removeContainerListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected ContainerListener containerListener = null; + + static private ContainerListener containerListener_private = null; + + /** + * The current list of registered FocusListener classes. + * + * @see #addFocusListener + * @see #removeFocusListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected FocusListener focusListener = null; + + static private FocusListener focusListener_private = null; + + /** + * The current list of registered KeyListener classes. + * + * @see #addKeyListener + * @see #removeKeyListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected KeyListener keyListener = null; + + static private KeyListener keyListener_private = null; + + /** + * The current list of registered MouseListener classes. + * + * @see #addMouseListener + * @see #removeMouseListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected MouseListener mouseListener = null; + + static private MouseListener mouseListener_private = null; + + /** + * The current list of registered MouseMotionListener classes. + * + * @see #addMouseMotionListener + * @see #removeMouseMotionListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected MouseMotionListener mouseMotionListener = null; + + static private MouseMotionListener mouseMotionListener_private = null; + + /** + * The current list of registered WindowListener classes. + * + * @see #addWindowListener + * @see #removeWindowListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected WindowListener windowListener = null; + + static private WindowListener windowListener_private = null; + + + // Semantic listeners + /** + * The current list of registered ActionListener classes. + * + * @see #addActionListener + * @see #removeActionListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected ActionListener actionListener = null; + + static private ActionListener actionListener_private = null; + + /** + * The current list of registered AdjustmentListener classes. + * + * @see #addAdjustmentListener + * @see #removeAdjustmentListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected AdjustmentListener adjustmentListener = null; + + static private AdjustmentListener adjustmentListener_private = null; + + /** + * The current list of registered ItemListener classes. + * + * @see #addItemListener + * @see #removeItemListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected ItemListener itemListener = null; + + static private ItemListener itemListener_private = null; + + /** + * The current list of registered TextListener classes. + * + * @see #addTextListener + * @see #removeTextListener + * + * @deprecated This field is unused. + */ + @Deprecated + static protected TextListener textListener = null; + + static private TextListener textListener_private = null; + + + /** + * The actual listener that is installed on the component instances. + * This listener calls the other registered listeners when an event + * occurs. By doing things this way, the actual number of listeners + * installed on a component instance is drastically reduced. + * + * @deprecated This field is unused. + */ + @Deprecated + static protected AWTEventsListener awtListener = new AWTEventsListener(); + + static private final AWTEventsListener awtListener_private = new AWTEventsListener(); + + /** + * Returns the component that currently has keyboard focus. The return + * value can be null. + * + * @return the component that has keyboard focus + */ + static public Component getComponentWithFocus() { + return componentWithFocus_private; + } + + /* + * Check permissions + */ + static private void checkInstallPermission() { + SecurityManager security = System.getSecurityManager(); + if (security != null) { + security.checkPermission(AWTPermissions.ALL_AWT_EVENTS_PERMISSION); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#COMPONENT COMPONENT} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeComponentListener + */ + static public void addComponentListener(ComponentListener l) { + if (componentListener_private == null) { + checkInstallPermission(); + awtListener_private.installListeners(EventID.COMPONENT); + } + componentListener_private = AWTEventMulticaster.add(componentListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#COMPONENT COMPONENT} events when they occur. + * + * @param l the listener to remove + * @see #addComponentListener + */ + static public void removeComponentListener(ComponentListener l) { + componentListener_private = AWTEventMulticaster.remove(componentListener_private, l); + if (componentListener_private == null) { + awtListener_private.removeListeners(EventID.COMPONENT); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#CONTAINER CONTAINER} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeContainerListener + */ + static public void addContainerListener(ContainerListener l) { + containerListener_private = AWTEventMulticaster.add(containerListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#CONTAINER CONTAINER} events when they occur. + * + * @param l the listener to remove + * @see #addContainerListener + */ + static public void removeContainerListener(ContainerListener l) { + containerListener_private = AWTEventMulticaster.remove(containerListener_private, l); + } + + /** + * Adds the specified listener to receive all {@link EventID#FOCUS FOCUS} events + * on each component instance in the Java Virtual Machine when they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeFocusListener + */ + static public void addFocusListener(FocusListener l) { + focusListener_private = AWTEventMulticaster.add(focusListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives {@link EventID#FOCUS FOCUS} + * events when they occur. + * + * @param l the listener to remove + * @see #addFocusListener + */ + static public void removeFocusListener(FocusListener l) { + focusListener_private = AWTEventMulticaster.remove(focusListener_private, l); + } + + /** + * Adds the specified listener to receive all {@link EventID#KEY KEY} events on each + * component instance in the Java Virtual Machine when they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeKeyListener + */ + static public void addKeyListener(KeyListener l) { + if (keyListener_private == null) { + checkInstallPermission(); + awtListener_private.installListeners(EventID.KEY); + } + keyListener_private = AWTEventMulticaster.add(keyListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives {@link EventID#KEY KEY} + * events when they occur. + * + * @param l the listener to remove + * @see #addKeyListener + */ + static public void removeKeyListener(KeyListener l) { + keyListener_private = AWTEventMulticaster.remove(keyListener_private, l); + if (keyListener_private == null) { + awtListener_private.removeListeners(EventID.KEY); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#MOUSE MOUSE} events + * on each component instance in the Java Virtual Machine when they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeMouseListener + */ + static public void addMouseListener(MouseListener l) { + if (mouseListener_private == null) { + checkInstallPermission(); + awtListener_private.installListeners(EventID.MOUSE); + } + mouseListener_private = AWTEventMulticaster.add(mouseListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#MOUSE MOUSE} events when they occur. + * + * @param l the listener to remove + * @see #addMouseListener + */ + static public void removeMouseListener(MouseListener l) { + mouseListener_private = AWTEventMulticaster.remove(mouseListener_private, l); + if (mouseListener_private == null) { + awtListener_private.removeListeners(EventID.MOUSE); + } + } + + /** + * Adds the specified listener to receive all mouse {@link EventID#MOTION MOTION} + * events on each component instance in the Java Virtual Machine when they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeMouseMotionListener + */ + static public void addMouseMotionListener(MouseMotionListener l) { + if (mouseMotionListener_private == null) { + checkInstallPermission(); + awtListener_private.installListeners(EventID.MOTION); + } + mouseMotionListener_private = AWTEventMulticaster.add(mouseMotionListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#MOTION MOTION} events when they occur. + * + * @param l the listener to remove + * @see #addMouseMotionListener + */ + static public void removeMouseMotionListener(MouseMotionListener l) { + mouseMotionListener_private = AWTEventMulticaster.remove(mouseMotionListener_private, l); + if (mouseMotionListener_private == null) { + awtListener_private.removeListeners(EventID.MOTION); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#WINDOW WINDOW} + * events on each component instance in the Java Virtual Machine when they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeWindowListener + */ + static public void addWindowListener(WindowListener l) { + if (windowListener_private == null) { + checkInstallPermission(); + awtListener_private.installListeners(EventID.WINDOW); + } + windowListener_private = AWTEventMulticaster.add(windowListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#WINDOW WINDOW} events when they occur. + * + * @param l the listener to remove + * @see #addWindowListener + */ + static public void removeWindowListener(WindowListener l) { + windowListener_private = AWTEventMulticaster.remove(windowListener_private, l); + if (windowListener_private == null) { + awtListener_private.removeListeners(EventID.WINDOW); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#ACTION ACTION} + * events on each component instance in the Java Virtual Machine when they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeActionListener + */ + static public void addActionListener(ActionListener l) { + if (actionListener_private == null) { + checkInstallPermission(); + awtListener_private.installListeners(EventID.ACTION); + } + actionListener_private = AWTEventMulticaster.add(actionListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#ACTION ACTION} events when they occur. + * + * @param l the listener to remove + * @see #addActionListener + */ + static public void removeActionListener(ActionListener l) { + actionListener_private = AWTEventMulticaster.remove(actionListener_private, l); + if (actionListener_private == null) { + awtListener_private.removeListeners(EventID.ACTION); + } + } + + /** + * Adds the specified listener to receive all + * {@link EventID#ADJUSTMENT ADJUSTMENT} events on each component instance + * in the Java Virtual Machine when they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeAdjustmentListener + */ + static public void addAdjustmentListener(AdjustmentListener l) { + if (adjustmentListener_private == null) { + checkInstallPermission(); + awtListener_private.installListeners(EventID.ADJUSTMENT); + } + adjustmentListener_private = AWTEventMulticaster.add(adjustmentListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#ADJUSTMENT ADJUSTMENT} events when they occur. + * + * @param l the listener to remove + * @see #addAdjustmentListener + */ + static public void removeAdjustmentListener(AdjustmentListener l) { + adjustmentListener_private = AWTEventMulticaster.remove(adjustmentListener_private, l); + if (adjustmentListener_private == null) { + awtListener_private.removeListeners(EventID.ADJUSTMENT); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#ITEM ITEM} events + * on each component instance in the Java Virtual Machine when they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeItemListener + */ + static public void addItemListener(ItemListener l) { + if (itemListener_private == null) { + checkInstallPermission(); + awtListener_private.installListeners(EventID.ITEM); + } + itemListener_private = AWTEventMulticaster.add(itemListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives {@link EventID#ITEM ITEM} + * events when they occur. + * + * @param l the listener to remove + * @see #addItemListener + */ + static public void removeItemListener(ItemListener l) { + itemListener_private = AWTEventMulticaster.remove(itemListener_private, l); + if (itemListener_private == null) { + awtListener_private.removeListeners(EventID.ITEM); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#TEXT TEXT} events + * on each component instance in the Java Virtual Machine when they occur. + *

Note: this listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeTextListener + */ + static public void addTextListener(TextListener l) { + if (textListener_private == null) { + checkInstallPermission(); + awtListener_private.installListeners(EventID.TEXT); + } + textListener_private = AWTEventMulticaster.add(textListener_private, l); + } + + /** + * Removes the specified listener so it no longer receives {@link EventID#TEXT TEXT} + * events when they occur. + * + * @param l the listener to remove + * @see #addTextListener + */ + static public void removeTextListener(TextListener l) { + textListener_private = AWTEventMulticaster.remove(textListener_private, l); + if (textListener_private == null) { + awtListener_private.removeListeners(EventID.TEXT); + } + } + + + /** + * AWTEventsListener is the class that does all the work for AWTEventMonitor. + * It is not intended for use by any other class except AWTEventMonitor. + * + */ + + static class AWTEventsListener implements TopLevelWindowListener, + ActionListener, AdjustmentListener, ComponentListener, + ContainerListener, FocusListener, ItemListener, KeyListener, + MouseListener, MouseMotionListener, TextListener, WindowListener, + ChangeListener { + + /** + * internal variables for Action introspection + */ + private java.lang.Class[] actionListeners; + private java.lang.reflect.Method removeActionMethod; + private java.lang.reflect.Method addActionMethod; + private java.lang.Object[] actionArgs; + + /** + * internal variables for Item introspection + */ + private java.lang.Class[] itemListeners; + private java.lang.reflect.Method removeItemMethod; + private java.lang.reflect.Method addItemMethod; + private java.lang.Object[] itemArgs; + + /** + * internal variables for Text introspection + */ + private java.lang.Class[] textListeners; + private java.lang.reflect.Method removeTextMethod; + private java.lang.reflect.Method addTextMethod; + private java.lang.Object[] textArgs; + + /** + * internal variables for Window introspection + */ + private java.lang.Class[] windowListeners; + private java.lang.reflect.Method removeWindowMethod; + private java.lang.reflect.Method addWindowMethod; + private java.lang.Object[] windowArgs; + + /** + * Create a new instance of this class and install it on each component + * instance in the virtual machine that supports any of the currently + * registered listeners in AWTEventMonitor. Also registers itself + * as a TopLevelWindowListener with EventQueueMonitor so it can + * automatically add new listeners to new components. + * + * @see EventQueueMonitor + * @see AWTEventMonitor + */ + public AWTEventsListener() { + String version = System.getProperty("java.version"); + if (version != null) { + runningOnJDK1_4 = (version.compareTo("1.4") >= 0); + } + initializeIntrospection(); + installListeners(); + if (runningOnJDK1_4) { + MenuSelectionManager.defaultManager().addChangeListener(this); + } + EventQueueMonitor.addTopLevelWindowListener(this); + } + + /** + * Set up all of the variables needed for introspection + */ + private boolean initializeIntrospection() { + actionListeners = new java.lang.Class[1]; + actionArgs = new java.lang.Object[1]; + actionListeners[0] = java.awt.event.ActionListener.class; + actionArgs[0] = this; + + itemListeners = new java.lang.Class[1]; + itemArgs = new java.lang.Object[1]; + itemListeners[0] = java.awt.event.ItemListener.class; + itemArgs[0] = this; + + textListeners = new java.lang.Class[1]; + textArgs = new java.lang.Object[1]; + textListeners[0] = java.awt.event.TextListener.class; + textArgs[0] = this; + + windowListeners = new java.lang.Class[1]; + windowArgs = new java.lang.Object[1]; + windowListeners[0] = java.awt.event.WindowListener.class; + windowArgs[0] = this; + + return true; + } + + /** + * Installs all currently registered listeners on all components based + * upon the current topLevelWindows cached by EventQueueMonitor. + * + * @see EventQueueMonitor + * @see AWTEventMonitor + */ + protected void installListeners() { + Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows(); + if (topLevelWindows != null) { + for (int i = 0; i < topLevelWindows.length; i++) { + installListeners(topLevelWindows[i]); + } + } + } + + /** + * Installs listeners for the given event ID on all components based + * upon the current topLevelWindows cached by EventQueueMonitor. + * + * @param eventID the event ID + * @see EventID + */ + protected void installListeners(int eventID) { + Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows(); + if (topLevelWindows != null) { + for (int i = 0; i < topLevelWindows.length; i++) { + installListeners(topLevelWindows[i], eventID); + } + } + } + + /** + * Installs all currently registered listeners to just the component. + * @param c the component to add listeners to + */ + protected void installListeners(Component c) { + + // Container and focus listeners are always installed for our own use. + // + installListeners(c,EventID.CONTAINER); + installListeners(c,EventID.FOCUS); + + // conditionally install low-level listeners + // + if (AWTEventMonitor.componentListener_private != null) { + installListeners(c,EventID.COMPONENT); + } + if (AWTEventMonitor.keyListener_private != null) { + installListeners(c,EventID.KEY); + } + if (AWTEventMonitor.mouseListener_private != null) { + installListeners(c,EventID.MOUSE); + } + if (AWTEventMonitor.mouseMotionListener_private != null) { + installListeners(c,EventID.MOTION); + } + if (AWTEventMonitor.windowListener_private != null) { + installListeners(c,EventID.WINDOW); + } + + // conditionally install Semantic listeners + // + if (AWTEventMonitor.actionListener_private != null) { + installListeners(c,EventID.ACTION); + } + if (AWTEventMonitor.adjustmentListener_private != null) { + installListeners(c,EventID.ADJUSTMENT); + } + if (AWTEventMonitor.itemListener_private != null) { + installListeners(c,EventID.ITEM); + } + if (AWTEventMonitor.textListener_private != null) { + installListeners(c,EventID.TEXT); + } + } + + public void stateChanged(ChangeEvent e) { + processFocusGained(); + } + + private void processFocusGained() { + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); + if (focusOwner == null) { + return; + } + MenuSelectionManager.defaultManager().removeChangeListener(this); + MenuSelectionManager.defaultManager().addChangeListener(this); + + // Only menus and popup selections are handled by the JRootPane. + if (focusOwner instanceof JRootPane) { + MenuElement [] path = + MenuSelectionManager.defaultManager().getSelectedPath(); + if (path.length > 1) { + Component penult = path[path.length-2].getComponent(); + Component last = path[path.length-1].getComponent(); + + if (last instanceof JPopupMenu || + last instanceof JMenu) { + // This is a popup with nothing in the popup + // selected. The menu itself is selected. + componentWithFocus_private = last; + } else if (penult instanceof JPopupMenu) { + // This is a popup with an item selected + componentWithFocus_private = penult; + } + } + } else { + // The focus owner has the selection. + componentWithFocus_private = focusOwner; + } + } + + /** + * Installs the given listener on the component and any of its children. + * As a precaution, it always attempts to remove itself as a listener + * first so it's always guaranteed to have installed itself just once. + * + * @param c the component to add listeners to + * @param eventID the eventID to add listeners for + * @see EventID + */ + protected void installListeners(Component c, int eventID) { + + // install the appropriate listener hook into this component + // + switch (eventID) { + + case EventID.ACTION: + try { + removeActionMethod = c.getClass().getMethod( + "removeActionListener", actionListeners); + addActionMethod = c.getClass().getMethod( + "addActionListener", actionListeners); + try { + removeActionMethod.invoke(c, actionArgs); + addActionMethod.invoke(c, actionArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.ADJUSTMENT: + if (c instanceof Adjustable) { + ((Adjustable) c).removeAdjustmentListener(this); + ((Adjustable) c).addAdjustmentListener(this); + } + break; + + case EventID.COMPONENT: + c.removeComponentListener(this); + c.addComponentListener(this); + break; + + case EventID.CONTAINER: + if (c instanceof Container) { + ((Container) c).removeContainerListener(this); + ((Container) c).addContainerListener(this); + } + break; + + case EventID.FOCUS: + c.removeFocusListener(this); + c.addFocusListener(this); + + if (runningOnJDK1_4) { + processFocusGained(); + + } else { // not runningOnJDK1_4 + if ((c != componentWithFocus_private) && c.hasFocus()) { + componentWithFocus_private = c; + } + } + break; + + case EventID.ITEM: + try { + removeItemMethod = c.getClass().getMethod( + "removeItemListener", itemListeners); + addItemMethod = c.getClass().getMethod( + "addItemListener", itemListeners); + try { + removeItemMethod.invoke(c, itemArgs); + addItemMethod.invoke(c, itemArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + // [PK] CheckboxMenuItem isn't a component but it does + // implement Interface ItemSelectable!! + // if (c instanceof CheckboxMenuItem) { + // ((CheckboxMenuItem) c).removeItemListener(this); + // ((CheckboxMenuItem) c).addItemListener(this); + break; + + case EventID.KEY: + c.removeKeyListener(this); + c.addKeyListener(this); + break; + + case EventID.MOUSE: + c.removeMouseListener(this); + c.addMouseListener(this); + break; + + case EventID.MOTION: + c.removeMouseMotionListener(this); + c.addMouseMotionListener(this); + break; + + case EventID.TEXT: + try { + removeTextMethod = c.getClass().getMethod( + "removeTextListener", textListeners); + addTextMethod = c.getClass().getMethod( + "addTextListener", textListeners); + try { + removeTextMethod.invoke(c, textArgs); + addTextMethod.invoke(c, textArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.WINDOW: + try { + removeWindowMethod = c.getClass().getMethod( + "removeWindowListener", windowListeners); + addWindowMethod = c.getClass().getMethod( + "addWindowListener", windowListeners); + try { + removeWindowMethod.invoke(c, windowArgs); + addWindowMethod.invoke(c, windowArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + // Don't bother recursing the children if this isn't going to + // accomplish anything. + // + default: + return; + } + + // if this component is a container, recurse through children + // + if (c instanceof Container) { + int count = ((Container) c).getComponentCount(); + for (int i = 0; i < count; i++) { + installListeners(((Container) c).getComponent(i), eventID); + } + } + } + + /** + * Removes all listeners for the given event ID on all components based + * upon the topLevelWindows cached by EventQueueMonitor. + * + * @param eventID the event ID + * @see EventID + */ + protected void removeListeners(int eventID) { + Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows(); + if (topLevelWindows != null) { + for (int i = 0; i < topLevelWindows.length; i++) { + removeListeners(topLevelWindows[i], eventID); + } + } + } + + /** + * Removes all listeners for the given component and all its children. + * @param c the component + */ + protected void removeListeners(Component c) { + + // conditionally remove low-level listeners + // + if (AWTEventMonitor.componentListener_private != null) { + removeListeners(c,EventID.COMPONENT); + } + if (AWTEventMonitor.keyListener_private != null) { + removeListeners(c,EventID.KEY); + } + if (AWTEventMonitor.mouseListener_private != null) { + removeListeners(c,EventID.MOUSE); + } + if (AWTEventMonitor.mouseMotionListener_private != null) { + removeListeners(c,EventID.MOTION); + } + if (AWTEventMonitor.windowListener_private != null) { + removeListeners(c,EventID.WINDOW); + } + + // Remove semantic listeners + // + if (AWTEventMonitor.actionListener_private != null) { + removeListeners(c,EventID.ACTION); + } + if (AWTEventMonitor.adjustmentListener_private != null) { + removeListeners(c,EventID.ADJUSTMENT); + } + if (AWTEventMonitor.itemListener_private != null) { + removeListeners(c,EventID.ITEM); + } + if (AWTEventMonitor.textListener_private != null) { + removeListeners(c,EventID.TEXT); + } + } + + /** + * Removes all listeners for the event ID from the component and all + * of its children. + * + * @param c the component to remove listeners from + * @see EventID + */ + protected void removeListeners(Component c, int eventID) { + + // remove the appropriate listener hook into this component + // + switch (eventID) { + + case EventID.ACTION: + try { + removeActionMethod = c.getClass().getMethod( + "removeActionListener", + actionListeners); + try { + removeActionMethod.invoke(c, actionArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.ADJUSTMENT: + if (c instanceof Adjustable) { + ((Adjustable) c).removeAdjustmentListener(this); + } + break; + + case EventID.COMPONENT: + c.removeComponentListener(this); + break; + + // Never remove these because we're always interested in them + // for our own use. + //case EventID.CONTAINER: + // if (c instanceof Container) { + // ((Container) c).removeContainerListener(this); + // } + // break; + // + //case EventID.FOCUS: + // c.removeFocusListener(this); + // break; + + case EventID.ITEM: + try { + removeItemMethod = c.getClass().getMethod( + "removeItemListener", itemListeners); + try { + removeItemMethod.invoke(c, itemArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + // [PK] CheckboxMenuItem isn't a component but it does + // implement Interface ItemSelectable!! + // if (c instanceof CheckboxMenuItem) { + // ((CheckboxMenuItem) c).removeItemListener(this); + break; + + case EventID.KEY: + c.removeKeyListener(this); + break; + + case EventID.MOUSE: + c.removeMouseListener(this); + break; + + case EventID.MOTION: + c.removeMouseMotionListener(this); + break; + + case EventID.TEXT: + try { + removeTextMethod = c.getClass().getMethod( + "removeTextListener", textListeners); + try { + removeTextMethod.invoke(c, textArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.WINDOW: + try { + removeWindowMethod = c.getClass().getMethod( + "removeWindowListener", windowListeners); + try { + removeWindowMethod.invoke(c, windowArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + default: + return; + } + + if (c instanceof Container) { + int count = ((Container) c).getComponentCount(); + for (int i = 0; i < count; i++) { + removeListeners(((Container) c).getComponent(i), eventID); + } + } + } + + /********************************************************************/ + /* */ + /* Listener Interface Methods */ + /* */ + /********************************************************************/ + + /* TopLevelWindow Methods ***************************************/ + + /** + * Called when top level window is created. + * + * @see EventQueueMonitor + * @see EventQueueMonitor#addTopLevelWindowListener + */ + public void topLevelWindowCreated(Window w) { + installListeners(w); + } + + /** + * Called when top level window is destroyed. + * + * @see EventQueueMonitor + * @see EventQueueMonitor#addTopLevelWindowListener + */ + public void topLevelWindowDestroyed(Window w) { + } + + /* ActionListener Methods ***************************************/ + + /** + * Called when an action is performed. + * + * @see AWTEventMonitor#addActionListener + */ + public void actionPerformed(ActionEvent e) { + if (AWTEventMonitor.actionListener_private != null) { + AWTEventMonitor.actionListener_private.actionPerformed(e); + } + } + + /* AdjustmentListener Methods ***********************************/ + + /** + * Called when an adjustment is made. + * + * @see AWTEventMonitor#addAdjustmentListener + */ + public void adjustmentValueChanged(AdjustmentEvent e) { + if (AWTEventMonitor.adjustmentListener_private != null) { + AWTEventMonitor.adjustmentListener_private.adjustmentValueChanged(e); + } + } + + /* ComponentListener Methods ************************************/ + + /** + * Called when a component is hidden. + * + * @see AWTEventMonitor#addComponentListener + */ + public void componentHidden(ComponentEvent e) { + if (AWTEventMonitor.componentListener_private != null) { + AWTEventMonitor.componentListener_private.componentHidden(e); + } + } + + /** + * Called when a component is moved. + * + * @see AWTEventMonitor#addComponentListener + */ + public void componentMoved(ComponentEvent e) { + if (AWTEventMonitor.componentListener_private != null) { + AWTEventMonitor.componentListener_private.componentMoved(e); + } + } + + /** + * Called when a component is resized. + * + * @see AWTEventMonitor#addComponentListener + */ + public void componentResized(ComponentEvent e) { + if (AWTEventMonitor.componentListener_private != null) { + AWTEventMonitor.componentListener_private.componentResized(e); + } + } + + /** + * Called when a component is shown. + * + * @see AWTEventMonitor#addComponentListener + */ + public void componentShown(ComponentEvent e) { + if (AWTEventMonitor.componentListener_private != null) { + AWTEventMonitor.componentListener_private.componentShown(e); + } + } + + /* ContainerListener Methods ************************************/ + + /** + * Called when a component is added to a container. + * + * @see AWTEventMonitor#addContainerListener + */ + public void componentAdded(ContainerEvent e) { + installListeners(e.getChild()); + if (AWTEventMonitor.containerListener_private != null) { + AWTEventMonitor.containerListener_private.componentAdded(e); + } + } + + /** + * Called when a component is removed from a container. + * + * @see AWTEventMonitor#addContainerListener + */ + public void componentRemoved(ContainerEvent e) { + removeListeners(e.getChild()); + if (AWTEventMonitor.containerListener_private != null) { + AWTEventMonitor.containerListener_private.componentRemoved(e); + } + } + + /* FocusListener Methods ****************************************/ + + /** + * Called when a component gains keyboard focus. + * + * @see AWTEventMonitor#addFocusListener + */ + public void focusGained(FocusEvent e) { + AWTEventMonitor.componentWithFocus_private = (Component) e.getSource(); + if (AWTEventMonitor.focusListener_private != null) { + AWTEventMonitor.focusListener_private.focusGained(e); + } + } + + /** + * Called when a component loses keyboard focus. + * + * @see AWTEventMonitor#addFocusListener + */ + public void focusLost(FocusEvent e) { + AWTEventMonitor.componentWithFocus_private = null; + if (AWTEventMonitor.focusListener_private != null) { + AWTEventMonitor.focusListener_private.focusLost(e); + } + } + + /* ItemListener Methods *****************************************/ + + /** + * Called when an item's state changes. + * + * @see AWTEventMonitor#addItemListener + */ + public void itemStateChanged(ItemEvent e) { + if (AWTEventMonitor.itemListener_private != null) { + AWTEventMonitor.itemListener_private.itemStateChanged(e); + } + } + + /* KeyListener Methods ******************************************/ + + /** + * Called when a key is pressed. + * + * @see AWTEventMonitor#addKeyListener + */ + public void keyPressed(KeyEvent e) { + if (AWTEventMonitor.keyListener_private != null) { + AWTEventMonitor.keyListener_private.keyPressed(e); + } + } + + /** + * Called when a key is typed. + * + * @see AWTEventMonitor#addKeyListener + */ + public void keyReleased(KeyEvent e) { + if (AWTEventMonitor.keyListener_private != null) { + AWTEventMonitor.keyListener_private.keyReleased(e); + } + } + + /** + * Called when a key is released. + * + * @see AWTEventMonitor#addKeyListener + */ + public void keyTyped(KeyEvent e) { + if (AWTEventMonitor.keyListener_private != null) { + AWTEventMonitor.keyListener_private.keyTyped(e); + } + } + + /* MouseListener Methods ****************************************/ + + /** + * Called when the mouse is clicked. + * + * @see AWTEventMonitor#addMouseListener + */ + public void mouseClicked(MouseEvent e) { + if (AWTEventMonitor.mouseListener_private != null) { + AWTEventMonitor.mouseListener_private.mouseClicked(e); + } + } + + /** + * Called when the mouse enters a component. + * + * @see AWTEventMonitor#addMouseListener + */ + public void mouseEntered(MouseEvent e) { + if (AWTEventMonitor.mouseListener_private != null) { + AWTEventMonitor.mouseListener_private.mouseEntered(e); + } + } + + /** + * Called when the mouse leaves a component. + * + * @see AWTEventMonitor#addMouseListener + */ + public void mouseExited(MouseEvent e) { + if (AWTEventMonitor.mouseListener_private != null) { + AWTEventMonitor.mouseListener_private.mouseExited(e); + } + } + + /** + * Called when the mouse is pressed. + * + * @see AWTEventMonitor#addMouseListener + */ + public void mousePressed(MouseEvent e) { + if (AWTEventMonitor.mouseListener_private != null) { + AWTEventMonitor.mouseListener_private.mousePressed(e); + } + } + + /** + * Called when the mouse is released. + * + * @see AWTEventMonitor#addMouseListener + */ + public void mouseReleased(MouseEvent e) { + if (AWTEventMonitor.mouseListener_private != null) { + AWTEventMonitor.mouseListener_private.mouseReleased(e); + } + } + + /* MouseMotionListener Methods **********************************/ + + /** + * Called when the mouse is dragged. + * + * @see AWTEventMonitor#addMouseMotionListener + */ + public void mouseDragged(MouseEvent e) { + if (AWTEventMonitor.mouseMotionListener_private != null) { + AWTEventMonitor.mouseMotionListener_private.mouseDragged(e); + } + } + + /** + * Called when the mouse is moved. + * + * @see AWTEventMonitor#addMouseMotionListener + */ + public void mouseMoved(MouseEvent e) { + if (AWTEventMonitor.mouseMotionListener_private != null) { + AWTEventMonitor.mouseMotionListener_private.mouseMoved(e); + } + } + + /* TextListener Methods *****************************************/ + + /** + * Called when a component's text value changed. + * + * @see AWTEventMonitor#addTextListener + */ + public void textValueChanged(TextEvent e) { + if (AWTEventMonitor.textListener_private != null) { + AWTEventMonitor.textListener_private.textValueChanged(e); + } + } + + /* WindowListener Methods ***************************************/ + + /** + * Called when a window is opened. + * + * @see AWTEventMonitor#addWindowListener + */ + public void windowOpened(WindowEvent e) { + if (AWTEventMonitor.windowListener_private != null) { + AWTEventMonitor.windowListener_private.windowOpened(e); + } + } + + /** + * Called when a window is in the process of closing. + * + * @see AWTEventMonitor#addWindowListener + */ + public void windowClosing(WindowEvent e) { + if (AWTEventMonitor.windowListener_private != null) { + AWTEventMonitor.windowListener_private.windowClosing(e); + } + } + + /** + * Called when a window is closed. + * + * @see AWTEventMonitor#addWindowListener + */ + public void windowClosed(WindowEvent e) { + if (AWTEventMonitor.windowListener_private != null) { + AWTEventMonitor.windowListener_private.windowClosed(e); + } + } + + /** + * Called when a window is iconified. + * + * @see AWTEventMonitor#addWindowListener + */ + public void windowIconified(WindowEvent e) { + if (AWTEventMonitor.windowListener_private != null) { + AWTEventMonitor.windowListener_private.windowIconified(e); + } + } + + /** + * Called when a window is deiconified. + * + * @see AWTEventMonitor#addWindowListener + */ + public void windowDeiconified(WindowEvent e) { + if (AWTEventMonitor.windowListener_private != null) { + AWTEventMonitor.windowListener_private.windowDeiconified(e); + } + } + + /** + * Called when a window is activated. + * + * @see AWTEventMonitor#addWindowListener + */ + public void windowActivated(WindowEvent e) { + if (AWTEventMonitor.windowListener_private != null) { + AWTEventMonitor.windowListener_private.windowActivated(e); + } + } + + /** + * Called when a window is deactivated. + * + * @see AWTEventMonitor#addWindowListener + */ + public void windowDeactivated(WindowEvent e) { + if (AWTEventMonitor.windowListener_private != null) { + AWTEventMonitor.windowListener_private.windowDeactivated(e); + } + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityEventMonitor.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util; + +import java.util.*; +import java.beans.*; +import java.awt.*; +import java.awt.event.*; +import javax.accessibility.*; + +/** + *

{@code AccessibilityEventMonitor} implements a PropertyChange listener + * on every UI object that implements interface {@code Accessible} in the Java + * Virtual Machine. The events captured by these listeners are made available + * through listeners supported by {@code AccessibilityEventMonitor}. + * With this, all the individual events on each of the UI object + * instances are funneled into one set of PropertyChange listeners. + *

This class depends upon {@link EventQueueMonitor}, which provides the base + * level support for capturing the top-level containers as they are created. + * + */ + +@jdk.Exported +public class AccessibilityEventMonitor { + + // listeners + /** + * The current list of registered {@link java.beans.PropertyChangeListener + * PropertyChangeListener} classes. + * + * @see #addPropertyChangeListener + * @see #removePropertyChangeListener + */ + static protected final AccessibilityListenerList listenerList = + new AccessibilityListenerList(); + + + /** + * The actual listener that is installed on the component instances. + * This listener calls the other registered listeners when an event + * occurs. By doing things this way, the actual number of listeners + * installed on a component instance is drastically reduced. + */ + static protected final AccessibilityEventListener accessibilityListener = + new AccessibilityEventListener(); + + /** + * Adds the specified listener to receive all PropertyChange events on + * each UI object instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to UI object instances that support this listener type. + * + * @param l the listener to add + * + * @see #removePropertyChangeListener + */ + static public void addPropertyChangeListener(PropertyChangeListener l) { + if (listenerList.getListenerCount(PropertyChangeListener.class) == 0) { + accessibilityListener.installListeners(); + } + listenerList.add(PropertyChangeListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives PropertyChange + * events when they occur. + * @see #addPropertyChangeListener + * @param l the listener to remove + */ + static public void removePropertyChangeListener(PropertyChangeListener l) { + listenerList.remove(PropertyChangeListener.class, l); + if (listenerList.getListenerCount(PropertyChangeListener.class) == 0) { + accessibilityListener.removeListeners(); + } + } + + + /** + * AccessibilityEventListener is the class that does all the work for + * AccessibilityEventMonitor. It is not intended for use by any other + * class except AccessibilityEventMonitor. + * + */ + + static class AccessibilityEventListener implements TopLevelWindowListener, + PropertyChangeListener { + + /** + * Create a new instance of this class and install it on each component + * instance in the virtual machine that supports any of the currently + * registered listeners in AccessibilityEventMonitor. Also registers + * itself as a TopLevelWindowListener with EventQueueMonitor so it can + * automatically add new listeners to new components. + * @see EventQueueMonitor + * @see AccessibilityEventMonitor + */ + public AccessibilityEventListener() { + EventQueueMonitor.addTopLevelWindowListener(this); + } + + /** + * Installs PropertyChange listeners on all Accessible objects based + * upon the current topLevelWindows cached by EventQueueMonitor. + * @see EventQueueMonitor + * @see AWTEventMonitor + */ + protected void installListeners() { + Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows(); + if (topLevelWindows != null) { + for (int i = 0; i < topLevelWindows.length; i++) { + if (topLevelWindows[i] instanceof Accessible) { + installListeners((Accessible) topLevelWindows[i]); + } + } + } + } + + /** + * Installs PropertyChange listeners to the Accessible object, and it's + * children (so long as the object isn't of TRANSIENT state). + * @param a the Accessible object to add listeners to + */ + protected void installListeners(Accessible a) { + installListeners(a.getAccessibleContext()); + } + + /** + * Installs PropertyChange listeners to the AccessibleContext object, + * and it's * children (so long as the object isn't of TRANSIENT state). + * @param a the Accessible object to add listeners to + */ + private void installListeners(AccessibleContext ac) { + + if (ac != null) { + AccessibleStateSet states = ac.getAccessibleStateSet(); + if (!states.contains(AccessibleState.TRANSIENT)) { + ac.addPropertyChangeListener(this); + /* + * Don't add listeners to transient children. Components + * with transient children should return an AccessibleStateSet + * containing AccessibleState.MANAGES_DESCENDANTS. Components + * may not explicitly return the MANAGES_DESCENDANTS state. + * In this case, don't add listeners to the children of + * lists, tables and trees. + */ + AccessibleStateSet set = ac.getAccessibleStateSet(); + if (set.contains(_AccessibleState.MANAGES_DESCENDANTS)) { + return; + } + AccessibleRole role = ac.getAccessibleRole(); + if (role == AccessibleRole.LIST || + role == AccessibleRole.TREE) { + return; + } + if (role == AccessibleRole.TABLE) { + // handle Oracle tables containing tables + Accessible child = ac.getAccessibleChild(0); + if (child != null) { + AccessibleContext ac2 = child.getAccessibleContext(); + if (ac2 != null) { + role = ac2.getAccessibleRole(); + if (role != null && role != AccessibleRole.TABLE) { + return; + } + } + } + } + int count = ac.getAccessibleChildrenCount(); + for (int i = 0; i < count; i++) { + Accessible child = ac.getAccessibleChild(i); + if (child != null) { + installListeners(child); + } + } + } + } + } + + /** + * Removes PropertyChange listeners on all Accessible objects based + * upon the topLevelWindows cached by EventQueueMonitor. + * @param eventID the event ID + * @see EventID + */ + protected void removeListeners() { + Window topLevelWindows[] = EventQueueMonitor.getTopLevelWindows(); + if (topLevelWindows != null) { + for (int i = 0; i < topLevelWindows.length; i++) { + if (topLevelWindows[i] instanceof Accessible) { + removeListeners((Accessible) topLevelWindows[i]); + } + } + } + } + + /** + * Removes PropertyChange listeners for the given Accessible object, + * it's children (so long as the object isn't of TRANSIENT state). + * @param a the Accessible object to remove listeners from + */ + protected void removeListeners(Accessible a) { + removeListeners(a.getAccessibleContext()); + } + + /** + * Removes PropertyChange listeners for the given AccessibleContext + * object, it's children (so long as the object isn't of TRANSIENT + * state). + * @param a the Accessible object to remove listeners from + */ + private void removeListeners(AccessibleContext ac) { + + + if (ac != null) { + // Listeners are not added to transient components. + AccessibleStateSet states = ac.getAccessibleStateSet(); + if (!states.contains(AccessibleState.TRANSIENT)) { + ac.removePropertyChangeListener(this); + /* + * Listeners are not added to transient children. Components + * with transient children should return an AccessibleStateSet + * containing AccessibleState.MANAGES_DESCENDANTS. Components + * may not explicitly return the MANAGES_DESCENDANTS state. + * In this case, don't remove listeners from the children of + * lists, tables and trees. + */ + if (states.contains(_AccessibleState.MANAGES_DESCENDANTS)) { + return; + } + AccessibleRole role = ac.getAccessibleRole(); + if (role == AccessibleRole.LIST || + role == AccessibleRole.TABLE || + role == AccessibleRole.TREE) { + return; + } + int count = ac.getAccessibleChildrenCount(); + for (int i = 0; i < count; i++) { + Accessible child = ac.getAccessibleChild(i); + if (child != null) { + removeListeners(child); + } + } + } + } + } + + /********************************************************************/ + /* */ + /* Listener Interface Methods */ + /* */ + /********************************************************************/ + + /* TopLevelWindow Methods ***************************************/ + + /** + * Called when top level window is created. + * @see EventQueueMonitor + * @see EventQueueMonitor#addTopLevelWindowListener + */ + public void topLevelWindowCreated(Window w) { + if (w instanceof Accessible) { + installListeners((Accessible) w); + } + } + + /** + * Called when top level window is destroyed. + * @see EventQueueMonitor + * @see EventQueueMonitor#addTopLevelWindowListener + */ + public void topLevelWindowDestroyed(Window w) { + if (w instanceof Accessible) { + removeListeners((Accessible) w); + } + } + + + /* PropertyChangeListener Methods **************************************/ + + public void propertyChange(PropertyChangeEvent e) { + // propogate the event + Object[] listeners = + AccessibilityEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==PropertyChangeListener.class) { + ((PropertyChangeListener)listeners[i+1]).propertyChange(e); + } + } + + // handle childbirth/death + String name = e.getPropertyName(); + if (name.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) { + Object oldValue = e.getOldValue(); + Object newValue = e.getNewValue(); + + if ((oldValue == null) ^ (newValue == null)) { // one null, not both + if (oldValue != null) { + // this Accessible is a child that's going away + if (oldValue instanceof Accessible) { + Accessible a = (Accessible) oldValue; + removeListeners(a.getAccessibleContext()); + } else if (oldValue instanceof AccessibleContext) { + removeListeners((AccessibleContext) oldValue); + } + } else if (newValue != null) { + // this Accessible is a child was just born + if (newValue instanceof Accessible) { + Accessible a = (Accessible) newValue; + installListeners(a.getAccessibleContext()); + } else if (newValue instanceof AccessibleContext) { + installListeners((AccessibleContext) newValue); + } + } + } else { + System.out.println("ERROR in usage of PropertyChangeEvents for: " + e.toString()); + } + } + } + } +} + +/* + * workaround for no public AccessibleState constructor + */ +class _AccessibleState extends AccessibleState { + /** + * Indicates this object is responsible for managing its + * subcomponents. This is typically used for trees and tables + * that have a large number of subcomponents and where the + * objects are created only when needed and otherwise remain virtual. + * The application should not manage the subcomponents directly. + */ + public static final _AccessibleState MANAGES_DESCENDANTS + = new _AccessibleState ("managesDescendants"); + + /** + * Creates a new AccessibleState using the given locale independent key. + * This should not be a public method. Instead, it is used to create + * the constants in this file to make it a strongly typed enumeration. + * Subclasses of this class should enforce similar policy. + *

+ * The key String should be a locale independent key for the state. + * It is not intended to be used as the actual String to display + * to the user. To get the localized string, use toDisplayString. + * + * @param key the locale independent name of the state. + * @see AccessibleBundle#toDisplayString + */ + protected _AccessibleState(String key) { + super(key); + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityListenerList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/AccessibilityListenerList.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2005, 2015, 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 com.sun.java.accessibility.util; + +import java.util.*; +import java.beans.*; +import java.awt.*; +import java.awt.event.*; +import javax.accessibility.*; + +/** + *

The {@code AccessibilityListenerList} is a copy of the Swing + * {@link javax.swing.event.EventListenerList EventListerList} class. + * + */ + +@jdk.Exported +public class AccessibilityListenerList { + /* A null array to be shared by all empty listener lists */ + private final static Object[] NULL_ARRAY = new Object[0]; + + /** + * The list of listener type, listener pairs + */ + protected transient Object[] listenerList = NULL_ARRAY; + + /** + * Passes back the event listener list as an array of listener type, listener pairs. + * Note that for performance reasons, this implementation passes back the actual + * data structure in which the listener data is stored internally. This method + * is guaranteed to pass back a non-null array, so that no null-checking + * is required in fire methods. A zero-length array of Object is returned if + * there are currently no listeners. + *

+ * Absolutely no modification of the data contained in this array should be + * made. If any such manipulation is necessary, it should be done on a copy + * of the array returned rather than the array itself. + * + * @return an array of listener type, listener pairs. + */ + public Object[] getListenerList() { + return listenerList; + } + + /** + * Returns the total number of listeners for this listener list. + * + * @return the total number of listeners for this listener list. + */ + public int getListenerCount() { + return listenerList.length/2; + } + + /** + * Return the total number of listeners of the supplied type + * for this listener list. + * + * @param t the type of the listener to be counted + * @return the number of listeners found + */ + public int getListenerCount(Class t) { + int count = 0; + Object[] lList = listenerList; + for (int i = 0; i < lList.length; i+=2) { + if (t == (Class)lList[i]) + count++; + } + return count; + } + + /** + * Add the listener as a listener of the specified type. + * + * @param t the type of the listener to be added + * @param l the listener to be added + */ + public synchronized void add(Class t, EventListener l) { + if (!t.isInstance(l)) { + throw new IllegalArgumentException("Listener " + l + + " is not of type " + t); + } + if (l ==null) { + throw new IllegalArgumentException("Listener " + l + + " is null"); + } + if (listenerList == NULL_ARRAY) { + // if this is the first listener added, + // initialize the lists + listenerList = new Object[] { t, l }; + } else { + // Otherwise copy the array and add the new listener + int i = listenerList.length; + Object[] tmp = new Object[i+2]; + System.arraycopy(listenerList, 0, tmp, 0, i); + + tmp[i] = t; + tmp[i+1] = l; + + listenerList = tmp; + } + } + + /** + * Remove the listener as a listener of the specified type. + * + * @param t the type of the listener to be removed + * @param l the listener to be removed + */ + public synchronized void remove(Class t, EventListener l) { + if (!t.isInstance(l)) { + throw new IllegalArgumentException("Listener " + l + + " is not of type " + t); + } + if (l ==null) { + throw new IllegalArgumentException("Listener " + l + + " is null"); + } + + // Is l on the list? + int index = -1; + for (int i = listenerList.length-2; i>=0; i-=2) { + if ((listenerList[i]==t) && (listenerList[i+1] == l)) { + index = i; + break; + } + } + + // If so, remove it + if (index != -1) { + Object[] tmp = new Object[listenerList.length-2]; + // Copy the list up to index + System.arraycopy(listenerList, 0, tmp, 0, index); + // Copy from two past the index, up to + // the end of tmp (which is two elements + // shorter than the old list) + if (index < tmp.length) + System.arraycopy(listenerList, index+2, tmp, index, + tmp.length - index); + // set the listener array to the new array or null + listenerList = (tmp.length == 0) ? NULL_ARRAY : tmp; + } + } + + /** + * Return a string representation of the {@code AccessibilityListenerList}. + * + * @return a string representation of the {@code AccessibilityListenerList}. + */ + public String toString() { + Object[] lList = listenerList; + String s = "EventListenerList: "; + s += lList.length/2 + " listeners: "; + for (int i = 0 ; i <= lList.length-2 ; i+=2) { + s += " type " + ((Class)lList[i]).getName(); + s += " listener " + lList[i+1]; + } + return s; + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/EventID.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/EventID.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util; + +/** + * EventID contains integer constants that map to event support in + * AWT and Swing. They are used by primarily by AWTEventMonitor, + * AWTEventsListener, SwingEventMonitor, and SwingEventListener, but + * can be freely used by any other class. + * + * @see AWTEventMonitor + * @see SwingEventMonitor + * + */ +@jdk.Exported +public class EventID { + + /** + * Maps to AWT Action support (i.e., ActionListener and ActionEvent) + */ + static public final int ACTION = 0; + + /** + * Maps to AWT Adjustment support (i.e., AdjustmentListener + * and AdjustmentEvent) + */ + static public final int ADJUSTMENT = 1; + + /** + * Maps to AWT Component support (i.e., ComponentListener + * and ComponentEvent) + */ + static public final int COMPONENT = 2; + + /** + * Maps to AWT Container support (i.e., ContainerListener + * and ContainerEvent) + */ + static public final int CONTAINER = 3; + + /** + * Maps to AWT Focus support (i.e., FocusListener and FocusEvent) + */ + static public final int FOCUS = 4; + + /** + * Maps to AWT Item support (i.e., ItemListener and ItemEvent) + */ + static public final int ITEM = 5; + + /** + * Maps to AWT Key support (i.e., KeyListener and KeyEvent) + */ + static public final int KEY = 6; + + /** + * Maps to AWT Mouse support (i.e., MouseListener and MouseEvent) + */ + static public final int MOUSE = 7; + + /** + * Maps to AWT MouseMotion support (i.e., MouseMotionListener + * and MouseMotionEvent) + */ + static public final int MOTION = 8; + + /** + * Maps to AWT Text support (i.e., TextListener and TextEvent) + */ + static public final int TEXT = 10; + + /** + * Maps to AWT Window support (i.e., WindowListener and WindowEvent) + */ + static public final int WINDOW = 11; + + /** + * Maps to Swing Ancestor support (i.e., AncestorListener and + * AncestorEvent) + */ + static public final int ANCESTOR = 12; + + /** + * Maps to Swing Text Caret support (i.e., CaretListener and + * CaretEvent) + */ + static public final int CARET = 13; + + /** + * Maps to Swing CellEditor support (i.e., CellEditorListener and + * CellEditorEvent) + */ + static public final int CELLEDITOR = 14; + + /** + * Maps to Swing Change support (i.e., ChangeListener and + * ChangeEvent) + */ + static public final int CHANGE = 15; + + /** + * Maps to Swing TableColumnModel support (i.e., + * TableColumnModelListener and TableColumnModelEvent) + */ + static public final int COLUMNMODEL = 16; + + /** + * Maps to Swing Document support (i.e., DocumentListener and + * DocumentEvent) + */ + static public final int DOCUMENT = 17; + + /** + * Maps to Swing ListData support (i.e., ListDataListener and + * ListDataEvent) + */ + static public final int LISTDATA = 18; + + /** + * Maps to Swing ListSelection support (i.e., ListSelectionListener and + * ListSelectionEvent) + */ + static public final int LISTSELECTION = 19; + + /** + * Maps to Swing Menu support (i.e., MenuListener and + * MenuEvent) + */ + static public final int MENU = 20; + + /** + * Maps to Swing PopupMenu support (i.e., PopupMenuListener and + * PopupMenuEvent) + */ + static public final int POPUPMENU = 21; + + /** + * Maps to Swing TableModel support (i.e., TableModelListener and + * TableModelEvent) + */ + static public final int TABLEMODEL = 22; + + /** + * Maps to Swing TreeExpansion support (i.e., TreeExpansionListener and + * TreeExpansionEvent) + */ + static public final int TREEEXPANSION = 23; + + /** + * Maps to Swing TreeModel support (i.e., TreeModelListener and + * TreeModelEvent) + */ + static public final int TREEMODEL = 24; + + /** + * Maps to Swing TreeSelection support (i.e., TreeSelectionListener and + * TreeSelectionEvent) + */ + static public final int TREESELECTION = 25; + + /** + * Maps to Swing UndoableEdit support (i.e., UndoableEditListener and + * UndoableEditEvent) + */ + static public final int UNDOABLEEDIT = 26; + + /** + * Maps to Beans PropertyChange support (i.e., PropertyChangeListener + * and PropertyChangeEvent) + */ + static public final int PROPERTYCHANGE = 27; + + /** + * Maps to Beans VetoableChange support (i.e., VetoableChangeListener + * and VetoableChangeEvent) + */ + static public final int VETOABLECHANGE = 28; + + /** + * Maps to Swing InternalFrame support (i.e., InternalFrameListener) + */ + static public final int INTERNALFRAME = 29; +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/EventQueueMonitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/EventQueueMonitor.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,619 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util; + +import java.util.*; +import java.awt.*; +import java.awt.event.*; +import javax.accessibility.*; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * The {@code EventQueueMonitor} class provides key core functionality for Assistive + * Technologies (and other system-level technologies that need some of the same + * things that Assistive Technology needs). + * + * @see AWTEventMonitor + * @see SwingEventMonitor + */ +@jdk.Exported +public class EventQueueMonitor + implements AWTEventListener { + + // NOTE: All of the following properties are static. The reason + // for this is that there may be multiple EventQueue instances + // in use in the same VM. By making these properties static, + // we can guarantee we get the information from all of the + // EventQueue instances. + + // The stuff that is cached. + // + static VectortopLevelWindows = new Vector<>(); + static Window topLevelWindowWithFocus = null; + static Point currentMousePosition = null; + static Component currentMouseComponent = null; + + // Low-level listener interfaces + // + static GUIInitializedListener guiInitializedListener = null; + static TopLevelWindowListener topLevelWindowListener = null; + static MouseMotionListener mouseMotionListener = null; + + /** + * Class variable stating whether the assistive technologies have + * been loaded yet or not. The assistive technologies won't be + * loaded until the first event is posted to the EventQueue. This + * gives the toolkit a chance to do all the necessary initialization + * it needs to do. + */ + + /** + * Class variable stating whether the GUI subsystem has been initialized + * or not. + * + * @see #isGUIInitialized + */ + static boolean guiInitialized = false; + + /** + * Queue that holds events for later processing. + */ + static EventQueueMonitorItem componentEventQueue = null; + + /** + * Class that tells us what the component event dispatch thread is. + */ + static private ComponentEvtDispatchThread cedt = null; + + /** + * Handle the synchronization between the thing that populates the + * component event dispatch thread ({@link #queueComponentEvent}) + * and the thing that processes the events ({@link ComponentEvtDispatchThread}). + */ + static Object componentEventQueueLock = new Object(); + + /** + * Create a new {@code EventQueueMonitor} instance. Normally, this will + * be called only by the AWT Toolkit during initialization time. + * Assistive technologies should not create instances of + * EventQueueMonitor by themselves. Instead, they should either + * refer to it directly via the static methods in this class, e.g., + * {@link #getCurrentMousePosition} or obtain the instance by asking the + * Toolkit, e.g., {@link java.awt.Toolkit#getSystemEventQueue}. + */ + public EventQueueMonitor() { + if (cedt == null) { + cedt = new ComponentEvtDispatchThread("EventQueueMonitor-ComponentEvtDispatch"); + + cedt.setDaemon(true); + cedt.start(); + } + } + + /** + * Queue up a {@link java.awt.event.ComponentEvent ComponentEvent} for later + * processing by the {@link ComponentEvtDispatch} thread. + * + * @param e a {@code ComponentEvent} + */ + static void queueComponentEvent(ComponentEvent e) { + synchronized(componentEventQueueLock) { + EventQueueMonitorItem eqi = new EventQueueMonitorItem(e); + if (componentEventQueue == null) { + componentEventQueue = eqi; + } else { + EventQueueMonitorItem q = componentEventQueue; + while (true) { + if (q.next != null) { + q = q.next; + } else { + break; + } + } + q.next = eqi; + } + componentEventQueueLock.notifyAll(); + } + } + + /** + * Tell the {@code EventQueueMonitor} to start listening for events. + */ + public static void maybeInitialize() { + if (cedt == null) { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + try { + long eventMask = AWTEvent.WINDOW_EVENT_MASK | + AWTEvent.FOCUS_EVENT_MASK | + AWTEvent.MOUSE_MOTION_EVENT_MASK; + + Toolkit.getDefaultToolkit().addAWTEventListener(new EventQueueMonitor(), eventMask); + } catch (Exception e) { + } + return null; + } + } + ); + } + } + + /** + * Handle events as a result of registering a listener + * on the {@link java.awt.EventQueue EventQueue} in {@link #maybeInitialize}. + */ + public void eventDispatched(AWTEvent theEvent) { + processEvent(theEvent); + } + + /** + * Assisitive technologies that have + * registered a {@link GUIInitializedListener} will be notified. + * + * @see #addGUIInitializedListener + */ + static void maybeNotifyAssistiveTechnologies() { + + if (!guiInitialized) { + guiInitialized = true; + if (guiInitializedListener != null) { + guiInitializedListener.guiInitialized(); + } + } + + } + + /********************************************************************/ + /* */ + /* Package Private Methods */ + /* */ + /********************************************************************/ + + /** + * Add a Container to the list of top-level containers + * in the cache. This follows the object's hierarchy up the + * tree until it finds the top most parent. If the parent is + * not already in the list of Containers, it adds it to the list. + * + * @param c the Container + */ + static void addTopLevelWindow(Component c) { + Container parent; + + if (c == null) { + return; + } + + if (!(c instanceof Window)) { + addTopLevelWindow(c.getParent()); + return; + } + + if ((c instanceof Dialog) || (c instanceof Window)) { + parent = (Container) c; + } else { + parent = c.getParent(); + if (parent != null) { + addTopLevelWindow(parent); + return; + } + } + + if (parent == null) { + parent = (Container) c; + } + + // Because this method is static, do not make it synchronized because + // it can lock the whole class. Instead, just lock what needs to be + // locked. + // + synchronized (topLevelWindows) { + if ((parent != null) && !topLevelWindows.contains(parent)) { + topLevelWindows.addElement(parent); + if (topLevelWindowListener != null) { + topLevelWindowListener.topLevelWindowCreated((Window) parent); + } + } + } + } + + /** + * Removes a container from the list of top level containers in the cache. + * + * @param c the top level container to remove + */ + static void removeTopLevelWindow(Window w) { + + // Because this method is static, do not make it synchronized because + // it can lock the whole class. Instead, just lock what needs to be + // locked. + // + synchronized (topLevelWindows) { + if (topLevelWindows.contains(w)) { + topLevelWindows.removeElement(w); + if (topLevelWindowListener != null) { + topLevelWindowListener.topLevelWindowDestroyed(w); + } + } + } + } + + /** + * Update current mouse position. + * + * @param mouseEvent the MouseEvent that holds the new mouse position. + */ + static void updateCurrentMousePosition(MouseEvent mouseEvent) { + Point oldMousePos = currentMousePosition; + // Be careful here. The component in the event might be + // hidden by the time we process the event. + try { + Point eventPoint = mouseEvent.getPoint(); + currentMouseComponent = (Component) (mouseEvent.getSource()); + currentMousePosition = currentMouseComponent.getLocationOnScreen(); + currentMousePosition.translate(eventPoint.x,eventPoint.y); + } catch (Exception e) { + currentMousePosition = oldMousePos; + } + } + + /** + * Process the event. This maintains the event cache in addition + * to calling all the registered listeners. NOTE: The events that + * come through here are from peered Components. + * + * @param theEvent the AWTEvent + */ + static void processEvent(AWTEvent theEvent) { + switch (theEvent.getID()) { + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + case FocusEvent.FOCUS_GAINED: + case WindowEvent.WINDOW_DEACTIVATED: + queueComponentEvent((ComponentEvent) theEvent); + break; + + case WindowEvent.WINDOW_ACTIVATED: + // Dialogs fire WINDOW_ACTIVATED and FOCUS_GAINED events + // before WINDOW_OPENED so we need to add topLevelListeners + // for the dialog when it is first activated to get a + // focus gained event for the focus component in the dialog. + if (theEvent instanceof ComponentEvent) { + ComponentEvent ce = (ComponentEvent)theEvent; + if (ce.getComponent() instanceof Window) { + EventQueueMonitor.addTopLevelWindow(ce.getComponent()); + EventQueueMonitor.maybeNotifyAssistiveTechnologies(); + } else { + EventQueueMonitor.maybeNotifyAssistiveTechnologies(); + EventQueueMonitor.addTopLevelWindow(ce.getComponent()); + } + } + queueComponentEvent((ComponentEvent) theEvent); + break; + + // handle WINDOW_OPENED and WINDOW_CLOSED events synchronously + case WindowEvent.WINDOW_OPENED: + if (theEvent instanceof ComponentEvent) { + ComponentEvent ce = (ComponentEvent)theEvent; + if (ce.getComponent() instanceof Window) { + EventQueueMonitor.addTopLevelWindow(ce.getComponent()); + EventQueueMonitor.maybeNotifyAssistiveTechnologies(); + } else { + EventQueueMonitor.maybeNotifyAssistiveTechnologies(); + EventQueueMonitor.addTopLevelWindow(ce.getComponent()); + } + } + break; + case WindowEvent.WINDOW_CLOSED: + if (theEvent instanceof ComponentEvent) { + ComponentEvent ce = (ComponentEvent)theEvent; + EventQueueMonitor.removeTopLevelWindow((Window) (ce.getComponent())); + } + break; + + default: + break; + } + } + + /** + * Internal test + */ + static synchronized Component getShowingComponentAt(Container c, int x, int y) { + if (!c.contains(x, y)) { + return null; + } + int ncomponents = c.getComponentCount(); + for (int i = 0 ; i < ncomponents ; i++) { + Component comp = c.getComponent(i); + if (comp != null && comp.isShowing()) { + Point location = comp.getLocation(); + if (comp.contains(x - location.x, y - location.y)) { + return comp; + } + } + } + return c; + } + + /** + * Return the Component at the given Point on the screen in the + * given Container. + * + * @param c the Container to search + * @param p the Point in screen coordinates + * @return the Component at the given Point on the screen in the + * given Container -- can be null if no Component is at that Point + */ + static synchronized Component getComponentAt(Container c, Point p) { + if (!c.isShowing()) { + return null; + } + + Component comp; + Point containerLoc = c.getLocationOnScreen(); + Point containerPoint = new Point(p.x - containerLoc.x, + p.y - containerLoc.y); + + comp = getShowingComponentAt(c, containerPoint.x, containerPoint.y); + + if ((comp != c) && (comp instanceof Container)) { + return getComponentAt((Container)comp,p); + } else { + return comp; + } + } + + /** + * Obtain the {@link javax.accessibility.Accessible Accessible} object at the given point on the Screen. + * The return value may be null if an {@code Accessible} object cannot be + * found at the particular point. + * + * @param p the point to be accessed + * @return the {@code Accessible} at the specified point + */ + static public Accessible getAccessibleAt(Point p) { + Window w = getTopLevelWindowWithFocus(); + Window[] wins = getTopLevelWindows(); + Component c = null; + + // See if the point we're being asked about is the + // currentMousePosition. If so, start with the component + // that we know the currentMousePostion is over + // + if (currentMousePosition == null) { + return null; + } + if (currentMousePosition.equals(p)) { + if (currentMouseComponent instanceof Container) { + c = getComponentAt((Container) currentMouseComponent, p); + } + } + + // Try the window with focus next + // + if (c == null && w != null) { + c = getComponentAt(w,p); + } + + // Try the other windows next. [[[WDW: Stacking order???]]] + if (c == null) { + for (int i = 0; i < wins.length; i++) { + c = getComponentAt(wins[i],p); + if (c != null) { + break; + } + } + } + + if (c instanceof Accessible) { + AccessibleContext ac = ((Accessible) c).getAccessibleContext(); + if (ac != null) { + AccessibleComponent acmp = ac.getAccessibleComponent(); + if ((acmp != null) && (ac.getAccessibleChildrenCount() != 0)) { + Point location = acmp.getLocationOnScreen(); + location.move(p.x - location.x, p.y - location.y); + return acmp.getAccessibleAt(location); + } + } + return (Accessible) c; + } else { + return Translator.getAccessible(c); + } + } + + /********************************************************************/ + /* */ + /* Public Methods */ + /* */ + /********************************************************************/ + + /** + * Says whether the GUI subsystem has been initialized or not. + * If this returns true, the assistive technology can freely + * create GUI component instances. If the return value is false, + * the assistive technology should register a {@link GUIInitializedListener} + * and wait to create GUI component instances until the listener is + * called. + * + * @return true if the GUI subsystem has been initialized + * @see #addGUIInitializedListener + */ + static public boolean isGUIInitialized() { + maybeInitialize(); + return guiInitialized; + } + + /** + * Adds the specified listener to be notified when the GUI subsystem + * is initialized. Assistive technologies should get the results of + * {@link #isGUIInitialized} before calling this method. + * + * @param l the listener to add + * @see #isGUIInitialized + * @see #removeTopLevelWindowListener + */ + static public void addGUIInitializedListener(GUIInitializedListener l) { + maybeInitialize(); + guiInitializedListener = + GUIInitializedMulticaster.add(guiInitializedListener,l); + } + + /** + * Removes the specified listener to be notified when the GUI subsystem + * is initialized. + * + * @param l the listener to remove + * @see #addGUIInitializedListener + */ + static public void removeGUIInitializedListener(GUIInitializedListener l) { + guiInitializedListener = + GUIInitializedMulticaster.remove(guiInitializedListener,l); + } + + /** + * Adds the specified listener to be notified when a top level window + * is created or destroyed. + * + * @param l the listener to add + * @see #removeTopLevelWindowListener + */ + static public void addTopLevelWindowListener(TopLevelWindowListener l) { + topLevelWindowListener = + TopLevelWindowMulticaster.add(topLevelWindowListener,l); + } + + /** + * Removes the specified listener to be notified when a top level window + * is created or destroyed. + * + * @param l the listener to remove + * @see #addTopLevelWindowListener + */ + static public void removeTopLevelWindowListener(TopLevelWindowListener l) { + topLevelWindowListener = + TopLevelWindowMulticaster.remove(topLevelWindowListener,l); + } + + /** + * Return the last recorded position of the mouse in screen coordinates. + * + * @return the last recorded position of the mouse in screen coordinates + */ + static public Point getCurrentMousePosition() { + return currentMousePosition; + } + + /** + * Return the list of top level Windows in use in the Java Virtual Machine. + * + * @return an array of top level {@code Window}s in use in the Java Virtual Machine + */ + static public Window[] getTopLevelWindows() { + + // Because this method is static, do not make it synchronized because + // it can lock the whole class. Instead, just lock what needs to be + // locked. + // + synchronized (topLevelWindows) { + int count = topLevelWindows.size(); + if (count > 0) { + Window[] w = new Window[count]; + for (int i = 0; i < count; i++) { + w[i] = (Window)topLevelWindows.elementAt(i); + } + return w; + } else { + return new Window[0]; + } + } + } + + /** + * Return the top level {@code Window} that currently has keyboard focus. + * + * @return the top level {@code Window} that currently has keyboard focus + */ + static public Window getTopLevelWindowWithFocus() { + return topLevelWindowWithFocus; + } +} + +/** + * Handle all Component events in a separate thread. The reason for this is + * that WindowEvents tend to be used to do lots of processing on the Window + * hierarchy. As a result, it can frequently result in deadlock situations. + */ +class ComponentEvtDispatchThread extends Thread { + public ComponentEvtDispatchThread(String name) { + super(name); + } + public void run() { + ComponentEvent ce = null; + while (true) { + synchronized(EventQueueMonitor.componentEventQueueLock) { + while (EventQueueMonitor.componentEventQueue == null) { + try { + EventQueueMonitor.componentEventQueueLock.wait(); + } catch (InterruptedException e) { + } + } + ce = (ComponentEvent)EventQueueMonitor.componentEventQueue.event; + EventQueueMonitor.componentEventQueue = + EventQueueMonitor.componentEventQueue.next; + } + switch (ce.getID()) { + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + EventQueueMonitor.updateCurrentMousePosition((MouseEvent) ce); + break; + case WindowEvent.WINDOW_ACTIVATED: + EventQueueMonitor.maybeNotifyAssistiveTechnologies(); + EventQueueMonitor.topLevelWindowWithFocus = ((WindowEvent) ce).getWindow(); + break; + + default: + break; + } + } + } +} + +/** + * EventQueueMonitorItem is the basic type that handles the + * queue for queueComponentEvent and the ComponentEvtDispatchThread. + */ +class EventQueueMonitorItem { + AWTEvent event; + EventQueueMonitorItem next; + + EventQueueMonitorItem(AWTEvent evt) { + event = evt; + next = null; + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/GUIInitializedListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/GUIInitializedListener.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util; + +import java.awt.*; +import java.util.*; +import javax.accessibility.*; + +/** + * The {@code GUIInitializedListener} interface is used by the {@link EventQueueMonitor} + * class to notify an interested party when the GUI subsystem has been + * initialized. This is necessary because assistive technologies can + * be loaded before the GUI subsystem is initialized. As a result, + * assistive technologies should check the + * {@link EventQueueMonitor#isGUIInitialized isGUIInitialized} method + * of {@code EventQueueMonitor} before creating any GUI components. If the + * return value is true, assistive technologies can create GUI components + * following the same thread restrictions as any other application. If + * the return value is false, the assistive technology should register + * a {@code GUIInitializedListener} with the {@code EventQueueMonitor} to be notified + * when the GUI subsystem is initialized. + * + * @see EventQueueMonitor + * @see EventQueueMonitor#isGUIInitialized + * @see EventQueueMonitor#addGUIInitializedListener + * @see EventQueueMonitor#removeGUIInitializedListener + * + */ +@jdk.Exported +public interface GUIInitializedListener extends EventListener { + + /** + * Invoked when the GUI subsystem is initialized and it's OK for + * the assisitive technology to create instances of GUI objects. + */ + public void guiInitialized(); + +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/GUIInitializedMulticaster.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/GUIInitializedMulticaster.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2005, 2015, 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 com.sun.java.accessibility.util; + +import java.awt.*; +import java.util.EventListener; +import javax.accessibility.*; + + +/** + * The GUIInitializedMulticaster class is used to maintain a list of + * GUIInitializedListener classes. It is intended to be used primarily + * for internal support in the EventQueueMonitor class, and is not intended + * to be used by classes outside the Java Accessibility Utility package. + * + * @see EventQueueMonitor + * @see EventQueueMonitor#addGUIInitializedListener + * @see EventQueueMonitor#removeGUIInitializedListener + * + */ +class GUIInitializedMulticaster + extends AWTEventMulticaster implements GUIInitializedListener +{ + protected GUIInitializedMulticaster(EventListener a, EventListener b) { + super(a, b); + } + + public void guiInitialized() { + ((GUIInitializedListener)a).guiInitialized(); + ((GUIInitializedListener)b).guiInitialized(); + } + + public static GUIInitializedListener add(GUIInitializedListener a, GUIInitializedListener b) { + return (GUIInitializedListener)addInternal(a, b); + } + + public static GUIInitializedListener remove(GUIInitializedListener l, GUIInitializedListener oldl) { + return (GUIInitializedListener)removeInternal(l, oldl); + } + + protected static EventListener addInternal(EventListener a, EventListener b) { + if (a == null) return b; + if (b == null) return a; + return new GUIInitializedMulticaster(a, b); + } + + protected static EventListener removeInternal(EventListener l, EventListener oldl) { + if (l == oldl || l == null) { + return null; + } else if (l instanceof GUIInitializedMulticaster) { + return ((GUIInitializedMulticaster)l).remove(oldl); + } else { + return l; // it's not here + } + } + +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/SwingEventMonitor.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,2530 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util; + +import java.util.*; +import java.beans.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.table.*; +import javax.swing.tree.*; +import javax.swing.text.*; +import javax.swing.undo.*; +import javax.accessibility.*; + + +/** + *

{@code SwingEventMonitor} extends {@link AWTEventMonitor} by adding a suite of + * listeners conditionally installed on every Swing component instance + * in the Java Virtual Machine. The events captured by these listeners + * are made available through a unified set of listeners supported by + * {@code SwingEventMonitor}. With this, all the individual events on each of the + * AWT and Swing component instances are funneled into one set of listeners + * broken down by category (see {@link EventID} for the categories). + *

This class depends upon {@link EventQueueMonitor}, which provides the base + * level support for capturing the top-level containers as they are created. + *

Because this class extends {@code AWTEventMonitor}, it is not + * necessary to use this class and {@code AWTEventMonitor} at the same time. + * If you want to monitor both AWT and Swing components, you should + * use just this class. + * + * @see AWTEventMonitor + * + */ +@jdk.Exported +public class SwingEventMonitor extends AWTEventMonitor { + + /** + * The master list of all listeners registered by other classes. + * This can only be publicly modified by calling the add or + * remove listener methods in this class. + */ + static protected final EventListenerList listenerList = new EventListenerList(); + + /** + * The actual listener that is installed on the component instances. + * This listener calls the other registered listeners when an event + * occurs. By doing things this way, the actual number of listeners + * installed on a component instance is drastically reduced. + */ + static protected final SwingEventListener swingListener = new SwingEventListener(); + + /** + * Adds the specified listener to receive all {@link EventID#ANCESTOR ANCESTOR} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeAncestorListener + */ + static public void addAncestorListener(AncestorListener l) { + if (listenerList.getListenerCount(AncestorListener.class) == 0) { + swingListener.installListeners(EventID.ANCESTOR); + } + listenerList.add(AncestorListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#ANCESTOR ANCESTOR} events when they occur. + * + * @param l the listener to remove + * @see #addAncestorListener + */ + static public void removeAncestorListener(AncestorListener l) { + listenerList.remove(AncestorListener.class, l); + if (listenerList.getListenerCount(AncestorListener.class) == 0) { + swingListener.removeListeners(EventID.ANCESTOR); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#CARET CARET} events + * on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeCaretListener + */ + static public void addCaretListener(CaretListener l) { + if (listenerList.getListenerCount(CaretListener.class) == 0) { + swingListener.installListeners(EventID.CARET); + } + listenerList.add(CaretListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#CARET CARET} events when they occur. + * + * @param l the listener to remove + * @see #addCaretListener + */ + static public void removeCaretListener(CaretListener l) { + listenerList.remove(CaretListener.class, l); + if (listenerList.getListenerCount(CaretListener.class) == 0) { + swingListener.removeListeners(EventID.CARET); + } + } + + /** + * Adds the specified listener to receive all + * {@link EventID#CELLEDITOR CELLEDITOR} events on each + * component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeCellEditorListener + */ + static public void addCellEditorListener(CellEditorListener l) { + if (listenerList.getListenerCount(CellEditorListener.class) == 0) { + swingListener.installListeners(EventID.CELLEDITOR); + } + listenerList.add(CellEditorListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#CELLEDITOR CELLEDITOR} events when they occur. + * + * @param l the listener to remove + * @see #addCellEditorListener + */ + static public void removeCellEditorListener(CellEditorListener l) { + listenerList.remove(CellEditorListener.class, l); + if (listenerList.getListenerCount(CellEditorListener.class) == 0) { + swingListener.removeListeners(EventID.CELLEDITOR); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#CHANGE CHANGE} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeChangeListener + */ + static public void addChangeListener(ChangeListener l) { + if (listenerList.getListenerCount(ChangeListener.class) == 0) { + swingListener.installListeners(EventID.CHANGE); + } + listenerList.add(ChangeListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#CHANGE CHANGE} events when they occur. + * + * @param l the listener to remove + * @see #addChangeListener + */ + static public void removeChangeListener(ChangeListener l) { + listenerList.remove(ChangeListener.class, l); + if (listenerList.getListenerCount(ChangeListener.class) == 0) { + swingListener.removeListeners(EventID.CHANGE); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#COLUMNMODEL COLUMNMODEL} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeColumnModelListener + */ + static public void addColumnModelListener(TableColumnModelListener l) { + if (listenerList.getListenerCount(TableColumnModelListener.class) == 0) { + swingListener.installListeners(EventID.COLUMNMODEL); + } + listenerList.add(TableColumnModelListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#COLUMNMODEL COLUMNMODEL} events when they occur. + * + * @param l the listener to remove + * @see #addColumnModelListener + */ + static public void removeColumnModelListener(TableColumnModelListener l) { + listenerList.remove(TableColumnModelListener.class, l); + if (listenerList.getListenerCount(TableColumnModelListener.class) == 0) { + swingListener.removeListeners(EventID.COLUMNMODEL); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#DOCUMENT DOCUMENT} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeDocumentListener + */ + static public void addDocumentListener(DocumentListener l) { + if (listenerList.getListenerCount(DocumentListener.class) == 0) { + swingListener.installListeners(EventID.DOCUMENT); + } + listenerList.add(DocumentListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#DOCUMENT DOCUMENT} events when they occur. + * + * @param l the listener to remove + * @see #addDocumentListener + */ + static public void removeDocumentListener(DocumentListener l) { + listenerList.remove(DocumentListener.class, l); + if (listenerList.getListenerCount(DocumentListener.class) == 0) { + swingListener.removeListeners(EventID.DOCUMENT); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#LISTDATA LISTDATA} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeListDataListener + */ + static public void addListDataListener(ListDataListener l) { + if (listenerList.getListenerCount(ListDataListener.class) == 0) { + swingListener.installListeners(EventID.LISTDATA); + } + listenerList.add(ListDataListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#LISTDATA LISTDATA} events when they occur. + * + * @param l the listener to remove + * @see #addListDataListener + */ + static public void removeListDataListener(ListDataListener l) { + listenerList.remove(ListDataListener.class, l); + if (listenerList.getListenerCount(ListDataListener.class) == 0) { + swingListener.removeListeners(EventID.LISTDATA); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#LISTSELECTION LISTSELECTION} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeListSelectionListener + */ + static public void addListSelectionListener(ListSelectionListener l) { + if (listenerList.getListenerCount(ListSelectionListener.class) == 0) { + swingListener.installListeners(EventID.LISTSELECTION); + } + listenerList.add(ListSelectionListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#LISTSELECTION LISTSELECTION} events when they occur. + * + * @param l the listener to remove + * @see #addListSelectionListener + */ + static public void removeListSelectionListener(ListSelectionListener l) { + listenerList.remove(ListSelectionListener.class, l); + if (listenerList.getListenerCount(ListSelectionListener.class) == 0) { + swingListener.removeListeners(EventID.LISTSELECTION); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#MENU MENU} events + * on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeMenuListener + */ + static public void addMenuListener(MenuListener l) { + if (listenerList.getListenerCount(MenuListener.class) == 0) { + swingListener.installListeners(EventID.MENU); + } + listenerList.add(MenuListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#MENU MENU} events when they occur. + * + * @param l the listener to remove + * @see #addMenuListener + */ + static public void removeMenuListener(MenuListener l) { + listenerList.remove(MenuListener.class, l); + if (listenerList.getListenerCount(MenuListener.class) == 0) { + swingListener.removeListeners(EventID.MENU); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#POPUPMENU POPUPMENU} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removePopupMenuListener + */ + static public void addPopupMenuListener(PopupMenuListener l) { + if (listenerList.getListenerCount(PopupMenuListener.class) == 0) { + swingListener.installListeners(EventID.POPUPMENU); + } + listenerList.add(PopupMenuListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#POPUPMENU POPUPMENU} events when they occur. + * + * @param l the listener to remove + * @see #addPopupMenuListener + */ + static public void removePopupMenuListener(PopupMenuListener l) { + listenerList.remove(PopupMenuListener.class, l); + if (listenerList.getListenerCount(PopupMenuListener.class) == 0) { + swingListener.removeListeners(EventID.POPUPMENU); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#TABLEMODEL TABLEMODEL} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeTableModelListener + */ + static public void addTableModelListener(TableModelListener l) { + if (listenerList.getListenerCount(TableModelListener.class) == 0) { + swingListener.installListeners(EventID.TABLEMODEL); + } + listenerList.add(TableModelListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#TABLEMODEL TABLEMODEL} events when they occur. + * + * @param l the listener to remove + * @see #addTableModelListener + */ + static public void removeTableModelListener(TableModelListener l) { + listenerList.remove(TableModelListener.class, l); + if (listenerList.getListenerCount(TableModelListener.class) == 0) { + swingListener.removeListeners(EventID.TABLEMODEL); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#TREEEXPANSION TREEEXPANSION} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeTreeExpansionListener + */ + static public void addTreeExpansionListener(TreeExpansionListener l) { + if (listenerList.getListenerCount(TreeExpansionListener.class) == 0) { + swingListener.installListeners(EventID.TREEEXPANSION); + } + listenerList.add(TreeExpansionListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#TREEEXPANSION TREEEXPANSION} events when they occur. + * + * @param l the listener to remove + * @see #addTreeExpansionListener + */ + static public void removeTreeExpansionListener(TreeExpansionListener l) { + listenerList.remove(TreeExpansionListener.class, l); + if (listenerList.getListenerCount(TreeExpansionListener.class) == 0) { + swingListener.removeListeners(EventID.TREEEXPANSION); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#TREEMODEL TREEMODEL} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeTreeModelListener + */ + static public void addTreeModelListener(TreeModelListener l) { + if (listenerList.getListenerCount(TreeModelListener.class) == 0) { + swingListener.installListeners(EventID.TREEMODEL); + } + listenerList.add(TreeModelListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#TREEMODEL TREEMODEL} events when they occur. + * + * @param l the listener to remove + * @see #addTreeModelListener + */ + static public void removeTreeModelListener(TreeModelListener l) { + listenerList.remove(TreeModelListener.class, l); + if (listenerList.getListenerCount(TreeModelListener.class) == 0) { + swingListener.removeListeners(EventID.TREEMODEL); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#TREESELECTION TREESELECTION} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeTreeSelectionListener + */ + static public void addTreeSelectionListener(TreeSelectionListener l) { + if (listenerList.getListenerCount(TreeSelectionListener.class) == 0) { + swingListener.installListeners(EventID.TREESELECTION); + } + listenerList.add(TreeSelectionListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#TREESELECTION TREESELECTION} events when they occur. + * @see #addTreeSelectionListener + * @param l the listener to remove + */ + static public void removeTreeSelectionListener(TreeSelectionListener l) { + listenerList.remove(TreeSelectionListener.class, l); + if (listenerList.getListenerCount(TreeSelectionListener.class) == 0) { + swingListener.removeListeners(EventID.TREESELECTION); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#UNDOABLEEDIT UNDOABLEEDIT} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeUndoableEditListener + */ + static public void addUndoableEditListener(UndoableEditListener l) { + if (listenerList.getListenerCount(UndoableEditListener.class) == 0) { + swingListener.installListeners(EventID.UNDOABLEEDIT); + } + listenerList.add(UndoableEditListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#UNDOABLEEDIT UNDOABLEEDIT} events when they occur. + * + * @param l the listener to remove + * @see #addUndoableEditListener + */ + static public void removeUndoableEditListener(UndoableEditListener l) { + listenerList.remove(UndoableEditListener.class, l); + if (listenerList.getListenerCount(UndoableEditListener.class) == 0) { + swingListener.removeListeners(EventID.UNDOABLEEDIT); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#INTERNALFRAME INTERNALFRAME} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeInternalFrameListener + */ + static public void addInternalFrameListener(InternalFrameListener l) { + if (listenerList.getListenerCount(InternalFrameListener.class) == 0) { + swingListener.installListeners(EventID.INTERNALFRAME); + } + listenerList.add(InternalFrameListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#INTERNALFRAME INTERNALFRAME} events when they occur. + * + * @param l the listener to remove + * @see #addInternalFrameListener + */ + static public void removeInternalFrameListener(InternalFrameListener l) { + listenerList.remove(InternalFrameListener.class, l); + if (listenerList.getListenerCount(InternalFrameListener.class) == 0) { + swingListener.removeListeners(EventID.INTERNALFRAME); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#PROPERTYCHANGE PROPERTYCHANGE} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removePropertyChangeListener + */ + static public void addPropertyChangeListener(PropertyChangeListener l) { + if (listenerList.getListenerCount(PropertyChangeListener.class) == 0) { + swingListener.installListeners(EventID.PROPERTYCHANGE); + } + listenerList.add(PropertyChangeListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#PROPERTYCHANGE PROPERTYCHANGE} events when they occur. + * @see #addPropertyChangeListener + * @param l the listener to remove + */ + static public void removePropertyChangeListener(PropertyChangeListener l) { + listenerList.remove(PropertyChangeListener.class, l); + if (listenerList.getListenerCount(PropertyChangeListener.class) == 0) { + swingListener.removeListeners(EventID.PROPERTYCHANGE); + } + } + + /** + * Adds the specified listener to receive all {@link EventID#VETOABLECHANGE VETOABLECHANGE} + * events on each component instance in the Java Virtual Machine as they occur. + *

Note: This listener is automatically added to all component + * instances created after this method is called. In addition, it + * is only added to component instances that support this listener type. + * + * @param l the listener to add + * @see #removeVetoableChangeListener + */ + static public void addVetoableChangeListener(VetoableChangeListener l) { + if (listenerList.getListenerCount(VetoableChangeListener.class) == 0) { + swingListener.installListeners(EventID.VETOABLECHANGE); + } + listenerList.add(VetoableChangeListener.class, l); + } + + /** + * Removes the specified listener so it no longer receives + * {@link EventID#VETOABLECHANGE VETOABLECHANGE} events when they occur. + * + * @param l the listener to remove + * @see #addVetoableChangeListener + */ + static public void removeVetoableChangeListener(VetoableChangeListener l) { + listenerList.remove(VetoableChangeListener.class, l); + if (listenerList.getListenerCount(VetoableChangeListener.class) == 0) { + swingListener.removeListeners(EventID.VETOABLECHANGE); + } + } + + + /** + * SwingEventListener is the class that does all the work for + * SwingEventMonitor. It is not intended for use by any other class + * except SwingEventMonitor. + * + */ + static class SwingEventListener extends AWTEventsListener + implements AncestorListener, CaretListener, CellEditorListener, + ChangeListener, DocumentListener, ListDataListener, + ListSelectionListener, MenuListener, PopupMenuListener, + TableColumnModelListener, TableModelListener, TreeExpansionListener, + TreeModelListener, TreeSelectionListener, UndoableEditListener, + InternalFrameListener, + PropertyChangeListener, VetoableChangeListener { + + /** + * internal variables for Caret introspection + */ + private java.lang.Class[] caretListeners; + private java.lang.reflect.Method removeCaretMethod; + private java.lang.reflect.Method addCaretMethod; + private java.lang.Object[] caretArgs; + + /** + * internal variables for CellEditor introspection + */ + private java.lang.Class[] cellEditorListeners; + private java.lang.reflect.Method removeCellEditorMethod; + private java.lang.reflect.Method addCellEditorMethod; + private java.lang.Object[] cellEditorArgs; + private java.lang.reflect.Method getCellEditorMethod; + + /** + * internal variables for Change introspection + */ + private java.lang.Class[] changeListeners; + private java.lang.reflect.Method removeChangeMethod; + private java.lang.reflect.Method addChangeMethod; + private java.lang.Object[] changeArgs; + + /** + * internal variable for ColumnModel introspection + */ + private java.lang.reflect.Method getColumnModelMethod; + + /** + * internal variables for Document introspection + */ + private java.lang.Class[] documentListeners; + private java.lang.reflect.Method removeDocumentMethod; + private java.lang.reflect.Method addDocumentMethod; + private java.lang.Object[] documentArgs; + private java.lang.reflect.Method getDocumentMethod; + + /** + * internal variable for ListData, Table, and Tree introspection + */ + private java.lang.reflect.Method getModelMethod; + + /** + * internal variables for ListSelection introspection + */ + private java.lang.Class[] listSelectionListeners; + private java.lang.reflect.Method removeListSelectionMethod; + private java.lang.reflect.Method addListSelectionMethod; + private java.lang.Object[] listSelectionArgs; + private java.lang.reflect.Method getSelectionModelMethod; + + /** + * internal variables for Menu introspection + */ + private java.lang.Class[] menuListeners; + private java.lang.reflect.Method removeMenuMethod; + private java.lang.reflect.Method addMenuMethod; + private java.lang.Object[] menuArgs; + + /** + * internal variables for PopupMenu introspection + */ + private java.lang.Class[] popupMenuListeners; + private java.lang.reflect.Method removePopupMenuMethod; + private java.lang.reflect.Method addPopupMenuMethod; + private java.lang.Object[] popupMenuArgs; + private java.lang.reflect.Method getPopupMenuMethod; + + /** + * internal variables for TreeExpansion introspection + */ + private java.lang.Class[] treeExpansionListeners; + private java.lang.reflect.Method removeTreeExpansionMethod; + private java.lang.reflect.Method addTreeExpansionMethod; + private java.lang.Object[] treeExpansionArgs; + + /** + * internal variables for TreeSelection introspection + */ + private java.lang.Class[] treeSelectionListeners; + private java.lang.reflect.Method removeTreeSelectionMethod; + private java.lang.reflect.Method addTreeSelectionMethod; + private java.lang.Object[] treeSelectionArgs; + + /** + * internal variables for UndoableEdit introspection + */ + private java.lang.Class[] undoableEditListeners; + private java.lang.reflect.Method removeUndoableEditMethod; + private java.lang.reflect.Method addUndoableEditMethod; + private java.lang.Object[] undoableEditArgs; + + /** + * internal variables for InternalFrame introspection + */ + private java.lang.Class[] internalFrameListeners; + private java.lang.reflect.Method removeInternalFrameMethod; + private java.lang.reflect.Method addInternalFrameMethod; + private java.lang.Object[] internalFrameArgs; + + /** + * internal variables for PropertyChange introspection + */ + private java.lang.Class[] propertyChangeListeners; + private java.lang.reflect.Method removePropertyChangeMethod; + private java.lang.reflect.Method addPropertyChangeMethod; + private java.lang.Object[] propertyChangeArgs; + + /** + * internal variables for a variety of change introspections + */ + private java.lang.Class[] nullClass; + private java.lang.Object[] nullArgs; + + /** + * Create a new instance of this class and install it on each component + * instance in the virtual machine that supports any of the currently + * registered listeners in SwingEventMonitor. Also registers itself + * as a TopLevelWindowListener with EventQueueMonitor so it can + * automatically add new listeners to new components. + * @see EventQueueMonitor + * @see SwingEventMonitor + */ + public SwingEventListener() { + initializeIntrospection(); + installListeners(); + EventQueueMonitor.addTopLevelWindowListener(this); + } + + /** + * Set up all of the variables needed for introspection + */ + private boolean initializeIntrospection() { + caretListeners = new java.lang.Class[1]; + caretArgs = new java.lang.Object[1]; + caretListeners[0] = javax.swing.event.CaretListener.class; + caretArgs[0] = this; + + cellEditorListeners = new java.lang.Class[1]; + cellEditorArgs = new java.lang.Object[1]; + cellEditorListeners[0] = javax.swing.event.CellEditorListener.class; + cellEditorArgs[0] = this; + + changeListeners = new java.lang.Class[1]; + changeArgs = new java.lang.Object[1]; + changeListeners[0] = javax.swing.event.ChangeListener.class; + changeArgs[0] = this; + + documentListeners = new java.lang.Class[1]; + documentArgs = new java.lang.Object[1]; + documentListeners[0] = javax.swing.event.DocumentListener.class; + documentArgs[0] = this; + + listSelectionListeners = new java.lang.Class[1]; + listSelectionArgs = new java.lang.Object[1]; + listSelectionListeners[0] = javax.swing.event.ListSelectionListener.class; + listSelectionArgs[0] = this; + + menuListeners = new java.lang.Class[1]; + menuArgs = new java.lang.Object[1]; + menuListeners[0] = javax.swing.event.MenuListener.class; + menuArgs[0] = this; + + popupMenuListeners = new java.lang.Class[1]; + popupMenuArgs = new java.lang.Object[1]; + popupMenuListeners[0] = javax.swing.event.PopupMenuListener.class; + popupMenuArgs[0] = this; + + treeExpansionListeners = new java.lang.Class[1]; + treeExpansionArgs = new java.lang.Object[1]; + treeExpansionListeners[0] = javax.swing.event.TreeExpansionListener.class; + treeExpansionArgs[0] = this; + + treeSelectionListeners = new java.lang.Class[1]; + treeSelectionArgs = new java.lang.Object[1]; + treeSelectionListeners[0] = javax.swing.event.TreeSelectionListener.class; + treeSelectionArgs[0] = this; + + undoableEditListeners = new java.lang.Class[1]; + undoableEditArgs = new java.lang.Object[1]; + undoableEditListeners[0] = javax.swing.event.UndoableEditListener.class; + undoableEditArgs[0] = this; + + internalFrameListeners = new java.lang.Class[1]; + internalFrameArgs = new java.lang.Object[1]; + internalFrameListeners[0] = javax.swing.event.InternalFrameListener.class; + internalFrameArgs[0] = this; + + nullClass = new java.lang.Class[0]; + nullArgs = new java.lang.Object[0]; + + propertyChangeListeners = new java.lang.Class[1]; + propertyChangeArgs = new java.lang.Object[1]; + propertyChangeListeners[0] = java.beans.PropertyChangeListener.class; + propertyChangeArgs[0] = this; + + return true; + } + + /** + * Installs all appropriate Swing listeners to just the component. + * Also calls super (AWTEventsListener.installListeners()) to install + * the requested AWT listeners. + * @param c the component to add listeners to + */ + protected void installListeners(Component c) { + + // This SwingEventListener needs to be notified when a new + // Swing component has been added so it can add Swing listeners + // to these components. As a result, we always need a Container + // listener on every Container. + // + installListeners(c,EventID.CONTAINER); + + // conditionally install Swing listeners + // + if (SwingEventMonitor.listenerList.getListenerCount(AncestorListener.class) > 0) { + installListeners(c,EventID.ANCESTOR); + } + if (SwingEventMonitor.listenerList.getListenerCount(CaretListener.class) > 0) { + installListeners(c,EventID.CARET); + } + if (SwingEventMonitor.listenerList.getListenerCount(CellEditorListener.class) > 0) { + installListeners(c,EventID.CELLEDITOR); + } + if (SwingEventMonitor.listenerList.getListenerCount(ChangeListener.class) > 0) { + installListeners(c,EventID.CHANGE); + } + if (SwingEventMonitor.listenerList.getListenerCount(TableColumnModelListener.class) > 0) { + installListeners(c,EventID.COLUMNMODEL); + } + if (SwingEventMonitor.listenerList.getListenerCount(DocumentListener.class) > 0) { + installListeners(c,EventID.DOCUMENT); + } + if (SwingEventMonitor.listenerList.getListenerCount(ListDataListener.class) > 0) { + installListeners(c,EventID.LISTDATA); + } + if (SwingEventMonitor.listenerList.getListenerCount(ListSelectionListener.class) > 0) { + installListeners(c,EventID.LISTSELECTION); + } + if (SwingEventMonitor.listenerList.getListenerCount(MenuListener.class) > 0) { + installListeners(c,EventID.MENU); + } + if (SwingEventMonitor.listenerList.getListenerCount(PopupMenuListener.class) > 0) { + installListeners(c,EventID.POPUPMENU); + } + if (SwingEventMonitor.listenerList.getListenerCount(TableModelListener.class) > 0) { + installListeners(c,EventID.TABLEMODEL); + } + if (SwingEventMonitor.listenerList.getListenerCount(TreeExpansionListener.class) > 0) { + installListeners(c,EventID.TREEEXPANSION); + } + if (SwingEventMonitor.listenerList.getListenerCount(TreeModelListener.class) > 0) { + installListeners(c,EventID.TREEMODEL); + } + if (SwingEventMonitor.listenerList.getListenerCount(TreeSelectionListener.class) > 0) { + installListeners(c,EventID.TREESELECTION); + } + if (SwingEventMonitor.listenerList.getListenerCount(UndoableEditListener.class) > 0) { + installListeners(c,EventID.UNDOABLEEDIT); + } + if (SwingEventMonitor.listenerList.getListenerCount(InternalFrameListener.class) > 0) { + installListeners(c,EventID.INTERNALFRAME); + } + + // Conditionally install Beans listeners + // + if (SwingEventMonitor.listenerList.getListenerCount(PropertyChangeListener.class) > 0) { + installListeners(c,EventID.PROPERTYCHANGE); + } + if (SwingEventMonitor.listenerList.getListenerCount(VetoableChangeListener.class) > 0) { + installListeners(c,EventID.VETOABLECHANGE); + } + + // Now install the AWT listeners if needed. + // + super.installListeners(c); + } + + /** + * Installs all appropriate Swing listeners to the component and all its + * children. As a precaution, it always attempts to remove itself as + * a listener first so we're always guaranteed it will installed itself + * just once. + * @param c the component to add listeners to + * @param eventID the eventID to add listeners for + */ + protected void installListeners(Component c, int eventID) { + + // install the appropriate listener hook into this component + // + switch (eventID) { + + case EventID.CONTAINER: + if (c instanceof Container) { + ((Container) c).removeContainerListener(this); + ((Container) c).addContainerListener(this); + } + break; + + case EventID.ANCESTOR: + if (c instanceof JComponent) { + ((JComponent) c).removeAncestorListener(this); + ((JComponent) c).addAncestorListener(this); + } + break; + + case EventID.CARET: + try { + removeCaretMethod = c.getClass().getMethod( + "removeCaretListener", caretListeners); + addCaretMethod = c.getClass().getMethod( + "addCaretListener", caretListeners); + try { + removeCaretMethod.invoke(c, caretArgs); + addCaretMethod.invoke(c, caretArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.CELLEDITOR: + // Look for components which support the getCellEditor method + // (e.g. JTable, JTree) + // + try { + getCellEditorMethod = c.getClass().getMethod( + "getCellEditorMethod", nullClass); + try { + Object o = getCellEditorMethod.invoke(c, nullArgs); + if (o != null && o instanceof CellEditor) { + ((CellEditor) o).removeCellEditorListener(this); + ((CellEditor) o).addCellEditorListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support CellEditor listeners + // (no current example) + // + try { + removeCellEditorMethod = c.getClass().getMethod( + "removeCellEditorListener", cellEditorListeners); + addCellEditorMethod = c.getClass().getMethod( + "addCellEditorListener", cellEditorListeners); + try { + removeCellEditorMethod.invoke(c, cellEditorArgs); + addCellEditorMethod.invoke(c, cellEditorArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.CHANGE: + // [[[FIXME: Need to add support for Style, StyleContext -pk]]] + + // Look for components which support Change listeners + // (e.g. AbstractButton, Caret, JProgressBar, JSlider, + // JTabbedpane, JTextComponent, JViewport) + // + try { + removeChangeMethod = c.getClass().getMethod( + "removeChangeListener", changeListeners); + addChangeMethod = c.getClass().getMethod( + "addChangeListener", changeListeners); + try { + removeChangeMethod.invoke(c, changeArgs); + addChangeMethod.invoke(c, changeArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support the getModel method + // whose model supports Change listeners + // (e.g. BoundedRangeModel, ButtonModel, SingleSelectionModel) + // + try { + getModelMethod = c.getClass().getMethod( + "getModel", nullClass); + try { + Object o = getModelMethod.invoke(c, nullArgs); + if (o != null) { + removeChangeMethod = o.getClass().getMethod( + "removeChangeListener", changeListeners); + addChangeMethod = o.getClass().getMethod( + "addChangeListener", changeListeners); + removeChangeMethod.invoke(o, changeArgs); + addChangeMethod.invoke(o, changeArgs); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + break; + + case EventID.COLUMNMODEL: + try { + getColumnModelMethod = c.getClass().getMethod( + "getTableColumnModel", nullClass); + try { + Object o = getColumnModelMethod.invoke(c, nullArgs); + if (o != null && o instanceof TableColumnModel) { + ((TableColumnModel) o).removeColumnModelListener(this); + ((TableColumnModel) o).addColumnModelListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.DOCUMENT: + // Look for components which support the getDocument method + // (e.g. JTextComponent) + // + try { + getDocumentMethod = c.getClass().getMethod( + "getDocument", nullClass); + try { + Object o = getDocumentMethod.invoke(c, nullArgs); + if (o != null && o instanceof Document) { + ((Document) o).removeDocumentListener(this); + ((Document) o).addDocumentListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support Document listeners + // (no current example) + // + try { + removeDocumentMethod = c.getClass().getMethod( + "removeDocumentListener", documentListeners); + addDocumentMethod = c.getClass().getMethod( + "addDocumentListener", documentListeners); + try { + removeDocumentMethod.invoke(c, documentArgs); + addDocumentMethod.invoke(c, documentArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + // Add the monitor as a PropertyChangeListener for document + // change events from text components. + // + if (c instanceof JTextComponent) { + try { + removePropertyChangeMethod = c.getClass().getMethod( + "removePropertyChangeListener", + propertyChangeListeners); + addPropertyChangeMethod = c.getClass().getMethod( + "addPropertyChangeListener", + propertyChangeListeners); + try { + removePropertyChangeMethod.invoke(c, + propertyChangeArgs); + addPropertyChangeMethod.invoke(c, + propertyChangeArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + } + break; + + case EventID.LISTDATA: + case EventID.TABLEMODEL: + case EventID.TREEMODEL: + try { + getModelMethod = c.getClass().getMethod( + "getModel", nullClass); + try { + Object o = getModelMethod.invoke(c, nullArgs); + if (o != null) { + if (eventID == EventID.LISTDATA && + o instanceof ListModel) { + ((ListModel) o).removeListDataListener(this); + ((ListModel) o).addListDataListener(this); + } else if (eventID == EventID.TABLEMODEL && + o instanceof TableModel) { + ((TableModel) o).removeTableModelListener(this); + ((TableModel) o).addTableModelListener(this); + } else if ( + o instanceof TreeModel) { + ((TreeModel) o).removeTreeModelListener(this); + ((TreeModel) o).addTreeModelListener(this); + } + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.LISTSELECTION: + // Look for components which support ListSelectionListeners + // (e.g. JList) + // + try { + removeListSelectionMethod = c.getClass().getMethod( + "removeListSelectionListener", listSelectionListeners); + addListSelectionMethod = c.getClass().getMethod( + "addListSelectionListener", listSelectionListeners); + try { + removeListSelectionMethod.invoke(c, listSelectionArgs); + addListSelectionMethod.invoke(c, listSelectionArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for selection models which support ListSelectionListeners + // (e.g. JTable's selection model) + // + try { + getSelectionModelMethod = c.getClass().getMethod( + "getSelectionModel", nullClass); + try { + Object o = getSelectionModelMethod.invoke(c, nullArgs); + if (o != null && o instanceof ListSelectionModel) { + ((ListSelectionModel) o).removeListSelectionListener(this); + ((ListSelectionModel) o).addListSelectionListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.MENU: + try { + removeMenuMethod = c.getClass().getMethod( + "removeMenuListener", menuListeners); + addMenuMethod = c.getClass().getMethod( + "addMenuListener", menuListeners); + try { + removeMenuMethod.invoke(c, menuArgs); + addMenuMethod.invoke(c, menuArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.POPUPMENU: + // Look for components which support PopupMenuListeners + // (e.g. JPopupMenu) + // + try { + removePopupMenuMethod = c.getClass().getMethod( + "removePopupMenuListener", popupMenuListeners); + addPopupMenuMethod = c.getClass().getMethod( + "addPopupMenuListener", popupMenuListeners); + try { + removePopupMenuMethod.invoke(c, popupMenuArgs); + addPopupMenuMethod.invoke(c, popupMenuArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support getPopupMenu + // (e.g. JMenu) + // + try { + getPopupMenuMethod = c.getClass().getMethod( + "getPopupMenu", nullClass); + try { + Object o = getPopupMenuMethod.invoke(c, nullArgs); + if (o != null) { + removePopupMenuMethod = o.getClass().getMethod( + "removePopupMenuListener", popupMenuListeners); + addPopupMenuMethod = o.getClass().getMethod( + "addPopupMenuListener", popupMenuListeners); + removePopupMenuMethod.invoke(o, popupMenuArgs); + addPopupMenuMethod.invoke(o, popupMenuArgs); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.TREEEXPANSION: + try { + removeTreeExpansionMethod = c.getClass().getMethod( + "removeTreeExpansionListener", treeExpansionListeners); + addTreeExpansionMethod = c.getClass().getMethod( + "addTreeExpansionListener", treeExpansionListeners); + try { + removeTreeExpansionMethod.invoke(c, treeExpansionArgs); + addTreeExpansionMethod.invoke(c, treeExpansionArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.TREESELECTION: + try { + removeTreeSelectionMethod = c.getClass().getMethod( + "removeTreeSelectionListener", treeSelectionListeners); + addTreeSelectionMethod = c.getClass().getMethod( + "addTreeSelectionListener", treeSelectionListeners); + try { + removeTreeSelectionMethod.invoke(c, treeSelectionArgs); + addTreeSelectionMethod.invoke(c, treeSelectionArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.UNDOABLEEDIT: + // Look for components which support the getDocument method + // (e.g. JTextComponent) + // + try { + getDocumentMethod = c.getClass().getMethod( + "getDocument", nullClass); + try { + Object o = getDocumentMethod.invoke(c, nullArgs); + if (o != null && o instanceof Document) { + ((Document) o).removeUndoableEditListener(this); + ((Document) o).addUndoableEditListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support UndoableEdit listeners + // (no current example) + // + try { + removeUndoableEditMethod = c.getClass().getMethod( + "removeUndoableEditListener", undoableEditListeners); + addUndoableEditMethod = c.getClass().getMethod( + "addUndoableEditListener", undoableEditListeners); + try { + removeUndoableEditMethod.invoke(c, undoableEditArgs); + addUndoableEditMethod.invoke(c, undoableEditArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.INTERNALFRAME: + // Look for components which support InternalFrame listeners + // (e.g. JInternalFrame) + // + try { + removeInternalFrameMethod = c.getClass().getMethod( + "removeInternalFrameListener", internalFrameListeners); + addInternalFrameMethod = c.getClass().getMethod( + "addInternalFrameListener", internalFrameListeners); + try { + removeInternalFrameMethod.invoke(c, internalFrameArgs); + addInternalFrameMethod.invoke(c, internalFrameArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.PROPERTYCHANGE: + // Look for components which support PropertyChange listeners + // (e.g. JComponent) + // + try { + removePropertyChangeMethod = c.getClass().getMethod( + "removePropertyChangeListener", propertyChangeListeners); + addPropertyChangeMethod = c.getClass().getMethod( + "addPropertyChangeListener", propertyChangeListeners); + try { + removePropertyChangeMethod.invoke(c, propertyChangeArgs); + addPropertyChangeMethod.invoke(c, propertyChangeArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support the getSelectionModel method + // (e.g. JTextComponent) + // + try { + getSelectionModelMethod = c.getClass().getMethod( + "getSelectionModel", nullClass); + try { + Object o = getSelectionModelMethod.invoke(c, nullArgs); + if (o != null && o instanceof TreeSelectionModel) { + ((TreeSelectionModel) o).removePropertyChangeListener(this); + ((TreeSelectionModel) o).addPropertyChangeListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.VETOABLECHANGE: + if (c instanceof JComponent) { + ((JComponent) c).removeVetoableChangeListener(this); + ((JComponent) c).addVetoableChangeListener(this); + } + break; + + // Don't bother recursing the children if this isn't going to + // accomplish anything. + // + default: + return; + } + + if (c instanceof Container) { + int count = ((Container) c).getComponentCount(); + for (int i = 0; i < count; i++) { + installListeners(((Container) c).getComponent(i), eventID); + } + } + } + + /** + * Removes all listeners for the given component and all its children. + * @param c the component + */ + protected void removeListeners(Component c) { + + // conditionaly remove the Swing listeners + // + if (SwingEventMonitor.listenerList.getListenerCount(AncestorListener.class) > 0) { + removeListeners(c,EventID.ANCESTOR); + } + if (SwingEventMonitor.listenerList.getListenerCount(CaretListener.class) > 0) { + removeListeners(c,EventID.CARET); + } + if (SwingEventMonitor.listenerList.getListenerCount(CellEditorListener.class) > 0) { + removeListeners(c,EventID.CELLEDITOR); + } + if (SwingEventMonitor.listenerList.getListenerCount(ChangeListener.class) > 0) { + removeListeners(c,EventID.CHANGE); + } + if (SwingEventMonitor.listenerList.getListenerCount(TableColumnModelListener.class) > 0) { + removeListeners(c,EventID.COLUMNMODEL); + } + if (SwingEventMonitor.listenerList.getListenerCount(DocumentListener.class) > 0) { + removeListeners(c,EventID.DOCUMENT); + } + if (SwingEventMonitor.listenerList.getListenerCount(ListDataListener.class) > 0) { + removeListeners(c,EventID.LISTDATA); + } + if (SwingEventMonitor.listenerList.getListenerCount(ListSelectionListener.class) > 0) { + removeListeners(c,EventID.LISTSELECTION); + } + if (SwingEventMonitor.listenerList.getListenerCount(MenuListener.class) > 0) { + removeListeners(c,EventID.MENU); + } + if (SwingEventMonitor.listenerList.getListenerCount(PopupMenuListener.class) > 0) { + removeListeners(c,EventID.POPUPMENU); + } + if (SwingEventMonitor.listenerList.getListenerCount(TableModelListener.class) > 0) { + removeListeners(c,EventID.TABLEMODEL); + } + if (SwingEventMonitor.listenerList.getListenerCount(TreeExpansionListener.class) > 0) { + removeListeners(c,EventID.TREEEXPANSION); + } + if (SwingEventMonitor.listenerList.getListenerCount(TreeModelListener.class) > 0) { + removeListeners(c,EventID.TREEMODEL); + } + if (SwingEventMonitor.listenerList.getListenerCount(TreeSelectionListener.class) > 0) { + removeListeners(c,EventID.TREESELECTION); + } + if (SwingEventMonitor.listenerList.getListenerCount(UndoableEditListener.class) > 0) { + removeListeners(c,EventID.UNDOABLEEDIT); + } + if (SwingEventMonitor.listenerList.getListenerCount(InternalFrameListener.class) > 0) { + removeListeners(c,EventID.INTERNALFRAME); + } + + // conditionaly remove the beans listeners + // + if (SwingEventMonitor.listenerList.getListenerCount(PropertyChangeListener.class) > 0) { + removeListeners(c,EventID.PROPERTYCHANGE); + } + if (SwingEventMonitor.listenerList.getListenerCount(VetoableChangeListener.class) > 0) { + removeListeners(c,EventID.VETOABLECHANGE); + } + + // Now remove the AWT listeners if needed. + // + super.removeListeners(c); + } + + /** + * Removes all Swing listeners for the event ID from the component and + * all of its children. + * @param c the component to remove listeners from + */ + protected void removeListeners(Component c, int eventID) { + + // remove the appropriate listener hook into this component + // + switch (eventID) { + + case EventID.CONTAINER: + //Never remove these because we're always interested in them + // for our own use. + break; + + case EventID.ANCESTOR: + if (c instanceof JComponent) { + ((JComponent) c).removeAncestorListener(this); + } + break; + + case EventID.CARET: + try { + removeCaretMethod = c.getClass().getMethod( + "removeCaretListener", caretListeners); + try { + removeCaretMethod.invoke(c, caretArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.CELLEDITOR: + // Look for components which support the getCellEditor method + // (e.g. JTable, JTree) + // + try { + getCellEditorMethod = c.getClass().getMethod( + "getCellEditorMethod", nullClass); + try { + Object o = getCellEditorMethod.invoke(c, nullArgs); + if (o != null && o instanceof CellEditor) { + ((CellEditor) o).removeCellEditorListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support CellEditor listeners + // (no current example) + // + try { + removeCellEditorMethod = c.getClass().getMethod( + "removeCellEditorListener", cellEditorListeners); + try { + removeCellEditorMethod.invoke(c, cellEditorArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.CHANGE: + // [[[FIXME: Need to add support for Style, StyleContext -pk ]]] + + // Look for components which support Change listeners + // (e.g. AbstractButton, Caret, JProgressBar, JSlider, + // JTabbedpane, JTextComponent, JViewport) + // + try { + removeChangeMethod = c.getClass().getMethod( + "removeChangeListener", changeListeners); + try { + removeChangeMethod.invoke(c, changeArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support the getModel method + // whose model supports Change listeners + // (e.g. BoundedRangeModel, ButtonModel, SingleSelectionModel) + // + try { + getModelMethod = c.getClass().getMethod( + "getModel", nullClass); + try { + Object o = getModelMethod.invoke(c, nullArgs); + if (o != null) { + removeChangeMethod = o.getClass().getMethod( + "removeChangeListener", changeListeners); + removeChangeMethod.invoke(o, changeArgs); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.COLUMNMODEL: + try { + getColumnModelMethod = c.getClass().getMethod( + "getTableColumnModel", nullClass); + try { + Object o = getColumnModelMethod.invoke(c, nullArgs); + if (o != null && o instanceof TableColumnModel) { + ((TableColumnModel) o).removeColumnModelListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.DOCUMENT: + // Look for components which support the getDocument method + // (e.g. JTextComponent) + // + try { + getDocumentMethod = c.getClass().getMethod( + "getDocument", nullClass); + try { + Object o = getDocumentMethod.invoke(c, nullArgs); + if (o != null && o instanceof Document) { + ((Document) o).removeDocumentListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support Document listeners + // (no current example) + // + try { + removeDocumentMethod = c.getClass().getMethod( + "removeDocumentListener", documentListeners); + try { + removeDocumentMethod.invoke(c, documentArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.LISTDATA: + case EventID.TABLEMODEL: + case EventID.TREEMODEL: + try { + getModelMethod = c.getClass().getMethod( + "getModel", nullClass); + try { + Object o = getModelMethod.invoke(c, nullArgs); + if (o != null) { + if (eventID == EventID.LISTDATA && + o instanceof ListModel) { + ((ListModel) o).removeListDataListener(this); + } else if (eventID == EventID.TABLEMODEL && + o instanceof TableModel) { + ((TableModel) o).removeTableModelListener(this); + } else if ( + o instanceof TreeModel) { + ((TreeModel) o).removeTreeModelListener(this); + } + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.LISTSELECTION: + // Look for components which support ListSelectionListeners + // (e.g. JList) + // + try { + removeListSelectionMethod = c.getClass().getMethod( + "removeListSelectionListener", listSelectionListeners); + try { + removeListSelectionMethod.invoke(c, listSelectionArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for selection models which support + // ListSelectionListeners (e.g. JTable's selection model) + // + try { + getSelectionModelMethod = c.getClass().getMethod( + "getSelectionModel", nullClass); + try { + Object o = getSelectionModelMethod.invoke(c, nullArgs); + if (o != null && o instanceof ListSelectionModel) { + ((ListSelectionModel) o).removeListSelectionListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.MENU: + try { + removeMenuMethod = c.getClass().getMethod( + "removeMenuListener", menuListeners); + try { + removeMenuMethod.invoke(c, menuArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.POPUPMENU: + // Look for components which support PopupMenuListeners + // (e.g. JPopupMenu) + // + try { + removePopupMenuMethod = c.getClass().getMethod( + "removePopupMenuListener", popupMenuListeners); + try { + removePopupMenuMethod.invoke(c, popupMenuArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support getPopupMenu + // (e.g. JMenu) + // + try { + getPopupMenuMethod = c.getClass().getMethod( + "getPopupMenu", nullClass); + try { + Object o = getPopupMenuMethod.invoke(c, nullArgs); + if (o != null) { + removePopupMenuMethod = o.getClass().getMethod( + "removePopupMenuListener", popupMenuListeners); + removePopupMenuMethod.invoke(o, popupMenuArgs); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.TREEEXPANSION: + try { + removeTreeExpansionMethod = c.getClass().getMethod( + "removeTreeExpansionListener", treeExpansionListeners); + try { + removeTreeExpansionMethod.invoke(c, treeExpansionArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.TREESELECTION: + try { + removeTreeSelectionMethod = c.getClass().getMethod( + "removeTreeSelectionListener", treeSelectionListeners); + try { + removeTreeSelectionMethod.invoke(c, treeSelectionArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.UNDOABLEEDIT: + // Look for components which support the getDocument method + // (e.g. JTextComponent) + // + try { + getDocumentMethod = c.getClass().getMethod( + "getDocument", nullClass); + try { + Object o = getDocumentMethod.invoke(c, nullArgs); + if (o != null && o instanceof Document) { + ((Document) o).removeUndoableEditListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support UndoableEdit listeners + // (no current example) + // + try { + removeUndoableEditMethod = c.getClass().getMethod( + "removeUndoableEditListener", undoableEditListeners); + try { + removeUndoableEditMethod.invoke(c, undoableEditArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.INTERNALFRAME: + try { + removeInternalFrameMethod = c.getClass().getMethod( + "removeInternalFrameListener", internalFrameListeners); + try { + removeInternalFrameMethod.invoke(c, internalFrameArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.PROPERTYCHANGE: + // Look for components which support PropertyChange listeners + // (e.g. JComponent) + // + try { + removePropertyChangeMethod = c.getClass().getMethod( + "removePropertyChangeListener", propertyChangeListeners); + try { + removePropertyChangeMethod.invoke(c, propertyChangeArgs); + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + + // Look for components which support the getSelectionModel + // method (e.g. JTextComponent) + // + try { + getSelectionModelMethod = c.getClass().getMethod( + "getSelectionModel", nullClass); + try { + Object o = getSelectionModelMethod.invoke(c, nullArgs); + if (o != null && o instanceof TreeSelectionModel) { + ((TreeSelectionModel) o).removePropertyChangeListener(this); + } + } catch (java.lang.reflect.InvocationTargetException e) { + System.out.println("Exception: " + e.toString()); + } catch (IllegalAccessException e) { + System.out.println("Exception: " + e.toString()); + } + } catch (NoSuchMethodException e) { + // System.out.println("Exception: " + e.toString()); + } catch (SecurityException e) { + System.out.println("Exception: " + e.toString()); + } + break; + + case EventID.VETOABLECHANGE: + if (c instanceof JComponent) { + ((JComponent) c).removeVetoableChangeListener(this); + } + break; + + default: + return; + } + + if (c instanceof Container) { + int count = ((Container) c).getComponentCount(); + for (int i = 0; i < count; i++) { + removeListeners(((Container) c).getComponent(i), eventID); + } + } + } + + /********************************************************************/ + /* */ + /* Listener Interface Methods */ + /* */ + /********************************************************************/ + + /* ContainerListener Methods ************************************/ + + public void componentAdded(ContainerEvent e) { + installListeners(e.getChild()); + } + public void componentRemoved(ContainerEvent e) { + removeListeners(e.getChild()); + } + + /* AncestorListener Methods ******************************************/ + + public void ancestorAdded(AncestorEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==AncestorListener.class) { + ((AncestorListener)listeners[i+1]).ancestorAdded(e); + } + } + } + + public void ancestorRemoved(AncestorEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==AncestorListener.class) { + ((AncestorListener)listeners[i+1]).ancestorRemoved(e); + } + } + } + + public void ancestorMoved(AncestorEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==AncestorListener.class) { + ((AncestorListener)listeners[i+1]).ancestorMoved(e); + } + } + } + + /* CaretListener Methods ******************************************/ + + public void caretUpdate(CaretEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==CaretListener.class) { + ((CaretListener)listeners[i+1]).caretUpdate(e); + } + } + } + + /* CellEditorListener Methods *****************************************/ + + public void editingStopped(ChangeEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==CellEditorListener.class) { + ((CellEditorListener)listeners[i+1]).editingStopped(e); + } + } + } + + public void editingCanceled(ChangeEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==CellEditorListener.class) { + ((CellEditorListener)listeners[i+1]).editingCanceled(e); + } + } + } + + /* ChangeListener Methods *****************************************/ + + public void stateChanged(ChangeEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==ChangeListener.class) { + ((ChangeListener)listeners[i+1]).stateChanged(e); + } + } + } + + /* TableColumnModelListener Methods *******************************/ + + public void columnAdded(TableColumnModelEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TableColumnModelListener.class) { + ((TableColumnModelListener)listeners[i+1]).columnAdded(e); + } + } + } + public void columnMarginChanged(ChangeEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TableColumnModelListener.class) { + ((TableColumnModelListener)listeners[i+1]).columnMarginChanged(e); + } + } + } + public void columnMoved(TableColumnModelEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TableColumnModelListener.class) { + ((TableColumnModelListener)listeners[i+1]).columnMoved(e); + } + } + } + public void columnRemoved(TableColumnModelEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TableColumnModelListener.class) { + ((TableColumnModelListener)listeners[i+1]).columnRemoved(e); + } + } + } + public void columnSelectionChanged(ListSelectionEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TableColumnModelListener.class) { + ((TableColumnModelListener)listeners[i+1]).columnSelectionChanged(e); + } + } + } + + /* DocumentListener Methods **************************************/ + + public void changedUpdate(DocumentEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==DocumentListener.class) { + ((DocumentListener)listeners[i+1]).changedUpdate(e); + } + } + } + public void insertUpdate(DocumentEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==DocumentListener.class) { + ((DocumentListener)listeners[i+1]).insertUpdate(e); + } + } + } + public void removeUpdate(DocumentEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==DocumentListener.class) { + ((DocumentListener)listeners[i+1]).removeUpdate(e); + } + } + } + + /* ListDataListener Methods *****************************************/ + + public void contentsChanged(ListDataEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==ListDataListener.class) { + ((ListDataListener)listeners[i+1]).contentsChanged(e); + } + } + } + public void intervalAdded(ListDataEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==ListDataListener.class) { + ((ListDataListener)listeners[i+1]).intervalAdded(e); + } + } + } + public void intervalRemoved(ListDataEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==ListDataListener.class) { + ((ListDataListener)listeners[i+1]).intervalRemoved(e); + } + } + } + + /* ListSelectionListener Methods ***********************************/ + + public void valueChanged(ListSelectionEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==ListSelectionListener.class) { + ((ListSelectionListener)listeners[i+1]).valueChanged(e); + } + } + } + + /* MenuListener Methods *****************************************/ + + public void menuCanceled(MenuEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==MenuListener.class) { + ((MenuListener)listeners[i+1]).menuCanceled(e); + } + } + } + public void menuDeselected(MenuEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==MenuListener.class) { + ((MenuListener)listeners[i+1]).menuDeselected(e); + } + } + } + public void menuSelected(MenuEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==MenuListener.class) { + ((MenuListener)listeners[i+1]).menuSelected(e); + } + } + } + + /* PopupMenuListener Methods **************************************/ + + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==PopupMenuListener.class) { + ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeVisible(e); + } + } + } + + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==PopupMenuListener.class) { + ((PopupMenuListener)listeners[i+1]).popupMenuWillBecomeInvisible(e); + } + } + } + + public void popupMenuCanceled(PopupMenuEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==PopupMenuListener.class) { + ((PopupMenuListener)listeners[i+1]).popupMenuCanceled(e); + } + } + } + + /* TableModelListener Methods **************************************/ + + public void tableChanged(TableModelEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TableModelListener.class) { + ((TableModelListener)listeners[i+1]).tableChanged(e); + } + } + } + + /* TreeExpansionListener Methods **********************************/ + + public void treeCollapsed(TreeExpansionEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TreeExpansionListener.class) { + ((TreeExpansionListener)listeners[i+1]).treeCollapsed(e); + } + } + } + public void treeExpanded(TreeExpansionEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TreeExpansionListener.class) { + ((TreeExpansionListener)listeners[i+1]).treeExpanded(e); + } + } + } + + /* TreeModelListener Methods **********************************/ + + public void treeNodesChanged(TreeModelEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TreeModelListener.class) { + ((TreeModelListener)listeners[i+1]).treeNodesChanged(e); + } + } + } + public void treeNodesInserted(TreeModelEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TreeModelListener.class) { + ((TreeModelListener)listeners[i+1]).treeNodesInserted(e); + } + } + } + public void treeNodesRemoved(TreeModelEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TreeModelListener.class) { + ((TreeModelListener)listeners[i+1]).treeNodesRemoved(e); + } + } + } + public void treeStructureChanged(TreeModelEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TreeModelListener.class) { + ((TreeModelListener)listeners[i+1]).treeStructureChanged(e); + } + } + } + + /* TreeSelectionListener Methods ***********************************/ + + public void valueChanged(TreeSelectionEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==TreeSelectionListener.class) { + ((TreeSelectionListener)listeners[i+1]).valueChanged(e); + } + } + } + + /* UndoableEditListener Methods **************************************/ + + public void undoableEditHappened(UndoableEditEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==UndoableEditListener.class) { + ((UndoableEditListener)listeners[i+1]).undoableEditHappened(e); + } + } + } + + /* InternalFrame Methods **********************************/ + + public void internalFrameOpened(InternalFrameEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==InternalFrameListener.class) { + ((InternalFrameListener)listeners[i+1]).internalFrameOpened(e); + } + } + } + + public void internalFrameActivated(InternalFrameEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==InternalFrameListener.class) { + ((InternalFrameListener)listeners[i+1]).internalFrameActivated(e); + } + } + } + + public void internalFrameDeactivated(InternalFrameEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==InternalFrameListener.class) { + ((InternalFrameListener)listeners[i+1]).internalFrameDeactivated(e); + } + } + } + + public void internalFrameIconified(InternalFrameEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==InternalFrameListener.class) { + ((InternalFrameListener)listeners[i+1]).internalFrameIconified(e); + } + } + } + + public void internalFrameDeiconified(InternalFrameEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==InternalFrameListener.class) { + ((InternalFrameListener)listeners[i+1]).internalFrameDeiconified(e); + } + } + } + + public void internalFrameClosing(InternalFrameEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==InternalFrameListener.class) { + ((InternalFrameListener)listeners[i+1]).internalFrameClosing(e); + } + } + } + + public void internalFrameClosed(InternalFrameEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==InternalFrameListener.class) { + ((InternalFrameListener)listeners[i+1]).internalFrameClosed(e); + } + } + } + + /* PropertyChangeListener Methods **********************************/ + + public void propertyChange(PropertyChangeEvent e) { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==PropertyChangeListener.class) { + ((PropertyChangeListener)listeners[i+1]).propertyChange(e); + } + } + // Re-add the monitor as a DocumentChangeListener if + // the document changed in the text component. + if (e.getSource() instanceof JTextComponent) { + Document c = ((JTextComponent)e.getSource()).getDocument(); + if (c == null) { + return; + } + try { + removeDocumentMethod = c.getClass().getMethod( + "removeDocumentListener", documentListeners); + addDocumentMethod = c.getClass().getMethod( + "addDocumentListener", documentListeners); + try { + removeDocumentMethod.invoke(c, documentArgs); + addDocumentMethod.invoke(c, documentArgs); + } catch (java.lang.reflect.InvocationTargetException e2) { + System.out.println("Exception: " + e2.toString()); + } catch (IllegalAccessException e2) { + System.out.println("Exception: " + e2.toString()); + } + } catch (NoSuchMethodException e2) { + // System.out.println("Exception: " + e2.toString()); + } catch (SecurityException e2) { + System.out.println("Exception: " + e2.toString()); + } + } + + } + + /* VetoableChangeListener Methods **********************************/ + + public void vetoableChange(PropertyChangeEvent e) + throws PropertyVetoException { + Object[] listeners = SwingEventMonitor.listenerList.getListenerList(); + for (int i = listeners.length-2; i>=0; i-=2) { + if (listeners[i]==VetoableChangeListener.class) { + ((VetoableChangeListener)listeners[i+1]).vetoableChange(e); + } + } + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/TopLevelWindowListener.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/TopLevelWindowListener.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util; + +import java.awt.*; +import java.util.*; +import javax.accessibility.*; + +/** + * The {@code TopLevelWindowListener} interface is used by the {@link EventQueueMonitor} + * class to notify an interested party when a top level window is created + * or destroyed in the Java Virtual Machine. Classes wishing to express + * an interest in top level window events should implement this interface + * and register themselves with the {@code EventQueueMonitor} by calling the + * {@link EventQueueMonitor#addTopLevelWindowListener EventQueueMonitor.addTopLevelWindowListener} + * class method. + * + * @see EventQueueMonitor + * @see EventQueueMonitor#addTopLevelWindowListener + * @see EventQueueMonitor#removeTopLevelWindowListener + * + */ +@jdk.Exported +public interface TopLevelWindowListener extends EventListener { + + /** + * Invoked when a new top level window has been created. + * + * @param w the Window that was created + */ + public void topLevelWindowCreated(Window w); + + /** + * Invoked when a top level window has been destroyed. + * + * @param w the Window that was destroyed + */ + public void topLevelWindowDestroyed(Window w); +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/TopLevelWindowMulticaster.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/TopLevelWindowMulticaster.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2005, 2015, 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 com.sun.java.accessibility.util; + +import java.awt.*; +import java.util.EventListener; +import javax.accessibility.*; + + +/** + * The TopLevelWindowMulticaster class is used to maintain a list of + * TopLevelWindowListener classes. It is intended to be used primarily + * for internal support in the EventQueueMonitor class, and is not intended + * to be used by classes outside the Java Accessibility Utility package. + * + * @see EventQueueMonitor + * @see EventQueueMonitor#addTopLevelWindowListener + * @see EventQueueMonitor#removeTopLevelWindowListener + * + */ +class TopLevelWindowMulticaster + extends AWTEventMulticaster implements TopLevelWindowListener +{ + protected TopLevelWindowMulticaster(EventListener a, EventListener b) { + super(a, b); + } + + public void topLevelWindowCreated(Window w) { + ((TopLevelWindowListener)a).topLevelWindowCreated(w); + ((TopLevelWindowListener)b).topLevelWindowCreated(w); + } + + public void topLevelWindowDestroyed(Window w) { + ((TopLevelWindowListener)a).topLevelWindowDestroyed(w); + ((TopLevelWindowListener)b).topLevelWindowDestroyed(w); + } + + public static TopLevelWindowListener add(TopLevelWindowListener a, TopLevelWindowListener b) { + return (TopLevelWindowListener)addInternal(a, b); + } + + public static TopLevelWindowListener remove(TopLevelWindowListener l, TopLevelWindowListener oldl) { + return (TopLevelWindowListener)removeInternal(l, oldl); + } + + protected static EventListener addInternal(EventListener a, EventListener b) { + if (a == null) return b; + if (b == null) return a; + return new TopLevelWindowMulticaster(a, b); + } + + protected static EventListener removeInternal(EventListener l, EventListener oldl) { + if (l == oldl || l == null) { + return null; + } else if (l instanceof TopLevelWindowMulticaster) { + return ((TopLevelWindowMulticaster)l).remove(oldl); + } else { + return l; // it's not here + } + } + +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,744 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util; + +import java.lang.*; +import java.beans.*; +import java.util.*; +import java.awt.*; +import java.awt.event.*; +import java.awt.image.*; +// Do not import Swing classes. This module is intended to work +// with both Swing and AWT. +// import javax.swing.*; +import javax.accessibility.*; + +/** + *

The {@code Translator} class provides a translation to interface + * {@link javax.accessibility.Accessible Accessible} + * for objects that do not implement interface {@code Accessible}. Assistive + * technologies can use the {@link #getAccessible getAccessible} class method of + * {@code Translator} to obtain an object that implements interface {@code Accessible}. + * If the object passed in already implements interface {@code Accessible}, + * {@code getAccessible} merely returns the object. + * + *

An example of how an assistive technology might use the {@code Translator} + * class is as follows: + * + *

+ *    Accessible accessible = Translator.getAccessible(someObj);
+ *    // obtain information from the 'accessible' object.
+ * 
+ * + *

Note: This implementation is missing many things and is not a recommended way + * to implement accessibility features for a toolkit. Instead of relying upon this + * code, a toolkit's components should implement interface {@code Accessible} directly. + */ +@jdk.Exported +public class Translator extends AccessibleContext + implements Accessible, AccessibleComponent { + + /** The source object needing translating. */ + protected Object source; + + /** + * Find a translator for this class. If one doesn't exist for this + * class explicitly, try its superclass and so on. + * + * @param c a Class + * @return the {@code Translator} Class for the Class passed in + */ + protected static Class getTranslatorClass(Class c) { + Class t = null; + if (c == null) { + return null; + } + try { + t = Class.forName("com.sun.java.accessibility.util." + + c.getName() + + "Translator"); + return t; + } catch (Exception e) { + return getTranslatorClass(c.getSuperclass()); + } + } + + /** + * Obtain an object that implements interface {@code Accessible}. If the object + * passed in already implements interface {@code Accessible}, {@code getAccessible} + * merely returns the object. + * + * @param o an Object; if a null is passed in a null is returned + * @return an {@code Object}, possibly the {@code Object} passed in, that + * implements the {@code Accessible} interface for the {@code Object} + * which was passed in + */ + public static Accessible getAccessible(Object o) { + Accessible a = null; + + if (o == null) { + return null; + } + if (o instanceof Accessible) { + a = (Accessible)o; + } else { + Class translatorClass = getTranslatorClass(o.getClass()); + if (translatorClass != null) { + try { + Translator t = (Translator)translatorClass.newInstance(); + t.setSource(o); + a = t; + } catch (Exception e) { + } + } + } + if (a == null) { + a = new Translator(o); + } + return a; + } + + /** + * Create a new {@code Translator}. You must call the {@link #setSource setSource} + * method to set the object to be translated after calling this constructor. + */ + public Translator() { + } + + /** + * Create a new {@code Translator} with the source object o. + * + * @param o the Component that does not implement interface + * {@link javax.accessibility.Accessible Accessible} + */ + public Translator(Object o) { + source = o; + } + + /** + * Get the source {@code Object} of the {@code Translator}. + * + * @return the source {@code Object} of the {@code Translator} + */ + public Object getSource() { + return source; + } + + /** + * Set the source object of the {@code Translator}. + * + * @param o the Component that does not implement interface Accessible + */ + public void setSource(Object o) { + source = o; + } + + /** + * Returns true if this object is the same as the one passed in. + * + * @param o the {@code Object} to check against + * @return true if this is the same object + */ + public boolean equals(Object o) { + if (o instanceof Translator) { + return java.util.Objects.equals(source, o); + } else { + return false; + } + } + + /** + * Return hashcode. + * + * @return hashcode + */ + public int hashCode() { + return java.util.Objects.hashCode(source); + } + + +// Accessible methods + + /** + * Returns this object. + */ + public AccessibleContext getAccessibleContext() { + return this; + } + +// AccessibleContext methods + + /** + * Get the accessible name of this object. + * + * @return the localized name of the object; can be null if this object + * does not have a name + */ + public String getAccessibleName() { + if (source instanceof MenuItem) { + return ((MenuItem) source).getLabel(); + } else if (source instanceof Component) { + return ((Component) source).getName(); + } else { + return null; + } + } + + /** + * Set the name of this object. + */ + public void setAccessibleName(String s) { + if (source instanceof MenuItem) { + ((MenuItem) source).setLabel(s); + } else if (source instanceof Component) { + ((Component) source).setName(s); + } + } + + /** + * Get the accessible description of this object. + * + * @return the description of the object; can be null if this object does + * not have a description + */ + public String getAccessibleDescription() { + return null; + } + + /** + * Set the accessible description of this object. + * + * @param s the new localized description of the object + */ + public void setAccessibleDescription(String s) { + } + + /** + * Get the role of this object. + * + * @return an instance of AccessibleRole describing the role of the object + */ + public AccessibleRole getAccessibleRole() { + return AccessibleRole.UNKNOWN; + } + + + /** + * Get the state of this object, given an already populated state. + * This method is intended for use by subclasses so they don't have + * to check for everything. + * + * @return an instance of {@code AccessibleStateSet} + * containing the current state of the object + */ + public AccessibleStateSet getAccessibleStateSet() { + AccessibleStateSet states = new AccessibleStateSet(); + if (source instanceof Component) { + Component c = (Component) source; + for (Container p = c.getParent(); p != null; p = p.getParent()) { + if (p instanceof Window) { + if (((Window)p).getFocusOwner() == c) { + states.add(AccessibleState.FOCUSED); + } + } + } + } + if (isEnabled()) { + states.add(AccessibleState.ENABLED); + } + if (isFocusTraversable()) { + states.add(AccessibleState.FOCUSABLE); + } + if (source instanceof MenuItem) { + states.add(AccessibleState.FOCUSABLE); + } + return states; + } + + /** + * Get the accessible parent of this object. + * + * @return the accessible parent of this object; can be null if this + * object does not have an accessible parent + */ + public Accessible getAccessibleParent() { + if (accessibleParent != null) { + return accessibleParent; + } else if (source instanceof Component) { + return getAccessible(((Component) source).getParent()); + } else { + return null; + } + } + + /** + * Get the index of this object in its accessible parent. + * + * @return -1 of this object does not have an accessible parent; otherwise, + * the index of the child in its accessible parent + */ + public int getAccessibleIndexInParent() { + if (source instanceof Component) { + Container parent = ((Component) source).getParent(); + if (parent != null) { + Component ca[] = parent.getComponents(); + for (int i = 0; i < ca.length; i++) { + if (source.equals(ca[i])) { + return i; + } + } + } + } + return -1; + } + + /** + * Returns the number of accessible children in the object. + * + * @return the number of accessible children in the object + */ + public int getAccessibleChildrenCount() { + if (source instanceof Container) { + Component[] children = ((Container) source).getComponents(); + int count = 0; + for (int i = 0; i < children.length; i++) { + Accessible a = getAccessible(children[i]); + if (a != null) { + count++; + } + } + return count; + } else { + return 0; + } + } + + /** + * Return the nth accessible child of the object. + * + * @param i zero-based index of child + * @return the nth accessible child of the object + */ + public Accessible getAccessibleChild(int i) { + if (source instanceof Container) { + Component[] children = ((Container) source).getComponents(); + int count = 0; + + for (int j = 0; j < children.length; j++) { + Accessible a = getAccessible(children[j]); + if (a != null) { + if (count == i) { + AccessibleContext ac = a.getAccessibleContext(); + if (ac != null) { + ac.setAccessibleParent(this); + } + return a; + } else { + count++; + } + } + } + } + return null; + } + + /** + * Gets the {@code Locale} of the component. If the component does not have a + * locale, the locale of its parent is returned. + * + * @return the {@code Locale} of the object + */ + public Locale getLocale() throws IllegalComponentStateException { + if (source instanceof Component) { + return ((Component) source).getLocale(); + } else { + return null; + } + } + + /** + * Add a {@code PropertyChangeListener} to the listener list. The listener + * is registered for all properties. + */ + public void addPropertyChangeListener(PropertyChangeListener l) { + } + + /** + * Remove the {@code PropertyChangeListener} from the listener list. + */ + public void removePropertyChangeListener(PropertyChangeListener l) { + } + +// AccessibleComponent methods + + /** + * Get the background {@code Color} of this object. + * + * @return if supported, the background {@code Color} of the object; + * otherwise, null + * + */ + public Color getBackground() { + if (source instanceof Component) { // MenuComponent doesn't do background + return ((Component) source).getBackground(); + } else { + return null; + } + } + + /** + * Set the background {@code Color} of this object. + * + * @param c the new {@code Color} for the background + */ + public void setBackground(Color c) { + if (source instanceof Component) { // MenuComponent doesn't do background + ((Component) source).setBackground(c); + } + } + + /** + * Get the foreground {@code Color} of this object. + * + * @return if supported, the foreground {@code Color} of the object; otherwise, null + */ + public Color getForeground() { + if (source instanceof Component) { // MenuComponent doesn't do foreground + return ((Component) source).getForeground(); + } else { + return null; + } + } + + /** + * Set the foreground {@code Color} of this object. + * + * @param c the new {@code Color} for the foreground + */ + public void setForeground(Color c) { + if (source instanceof Component) { // MenuComponent doesn't do foreground + ((Component) source).setForeground(c); + } + } + + /** + * Get the {@code Cursor} of this object. + * + * @return if supported, the Cursor of the object; otherwise, null + */ + public Cursor getCursor() { + if (source instanceof Component) { // MenuComponent doesn't do cursor + return ((Component) source).getCursor(); + } else { + return null; + } + } + + /** + * Set the {@code Cursor} of this object. + * @param c the new {@code Cursor} for the object + */ + public void setCursor(Cursor c) { + if (source instanceof Component) { // MenuComponent doesn't do cursor + ((Component) source).setCursor(c); + } + } + + /** + * Get the {@code Font} of this object. + * + * @return if supported, the {@code Font} for the object; otherwise, null + */ + public Font getFont() { + if (source instanceof Component) { + return ((Component) source).getFont(); + } else if (source instanceof MenuComponent) { + return ((MenuComponent) source).getFont(); + } else { + return null; + } + } + + /** + * Set the {@code Font} of this object. + * + * @param f the new {@code Font} for the object + */ + public void setFont(Font f) { + if (source instanceof Component) { + ((Component) source).setFont(f); + } else if (source instanceof MenuComponent) { + ((MenuComponent) source).setFont(f); + } + } + + /** + * Get the {@code FontMetrics} of this object. + * + * @param f the {@code Font} + * @return if supported, the {@code FontMetrics} the object; otherwise, null + * @see #getFont + */ + public FontMetrics getFontMetrics(Font f) { + if (source instanceof Component) { + return ((Component) source).getFontMetrics(f); + } else { + return null; + } + } + + /** + * Determine if the object is enabled. + * + * @return true if object is enabled; otherwise, false + */ + public boolean isEnabled() { + if (source instanceof Component) { + return ((Component) source).isEnabled(); + } else if (source instanceof MenuItem) { + return ((MenuItem) source).isEnabled(); + } else { + return true; + } + } + + /** + * Set the enabled state of the object. + * + * @param b if true, enables this object; otherwise, disables it + */ + public void setEnabled(boolean b) { + if (source instanceof Component) { + ((Component) source).setEnabled(b); + } else if (source instanceof MenuItem) { + ((MenuItem) source).setEnabled(b); + } + } + + /** + * Determine if the object is visible. + * + * @return true if object is visible; otherwise, false + */ + public boolean isVisible() { + if (source instanceof Component) { + return ((Component) source).isVisible(); + } else { + return false; + } + } + + /** + * Set the visible state of the object. + * + * @param b if true, shows this object; otherwise, hides it + */ + public void setVisible(boolean b) { + if (source instanceof Component) { + ((Component) source).setVisible(b); + } + } + + /** + * Determine if the object is showing. This is determined by checking + * the visibility of the object and ancestors of the object. + * + * @return true if object is showing; otherwise, false + */ + public boolean isShowing() { + if (source instanceof Component) { + return ((Component) source).isShowing(); + } else { + return false; + } + } + + /** + * Checks whether the specified {@code Point} is within this + * object's bounds, where the {@code Point} is relative to the coordinate + * system of the object. + * + * @param p the {@code Point} relative to the coordinate system of the object + * @return true if object contains {@code Point}; otherwise false + */ + public boolean contains(Point p) { + if (source instanceof Component) { + return ((Component) source).contains(p); + } else { + return false; + } + } + + /** + * Returns the location of the object on the screen. + * + * @return location of object on screen; can be null if this object + * is not on the screen + */ + public Point getLocationOnScreen() { + if (source instanceof Component) { + return ((Component) source).getLocationOnScreen(); + } else { + return null; + } + } + + /** + * Returns the location of the object relative to parent. + * + * @return location of object relative to parent; can be null if + * this object or its parent are not on the screen + */ + public Point getLocation() { + if (source instanceof Component) { + return ((Component) source).getLocation(); + } else { + return null; + } + } + + /** + * Sets the location of the object relative to parent. + */ + public void setLocation(Point p) { + if (source instanceof Component) { + ((Component) source).setLocation(p); + } + } + + /** + * Returns the current bounds of this object. + * + * @return current bounds of object; can be null if this object + * is not on the screen + */ + public Rectangle getBounds() { + if (source instanceof Component) { + return ((Component) source).getBounds(); + } else { + return null; + } + } + + /** + * Sets the current bounds of this object. + */ + public void setBounds(Rectangle r) { + if (source instanceof Component) { + ((Component) source).setBounds(r); + } + } + + /** + * Returns the current size of this object. + * + * @return current size of object; can be null if this object is + * not on the screen + */ + public Dimension getSize() { + if (source instanceof Component) { + return ((Component) source).getSize(); + } else { + return null; + } + } + + /** + * Sets the current size of this object. + */ + public void setSize(Dimension d) { + if (source instanceof Component) { + ((Component) source).setSize(d); + } + } + + /** + * Returns the accessible child contained at the local coordinate + * Point, if one exists. + * + * @return the Accessible at the specified location, if it exists + */ + public Accessible getAccessibleAt(Point p) { + if (source instanceof Component) { + Component c = ((Component) source).getComponentAt(p); + if (c != null) { + return (getAccessible(c)); + } + } + return null; + } + + /** + * Returns whether this object can accept focus or not. + * + * @return true if object can accept focus; otherwise false + */ + @SuppressWarnings("deprecation") + public boolean isFocusTraversable() { + if (source instanceof Component) { + return ((Component) source).isFocusTraversable(); + } else { + return false; + } + } + + /** + * Requests focus for this object. + */ + public void requestFocus() { + if (source instanceof Component) { + ((Component) source).requestFocus(); + } + } + + /** + * Adds the specified {@code FocusListener} to receive focus events from + * this component. + * + * @param l the focus listener + */ + public synchronized void addFocusListener(FocusListener l) { + if (source instanceof Component) { + ((Component) source).addFocusListener(l); + } + } + + /** + * Removes the specified focus listener so it no longer receives focus + * events from this component. + * + * @param l the focus listener; this method performs no function, nor does it + * throw an exception if the listener specified was not previously added + * to this component; if listener is null, no exception is thrown and no + * action is performed. + */ + public synchronized void removeFocusListener(FocusListener l) { + if (source instanceof Component) { + ((Component) source).removeFocusListener(l); + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/ButtonTranslator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/ButtonTranslator.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util.java.awt; + +import java.lang.*; +import java.util.*; +import java.awt.*; +import java.awt.image.*; +import javax.accessibility.*; +import com.sun.java.accessibility.util.*; + +/** + *

The Translator class provides a translation to interface Accessible + * for objects that do not implement interface Accessible. Assistive + * technologies can use the 'getAccessible' class method of Translator to + * obtain an object that implements interface Accessible. If the object + * passed in already implements interface Accessible, getAccessible merely + * returns the object. + * + *

An example of how an assistive technology might use the Translator + * class is as follows: + * + *

+ *    Accessible accessible = Translator.getAccessible(someObj);
+ *    // obtain information from the 'accessible' object.
+ * 
+ * + *

This class extends the Translator class to provide specific support + * for the Button class. Translator.getAccessible() will automatically + * load this class when an assistive technology asks for an accessible + * translator for Button. + * + */ +public class ButtonTranslator extends Translator { + + /** + * Get the name of this object. + * @return the name of the object -- can be null if this object does + * not have a name + */ + public String getAccessibleName() { + return ((Button) source).getLabel(); + } + + /** + * Set the name of this object. + */ + public void setAccessibleName(String s) { + ((Button) source).setLabel(s); + } + + public AccessibleRole getAccessibleRole() { + return AccessibleRole.PUSH_BUTTON; + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/CheckboxTranslator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/CheckboxTranslator.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util.java.awt; + +import java.lang.*; +import java.util.*; +import java.awt.*; +import java.awt.image.*; +import javax.accessibility.*; +import com.sun.java.accessibility.util.*; + +/** + *

The Translator class provides a translation to interface Accessible + * for objects that do not implement interface Accessible. Assistive + * technologies can use the 'getAccessible' class method of Translator to + * obtain an object that implements interface Accessible. If the object + * passed in already implements interface Accessible, getAccessible merely + * returns the object. + * + *

An example of how an assistive technology might use the Translator + * class is as follows: + * + *

+ *    Accessible accessible = Translator.getAccessible(someObj);
+ *    // obtain information from the 'accessible' object.
+ * 
+ * + *

This class extends the Translator class to provide specific support + * for the Checkbox class. Translator.getAccessible() will automatically + * load this class when an assistive technology asks for an accessible + * translator for Checkbox. + * + */ +public class CheckboxTranslator extends Translator { + + /** + * Get the state of this object. + * @return an instance of AccessibleState containing the current state of the object + * @see AccessibleState + */ + public AccessibleStateSet getAccessibleStateSet() { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (((Checkbox) source).getState()) { + states.add(AccessibleState.CHECKED); + } + return states; + } + + /** + * Get the name of this object. + * @return the name of the object -- can be null if this object does + * not have a name + */ + public String getAccessibleName() { + return ((Checkbox) source).getLabel(); + } + + /** + * Set the name of this object. + */ + public void setAccessibleName(String s) { + ((Checkbox) source).setLabel(s); + } + + public AccessibleRole getAccessibleRole() { + return AccessibleRole.CHECK_BOX; + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/LabelTranslator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/LabelTranslator.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util.java.awt; + +import java.lang.*; +import java.util.*; +import java.awt.*; +import java.awt.image.*; +import javax.accessibility.*; +import com.sun.java.accessibility.util.*; + +/** + *

The Translator class provides a translation to interface Accessible + * for objects that do not implement interface Accessible. Assistive + * technologies can use the 'getAccessible' class method of Translator to + * obtain an object that implements interface Accessible. If the object + * passed in already implements interface Accessible, getAccessible merely + * returns the object. + * + *

An example of how an assistive technology might use the Translator + * class is as follows: + * + *

+ *    Accessible accessible = Translator.getAccessible(someObj);
+ *    // obtain information from the 'accessible' object.
+ * 
+ * + *

This class extends the Translator class to provide specific support + * for the Label class. Translator.getAccessible() will automatically + * load this class when an assistive technology asks for an accessible + * translator for Label. + * + */ +public class LabelTranslator extends Translator { + + public String getAccessibleName() { + return ((Label) source).getText(); + } + + /** + * Set the name of this object. + */ + public void setAccessibleName(String s) { + ((Label) source).setText(s); + } + + public AccessibleRole getAccessibleRole() { + return AccessibleRole.LABEL; + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/ListTranslator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/ListTranslator.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util.java.awt; + +import java.lang.*; +import java.util.*; +import java.awt.*; +import java.awt.image.*; +import javax.accessibility.*; +import com.sun.java.accessibility.util.*; + +/** + *

The Translator class provides a translation to interface Accessible + * for objects that do not implement interface Accessible. Assistive + * technologies can use the 'getAccessible' class method of Translator to + * obtain an object that implements interface Accessible. If the object + * passed in already implements interface Accessible, getAccessible merely + * returns the object. + * + *

An example of how an assistive technology might use the Translator + * class is as follows: + * + *

+ *    Accessible accessible = Translator.getAccessible(someObj);
+ *    // obtain information from the 'accessible' object.
+ * 
+ * + *

This class extends the Translator class to provide specific support + * for the List class. Translator.getAccessible() will automatically + * load this class when an assistive technology asks for an accessible + * translator for List. + * + */ +public class ListTranslator extends Translator { + + /** + * Get the state of this object. + * @return an instance of AccessibleState containing the current state of the object + * @see AccessibleState + */ + public AccessibleStateSet getAccessibleStateSet() { + AccessibleStateSet states = super.getAccessibleStateSet(); + if (((java.awt.List) source).isMultipleMode()) { + states.add(AccessibleState.MULTISELECTABLE); + } + if (((java.awt.List) source).getSelectedItems().length > 0) { + states.add(AccessibleState.SELECTED); + } + return states; + } + + public AccessibleRole getAccessibleRole() { + return AccessibleRole.LIST; + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/TextComponentTranslator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/java/awt/TextComponentTranslator.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2002, 2015, 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 com.sun.java.accessibility.util.java.awt; + +import java.lang.*; +import java.util.*; +import java.awt.*; +import java.awt.image.*; +import javax.accessibility.*; +import com.sun.java.accessibility.util.*; + +/** + *

The Translator class provides a translation to interface Accessible + * for objects that do not implement interface Accessible. Assistive + * technologies can use the 'getAccessible' class method of Translator to + * obtain an object that implements interface Accessible. If the object + * passed in already implements interface Accessible, getAccessible merely + * returns the object. + * + *

An example of how an assistive technology might use the Translator + * class is as follows: + * + *

+ *    Accessible accessible = Translator.getAccessible(someObj);
+ *    // obtain information from the 'accessible' object.
+ * 
+ * + *

This class extends the Translator class to provide specific support + * for the TextComponent class. Translator.getAccessible() will automatically + * load this class when an assistive technology asks for an accessible + * translator for TextComponent. + * + */ +public class TextComponentTranslator extends Translator { + + public AccessibleRole getAccessibleRole() { + return AccessibleRole.TEXT; + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/package-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/package-info.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2013, 2015 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. + */ + +/** + * Provides a collection of interfaces and classes that compose the Java Accessibility + * Utilities. The classes are used by Assistive Technologies, such as the screen + * readers which are used by those who are blind, and help provide access to GUI + * toolkits that implement the Java Accessibility API. An overview of the important + * classes follows. + * + *

The class {@code AccessibilityEventMonitor} implements a PropertyChange + * listener on every UI object that implements interface {@code Accessible} in the Java + * Virtual Machine. + * + *

The class {@code AWTEventMonitor} implements a suite of listeners that are + * conditionally installed on every AWT component instance in the Java Virtual Machine. + * + *

The class {@code EventQueueMonitor} provides key core functionality for + * Assistive Technologies (and other system-level technologies that need some of + * the same things that Assistive Technology needs). + * + *

The class {@code GUIInitializedMulticaster} is used to maintain a list of + * {@code GUIInitializedListener} classes which are used by the {@code EventQueueMonitor} + * class to notify an interested party when the GUI subsystem has been initialized. + * Note that this class is intended to be used primarily for internal support in + * the {@code EventQueueMonitor} class, and is not intended to be used by classes + * outside the Java Accessibility Utility package. + * + *

The class {@code SwingEventMonitor} extends {@code AWTEventMonitor} by adding + * a suite of listeners conditionally installed on every Swing component instance + * in the Java Virtual Machine. + * + *

The class {@code TopLevelWindowMulticaster} is used to maintain a list of + * {@code TopLevelWindowListener} classes which are used by the {@code EventQueueMonitor} + * class to notify an interested party when a top level window is created or destroyed + * in the Java Virtual Machine Note that this class is intended to be used primarily + * for internal support in the {@code EventQueueMonitor} class, and is not intended + * to be used by classes outside the Java Accessibility Utility package. + * + *

The class {@code Translator} provides a translation to interface {@code Accessible} + * for objects that do not implement interface {@code Accessible}. + * + * @since JDK1.7 + */ +package com.sun.java.accessibility.util; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/AccessBridge.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/AccessBridge.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,7170 @@ +/* + * Copyright (c) 2005, 2015, 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 com.sun.java.accessibility; + +import java.awt.*; +import java.awt.event.*; +import java.util.*; +import java.lang.*; +import java.lang.reflect.*; + +import java.beans.*; +import javax.swing.*; +import javax.swing.event.*; +import javax.swing.text.*; +import javax.swing.tree.*; +import javax.swing.table.*; +import javax.swing.plaf.TreeUI; + +import javax.accessibility.*; +import com.sun.java.accessibility.util.*; +import sun.awt.AWTAccessor; +import sun.awt.AppContext; +import sun.awt.SunToolkit; + +import java.util.concurrent.Callable; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; + +/* + * Note: This class has to be public. It's loaded from the VM like this: + * Class.forName(atName).newInstance(); + */ +@jdk.Exported(false) +final public class AccessBridge { + + private static AccessBridge theAccessBridge; + private ObjectReferences references; + private EventHandler eventHandler; + + // Maps AccessibleRoles strings to AccessibleRoles. + private ConcurrentHashMap accessibleRoleMap = new ConcurrentHashMap<>(); + + /** + If the object's role is in the following array getVirtualAccessibleName + will use the extended search algorithm. + */ + private ArrayList extendedVirtualNameSearchRoles = new ArrayList<>(); + /** + If the role of the object's parent is in the following array + getVirtualAccessibleName will NOT use the extended search + algorithm even if the object's role is in the + extendedVirtualNameSearchRoles array. + */ + private ArrayList noExtendedVirtualNameSearchParentRoles = new ArrayList<>(); + + private static native boolean isSysWow(); + + + /** + * Load DLLs + */ + static { + // Load the appropriate DLLs + boolean is32on64 = false; + if (System.getProperty("os.arch").equals("x86")) { + // 32 bit JRE + // Load jabsysinfo.dll so can determine Win bitness + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + System.loadLibrary("jabsysinfo"); + return null; + } + }, null, new java.lang.RuntimePermission("loadLibrary.jabsysinfo") + ); + if (isSysWow()) { + // 32 bit JRE on 64 bit OS + is32on64 = true; + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + System.loadLibrary("javaaccessbridge-32"); + return null; + } + }, null, new java.lang.RuntimePermission("loadLibrary.javaaccessbridge-32") + ); + } + } + if (!is32on64) { + // 32 bit JRE on 32 bit OS or 64 bit JRE on 64 bit OS + java.security.AccessController.doPrivileged( + new java.security.PrivilegedAction() { + public Void run() { + System.loadLibrary("javaaccessbridge"); + return null; + } + }, null, new java.lang.RuntimePermission("loadLibrary.javaaccessbridge") + ); + } + } + + /** + * AccessBridge constructor + * + * Note: This constructor has to be public. It's called from the VM like this: + * Class.forName(atName).newInstance(); + */ + public AccessBridge() { + theAccessBridge = this; + references = new ObjectReferences(); + + // initialize shutdown hook + Runtime runTime = Runtime.getRuntime(); + shutdownHook hook = new shutdownHook(); + runTime.addShutdownHook(new Thread(hook)); + + // initialize AccessibleRole map + initAccessibleRoleMap(); + + // determine which version of the JDK is running + String version = getJavaVersionProperty(); + debugString("JDK version = "+version); + + // initialize the methods that map HWNDs and Java top-level + // windows + initHWNDcalls(); + + // is this a JVM we can use? + // install JDK 1.2 and later Swing ToolKit listener + EventQueueMonitor.isGUIInitialized(); + + // start the Java event handler + eventHandler = new EventHandler(this); + + // register for menu selection events + MenuSelectionManager.defaultManager().addChangeListener(eventHandler); + + // register as a NativeWindowHandler + addNativeWindowHandler(new DefaultNativeWindowHandler()); + + // start in a new thread + Thread abthread = new Thread(new dllRunner()); + abthread.setDaemon(true); + abthread.start(); + debugString("AccessBridge started"); + } + + /* + * adaptor to run the AccessBridge DLL + */ + private class dllRunner implements Runnable { + public void run() { + runDLL(); + } + } + + /* + * shutdown hook + */ + private class shutdownHook implements Runnable { + + public void run() { + debugString("***** shutdownHook: shutting down..."); + javaShutdown(); + } + } + + + /* + * Initialize the hashtable that maps Strings to AccessibleRoles. + */ + private void initAccessibleRoleMap() { + /* + * Initialize the AccessibleRoles map. This code uses methods in + * java.lang.reflect.* to build the map. + */ + try { + Class clAccessibleRole = Class.forName ("javax.accessibility.AccessibleRole"); + if (null != clAccessibleRole) { + AccessibleRole roleUnknown = AccessibleRole.UNKNOWN; + Field [] fields = clAccessibleRole.getFields (); + int i = 0; + for (i = 0; i < fields.length; i ++) { + Field f = fields [i]; + if (javax.accessibility.AccessibleRole.class == f.getType ()) { + AccessibleRole nextRole = (AccessibleRole) (f.get (roleUnknown)); + String nextRoleString = nextRole.toDisplayString (Locale.US); + accessibleRoleMap.put (nextRoleString, nextRole); + } + } + } + } catch (Exception e) {} + + /* + Build the extendedVirtualNameSearchRoles array list. I chose this method + because some of the Accessible Roles that need to be added to it are not + available in all versions of the J2SE that we want to support. + */ + extendedVirtualNameSearchRoles.add (AccessibleRole.COMBO_BOX); + try { + /* + Added in J2SE 1.4 + */ + extendedVirtualNameSearchRoles.add (AccessibleRole.DATE_EDITOR); + } catch (NoSuchFieldError e) {} + extendedVirtualNameSearchRoles.add (AccessibleRole.LIST); + extendedVirtualNameSearchRoles.add (AccessibleRole.PASSWORD_TEXT); + extendedVirtualNameSearchRoles.add (AccessibleRole.SLIDER); + try { + /* + Added in J2SE 1.3 + */ + extendedVirtualNameSearchRoles.add (AccessibleRole.SPIN_BOX); + } catch (NoSuchFieldError e) {} + extendedVirtualNameSearchRoles.add (AccessibleRole.TABLE); + extendedVirtualNameSearchRoles.add (AccessibleRole.TEXT); + extendedVirtualNameSearchRoles.add (AccessibleRole.UNKNOWN); + + noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TABLE); + noExtendedVirtualNameSearchParentRoles.add (AccessibleRole.TOOL_BAR); + } + + /** + * start the AccessBridge DLL running in its own thread + */ + private native void runDLL(); + + /** + * debugging output (goes to OutputDebugStr()) + */ + private native void sendDebugString(String debugStr); + + /** + * debugging output (goes to OutputDebugStr()) + */ + private void debugString(String debugStr) { + sendDebugString(debugStr); + } + + /* ===== utility methods ===== */ + + /** + * decrement the reference to the object (called by native code) + */ + private void decrementReference(Object o) { + references.decrement(o); + } + + /** + * get the java.version property from the JVM + */ + private String getJavaVersionProperty() { + String s = System.getProperty("java.version"); + if (s != null) { + references.increment(s); + return s; + } + return null; + } + + /* ===== HWND/Java window mapping methods ===== */ + + // Java toolkit methods for mapping HWNDs to Java components + private Method javaGetComponentFromNativeWindowHandleMethod; + private Method javaGetNativeWindowHandleFromComponentMethod; + + // native jawt methods for mapping HWNDs to Java components + private native int jawtGetNativeWindowHandleFromComponent(Component comp); + + private native Component jawtGetComponentFromNativeWindowHandle(int handle); + + Toolkit toolkit; + + /** + * map an HWND to an AWT Component + */ + private void initHWNDcalls() { + Class integerParemter[] = new Class[1]; + integerParemter[0] = Integer.TYPE; + Class componentParemter[] = new Class[1]; + try { + componentParemter[0] = Class.forName("java.awt.Component"); + } catch (ClassNotFoundException e) { + debugString("Exception: " + e.toString()); + } + toolkit = Toolkit.getDefaultToolkit(); + return; + } + + // native window handler interface + private interface NativeWindowHandler { + public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle); + } + + // hash table of native window handle to AccessibleContext mappings + static private ConcurrentHashMap windowHandleToContextMap = new ConcurrentHashMap<>(); + + // hash table of AccessibleContext to native window handle mappings + static private ConcurrentHashMap contextToWindowHandleMap = new ConcurrentHashMap<>(); + + /* + * adds a virtual window handler to our hash tables + */ + static private void registerVirtualFrame(final Accessible a, + Integer nativeWindowHandle ) { + if (a != null) { + AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return a.getAccessibleContext(); + } + }, a); + windowHandleToContextMap.put(nativeWindowHandle, ac); + contextToWindowHandleMap.put(ac, nativeWindowHandle); + } + } + + /* + * removes a virtual window handler to our hash tables + */ + static private void revokeVirtualFrame(final Accessible a, + Integer nativeWindowHandle ) { + AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return a.getAccessibleContext(); + } + }, a); + windowHandleToContextMap.remove(nativeWindowHandle); + contextToWindowHandleMap.remove(ac); + } + + // vector of native window handlers + private static Vector nativeWindowHandlers = new Vector<>(); + + /* + * adds a native window handler to our list + */ + private static void addNativeWindowHandler(NativeWindowHandler handler) { + if (handler == null) { + throw new IllegalArgumentException(); + } + nativeWindowHandlers.addElement(handler); + } + + /* + * removes a native window handler to our list + */ + private static boolean removeNativeWindowHandler(NativeWindowHandler handler) { + if (handler == null) { + throw new IllegalArgumentException(); + } + return nativeWindowHandlers.removeElement(handler); + } + + /** + * verifies that a native window handle is a Java window + */ + private boolean isJavaWindow(int nativeHandle) { + AccessibleContext ac = getContextFromNativeWindowHandle(nativeHandle); + if (ac != null) { + saveContextToWindowHandleMapping(ac, nativeHandle); + return true; + } + return false; + } + + /* + * saves the mapping between an AccessibleContext and a window handle + */ + private void saveContextToWindowHandleMapping(AccessibleContext ac, + int nativeHandle) { + debugString("saveContextToWindowHandleMapping..."); + if (ac == null) { + return; + } + if (! contextToWindowHandleMap.containsKey(ac)) { + debugString("saveContextToWindowHandleMapping: ac = "+ac+"; handle = "+nativeHandle); + contextToWindowHandleMap.put(ac, nativeHandle); + } + } + + /** + * maps a native window handle to an Accessible Context + */ + private AccessibleContext getContextFromNativeWindowHandle(int nativeHandle) { + // First, look for the Accessible in our hash table of + // virtual window handles. + AccessibleContext ac = windowHandleToContextMap.get(nativeHandle); + if(ac!=null) { + saveContextToWindowHandleMapping(ac, nativeHandle); + return ac; + } + + // Next, look for the native window handle in our vector + // of native window handles. + int numHandlers = nativeWindowHandlers.size(); + for (int i = 0; i < numHandlers; i++) { + NativeWindowHandler nextHandler = nativeWindowHandlers.elementAt(i); + final Accessible a = nextHandler.getAccessibleFromNativeWindowHandle(nativeHandle); + if (a != null) { + ac = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return a.getAccessibleContext(); + } + }, a); + saveContextToWindowHandleMapping(ac, nativeHandle); + return ac; + } + } + // Not found. + return null; + } + + /** + * maps an AccessibleContext to a native window handle + * returns 0 on error + */ + private int getNativeWindowHandleFromContext(AccessibleContext ac) { + debugString("getNativeWindowHandleFromContext: ac = "+ac); + try { + return contextToWindowHandleMap.get(ac); + } catch (Exception ex) { + return 0; + } + } + + private class DefaultNativeWindowHandler implements NativeWindowHandler { + /* + * returns the Accessible associated with a native window + */ + public Accessible getAccessibleFromNativeWindowHandle(int nativeHandle) { + final Component c = jawtGetComponentFromNativeWindowHandle(nativeHandle); + if (c instanceof Accessible) { + AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return c.getAccessibleContext(); + } + }, c); + saveContextToWindowHandleMapping(ac, nativeHandle); + return (Accessible)c; + } else { + return null; + } + } + } + + /* ===== AccessibleContext methods =====*/ + + /* + * returns the inner-most AccessibleContext in parent at Point(x, y) + */ + private AccessibleContext getAccessibleContextAt(int x, int y, + AccessibleContext parent) { + if (parent == null) { + return null; + } + if (windowHandleToContextMap != null && + windowHandleToContextMap.containsValue(getRootAccessibleContext(parent))) { + // Path for applications that register their top-level + // windows with the AccessBridge (e.g., StarOffice 6.1) + return getAccessibleContextAt_1(x, y, parent); + } else { + // Path for applications that do not register + // their top-level windows with the AccessBridge + // (e.g., Swing/AWT applications) + return getAccessibleContextAt_2(x, y, parent); + } + } + + /* + * returns the root accessible context + */ + private AccessibleContext getRootAccessibleContext(final AccessibleContext ac) { + if (ac == null) { + return null; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + Accessible parent = ac.getAccessibleParent(); + if (parent == null) { + return ac; + } + Accessible tmp = parent.getAccessibleContext().getAccessibleParent(); + while (tmp != null) { + parent = tmp; + tmp = parent.getAccessibleContext().getAccessibleParent(); + } + return parent.getAccessibleContext(); + } + }, ac); + } + + /* + * StarOffice version that does not use the EventQueueMonitor + */ + private AccessibleContext getAccessibleContextAt_1(final int x, final int y, + final AccessibleContext parent) { + debugString(" : getAccessibleContextAt_1 called"); + debugString(" -> x = " + x + " y = " + y + " parent = " + parent); + + if (parent == null) return null; + final AccessibleComponent acmp = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleComponent call() throws Exception { + return parent.getAccessibleComponent(); + } + }, parent); + if (acmp!=null) { + final Point loc = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Point call() throws Exception { + return acmp.getLocation(); + } + }, parent); + final Accessible a = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Accessible call() throws Exception { + return acmp.getAccessibleAt(new Point(x - loc.x, y - loc.y)); + } + }, parent); + if (a != null) { + AccessibleContext foundAC = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return a.getAccessibleContext(); + } + }, parent); + if (foundAC != null) { + if (foundAC != parent) { + // recurse down into the child + return getAccessibleContextAt_1(x - loc.x, y - loc.y, + foundAC); + } else + return foundAC; + } + } + } + return parent; + } + + /* + * AWT/Swing version + */ + private AccessibleContext getAccessibleContextAt_2(final int x, final int y, + AccessibleContext parent) { + debugString("getAccessibleContextAt_2 called"); + debugString(" -> x = " + x + " y = " + y + " parent = " + parent); + + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + Accessible a = EventQueueMonitor.getAccessibleAt(new Point(x, y)); + if (a != null) { + AccessibleContext childAC = a.getAccessibleContext(); + if (childAC != null) { + debugString(" returning childAC = " + childAC); + return childAC; + } + } + return null; + } + }, parent); + } + + /** + * returns the Accessible that has focus + */ + private AccessibleContext getAccessibleContextWithFocus() { + Component c = AWTEventMonitor.getComponentWithFocus(); + if (c != null) { + final Accessible a = Translator.getAccessible(c); + if (a != null) { + AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return a.getAccessibleContext(); + } + }, c); + if (ac != null) { + return ac; + } + } + } + return null; + } + + /** + * returns the AccessibleName from an AccessibleContext + */ + private String getAccessibleNameFromContext(final AccessibleContext ac) { + debugString("***** ac = "+ac.getClass()); + if (ac != null) { + String s = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return ac.getAccessibleName(); + } + }, ac); + if (s != null) { + references.increment(s); + debugString("Returning AccessibleName from Context: " + s); + return s; + } else { + return null; + } + } else { + debugString("getAccessibleNameFromContext; ac = null!"); + return null; + } + } + + /** + * Returns an AccessibleName for a component using an algorithm optimized + * for the JAWS screen reader. This method is only intended for JAWS. All + * other uses are entirely optional. + */ + private String getVirtualAccessibleNameFromContext(final AccessibleContext ac) { + if (null != ac) { + /* + Step 1: + ======= + Determine if we can obtain the Virtual Accessible Name from the + Accessible Name or Accessible Description of the object. + */ + String nameString = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return ac.getAccessibleName(); + } + }, ac); + if ( ( null != nameString ) && ( 0 != nameString.length () ) ) { + debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleName."); + references.increment (nameString); + return nameString; + } + String descriptionString = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return ac.getAccessibleDescription(); + } + }, ac); + if ( ( null != descriptionString ) && ( 0 != descriptionString.length () ) ) { + debugString ("bk -- The Virtual Accessible Name was obtained from AccessibleContext::getAccessibleDescription."); + references.increment (descriptionString); + return descriptionString; + } + + debugString ("The Virtual Accessible Name was not found using AccessibleContext::getAccessibleDescription. or getAccessibleName"); + /* + Step 2: + ======= + Decide whether the extended name search algorithm should be + used for this object. + */ + boolean bExtendedSearch = false; + AccessibleRole role = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRole call() throws Exception { + return ac.getAccessibleRole(); + } + }, ac); + AccessibleContext parentContext = null; + AccessibleRole parentRole = AccessibleRole.UNKNOWN; + + if ( extendedVirtualNameSearchRoles.contains (role) ) { + parentContext = getAccessibleParentFromContext (ac); + if ( null != parentContext ) { + final AccessibleContext parentContextInnerTemp = parentContext; + parentRole = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRole call() throws Exception { + return parentContextInnerTemp.getAccessibleRole(); + } + }, ac); + if ( AccessibleRole.UNKNOWN != parentRole ) { + bExtendedSearch = true; + if ( noExtendedVirtualNameSearchParentRoles.contains (parentRole) ) { + bExtendedSearch = false; + } + } + } + } + + if (false == bExtendedSearch) { + debugString ("bk -- getVirtualAccessibleNameFromContext will not use the extended name search algorithm. role = " + role.toDisplayString (Locale.US) ); + /* + Step 3: + ======= + We have determined that we should not use the extended name + search algorithm for this object (we must obtain the name of + the object from the object itself and not from neighboring + objects). However the object name cannot be obtained from + the Accessible Name or Accessible Description of the object. + + Handle several special cases here that might yield a value for + the Virtual Accessible Name. Return null if the object does + not match the criteria for any of these special cases. + */ + if (AccessibleRole.LABEL == role) { + /* + Does the label support the Accessible Text Interface? + */ + final AccessibleText at = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleText call() throws Exception { + return ac.getAccessibleText(); + } + }, ac); + if (null != at) { + int charCount = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return at.getCharCount(); + } + }, ac); + String text = getAccessibleTextRangeFromContext (ac, 0, charCount); + if (null != text) { + debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Text of the LABEL object."); + references.increment (text); + return text; + } + } + /* + Does the label support the Accessible Icon Interface? + */ + debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information."); + final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleIcon[] call() throws Exception { + return ac.getAccessibleIcon(); + } + }, ac); + if ( (null != ai) && (ai.length > 0) ) { + String iconDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return ai[0].getAccessibleIconDescription(); + } + }, ac); + if (iconDescription != null){ + debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the LABEL object."); + references.increment (iconDescription); + return iconDescription; + } + } else { + parentContext = getAccessibleParentFromContext (ac); + if ( null != parentContext ) { + final AccessibleContext parentContextInnerTemp = parentContext; + parentRole = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRole call() throws Exception { + return parentContextInnerTemp.getAccessibleRole(); + } + }, ac); + if ( AccessibleRole.TABLE == parentRole ) { + int indexInParent = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return ac.getAccessibleIndexInParent(); + } + }, ac); + final AccessibleContext acTableCell = getAccessibleChildFromContext (parentContext, indexInParent); + debugString ("bk -- Making a second attempt to obtain the Virtual Accessible Name from the Accessible Icon information for the Table Cell."); + if (acTableCell != null) { + final AccessibleIcon [] aiRet =InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleIcon[] call() throws Exception { + return acTableCell.getAccessibleIcon(); + } + }, ac); + if ( (null != aiRet) && (aiRet.length > 0) ) { + String iconDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return aiRet[0].getAccessibleIconDescription(); + } + }, ac); + if (iconDescription != null){ + debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the Table Cell object."); + references.increment (iconDescription); + return iconDescription; + } + } + } + } + } + } + } else if ( (AccessibleRole.TOGGLE_BUTTON == role) || + (AccessibleRole.PUSH_BUTTON == role) ) { + /* + Does the button support the Accessible Icon Interface? + */ + debugString ("bk -- Attempting to obtain the Virtual Accessible Name from the Accessible Icon information."); + final AccessibleIcon [] ai = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleIcon[] call() throws Exception { + return ac.getAccessibleIcon(); + } + }, ac); + if ( (null != ai) && (ai.length > 0) ) { + String iconDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return ai[0].getAccessibleIconDescription(); + } + }, ac); + if (iconDescription != null){ + debugString ("bk -- The Virtual Accessible Name was obtained from the description of the first Accessible Icon found in the TOGGLE_BUTTON or PUSH_BUTTON object."); + references.increment (iconDescription); + return iconDescription; + } + } + } else if ( AccessibleRole.CHECK_BOX == role ) { + /* + NOTE: The only case I know of in which a check box does not + have a name is when that check box is contained in a table. + + In this case it would be appropriate to use the display string + of the check box object as the name (in US English the display + string is typically either "true" or "false"). + + I am using the AccessibleValue interface to obtain the display + string of the check box. If the Accessible Value is 1, I am + returning Boolean.TRUE.toString (), If the Accessible Value is + 0, I am returning Boolean.FALSE.toString (). If the Accessible + Value is some other number, I will return the display string of + the current numerical value of the check box. + */ + final AccessibleValue av = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleValue call() throws Exception { + return ac.getAccessibleValue(); + } + }, ac); + if ( null != av ) { + nameString = null; + Number value = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Number call() throws Exception { + return av.getCurrentAccessibleValue(); + } + }, ac); + if ( null != value ) { + if ( 1 == value.intValue () ) { + nameString = Boolean.TRUE.toString (); + } else if ( 0 == value.intValue () ) { + nameString = Boolean.FALSE.toString (); + } else { + nameString = value.toString (); + } + if ( null != nameString ) { + references.increment (nameString); + return nameString; + } + } + } + } + return null; + } + + /* + + + Beginning of the extended name search + + + */ + final AccessibleContext parentContextOuterTemp = parentContext; + String parentName = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return parentContextOuterTemp.getAccessibleName(); + } + }, ac); + String parentDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return parentContextOuterTemp.getAccessibleDescription(); + } + }, ac); + + /* + Step 4: + ======= + Special case for Slider Bar objects. + */ + if ( (AccessibleRole.SLIDER == role) && + (AccessibleRole.PANEL == parentRole) && + (null != parentName) ) { + debugString ("bk -- The Virtual Accessible Name was obtained from the Accessible Name of the SLIDER object's parent object."); + references.increment (parentName); + return parentName; + } + + boolean bIsEditCombo = false; + + AccessibleContext testContext = ac; + /* + Step 5: + ======= + Special case for Edit Combo Boxes + */ + if ( (AccessibleRole.TEXT == role) && + (AccessibleRole.COMBO_BOX == parentRole) ) { + bIsEditCombo = true; + if (null != parentName) { + debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Name of the object's parent object."); + references.increment (parentName); + return parentName; + } else if (null != parentDescription) { + debugString ("bk -- The Virtual Accessible Name for this Edit Combo box was obtained from the Accessible Description of the object's parent object."); + references.increment (parentDescription); + return parentDescription; + } + testContext = parentContext; + parentRole = AccessibleRole.UNKNOWN; + parentContext = getAccessibleParentFromContext (testContext); + if ( null != parentContext ) { + final AccessibleContext parentContextInnerTemp = parentContext; + parentRole = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRole call() throws Exception { + return parentContextInnerTemp.getAccessibleRole(); + } + }, ac); + } + } + + /* + Step 6: + ======= + Attempt to get the Virtual Accessible Name of the object using the + Accessible Relation Set Info (the LABELED_BY Accessible Relation). + */ + { + final AccessibleContext parentContextTempInner = parentContext; + AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRelationSet call() throws Exception { + return parentContextTempInner.getAccessibleRelationSet(); + } + }, ac); + if ( ars != null && (ars.size () > 0) && (ars.contains (AccessibleRelation.LABELED_BY)) ) { + AccessibleRelation labeledByRelation = ars.get (AccessibleRelation.LABELED_BY); + if (labeledByRelation != null) { + Object [] targets = labeledByRelation.getTarget (); + Object o = targets [0]; + if (o instanceof Accessible) { + AccessibleContext labelContext = ((Accessible)o).getAccessibleContext (); + if (labelContext != null) { + String labelName = labelContext.getAccessibleName (); + String labelDescription = labelContext.getAccessibleDescription (); + if (null != labelName) { + debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Name Case."); + references.increment (labelName); + return labelName; + } else if (null != labelDescription) { + debugString ("bk -- The Virtual Accessible Name was obtained using the LABELED_BY AccessibleRelation -- Description Case."); + references.increment (labelDescription); + return labelDescription; + } + } + } + } + } + } + + //Note: add AccessibleContext to use InvocationUtils.invokeAndWait + /* + Step 7: + ======= + Search for a label object that is positioned either just to the left + or just above the object and get the Accessible Name of the Label + object. + */ + int testIndexMax = 0; + int testX = 0; + int testY = 0; + int testWidth = 0; + int testHeight = 0; + int targetX = 0; + int targetY = 0; + final AccessibleContext tempContext = testContext; + int testIndex = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return tempContext.getAccessibleIndexInParent(); + } + }, ac); + if ( null != parentContext ) { + final AccessibleContext parentContextInnerTemp = parentContext; + testIndexMax = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return parentContextInnerTemp.getAccessibleChildrenCount() - 1; + } + }, ac); + } + testX = getAccessibleXcoordFromContext (testContext); + testY = getAccessibleYcoordFromContext (testContext); + testWidth = getAccessibleWidthFromContext (testContext); + testHeight = getAccessibleHeightFromContext (testContext); + targetX = testX + 2; + targetY = testY + 2; + + int childIndex = testIndex - 1; + /*Accessible child = null; + AccessibleContext childContext = null; + AccessibleRole childRole = AccessibleRole.UNKNOWN;*/ + int childX = 0; + int childY = 0; + int childWidth = 0; + int childHeight = 0; + String childName = null; + String childDescription = null; + while (childIndex >= 0) { + final int childIndexTemp = childIndex; + final AccessibleContext parentContextInnerTemp = parentContext; + final Accessible child = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Accessible call() throws Exception { + return parentContextInnerTemp.getAccessibleChild(childIndexTemp); + } + }, ac); + if ( null != child ) { + final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return child.getAccessibleContext(); + } + }, ac); + if ( null != childContext ) { + AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRole call() throws Exception { + return childContext.getAccessibleRole(); + } + }, ac); + if ( AccessibleRole.LABEL == childRole ) { + childX = getAccessibleXcoordFromContext (childContext); + childY = getAccessibleYcoordFromContext (childContext); + childWidth = getAccessibleWidthFromContext (childContext); + childHeight = getAccessibleHeightFromContext (childContext); + if ( (childX < testX) && + ((childY <= targetY) && (targetY <= (childY + childHeight))) ) { + childName = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleName(); + } + }, ac); + if ( null != childName ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object."); + references.increment (childName); + return childName; + } + childDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleDescription(); + } + }, ac); + if ( null != childDescription ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object."); + references.increment (childDescription); + return childDescription; + } + } else if ( (childY < targetY) && + ((childX <= targetX) && (targetX <= (childX + childWidth))) ) { + childName = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleName(); + } + }, ac); + if ( null != childName ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object."); + references.increment (childName); + return childName; + } + childDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleDescription(); + } + }, ac); + if ( null != childDescription ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object."); + references.increment (childDescription); + return childDescription; + } + } + } + } + } + childIndex --; + } + childIndex = testIndex + 1; + while (childIndex <= testIndexMax) { + final int childIndexTemp = childIndex; + final AccessibleContext parentContextInnerTemp = parentContext; + final Accessible child = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Accessible call() throws Exception { + return parentContextInnerTemp.getAccessibleChild(childIndexTemp); + } + }, ac); + if ( null != child ) { + final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return child.getAccessibleContext(); + } + }, ac); + if ( null != childContext ) { + AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRole call() throws Exception { + return childContext.getAccessibleRole(); + } + }, ac); + if ( AccessibleRole.LABEL == childRole ) { + childX = getAccessibleXcoordFromContext (childContext); + childY = getAccessibleYcoordFromContext (childContext); + childWidth = getAccessibleWidthFromContext (childContext); + childHeight = getAccessibleHeightFromContext (childContext); + if ( (childX < testX) && + ((childY <= targetY) && (targetY <= (childY + childHeight))) ) { + childName = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleName(); + } + }, ac); + if ( null != childName ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned to the left of the object."); + references.increment (childName); + return childName; + } + childDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleDescription(); + } + }, ac); + if ( null != childDescription ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned to the left of the object."); + references.increment (childDescription); + return childDescription; + } + } else if ( (childY < targetY) && + ((childX <= targetX) && (targetX <= (childX + childWidth))) ) { + childName = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleName(); + } + }, ac); + if ( null != childName ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a LABEL object positioned above the object."); + references.increment (childName); + return childName; + } + childDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleDescription(); + } + }, ac); + if ( null != childDescription ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a LABEL object positioned above the object."); + references.increment (childDescription); + return childDescription; + } + } + } + } + } + childIndex ++; + } + /* + Step 8: + ======= + Special case for combo boxes and text objects, based on a + similar special case I found in some of our internal JAWS code. + + Search for a button object that is positioned either just to the left + or just above the object and get the Accessible Name of the button + object. + */ + if ( (AccessibleRole.TEXT == role) || + (AccessibleRole.COMBO_BOX == role) || + (bIsEditCombo) ) { + childIndex = testIndex - 1; + while (childIndex >= 0) { + final int childIndexTemp = childIndex; + final AccessibleContext parentContextInnerTemp = parentContext; + final Accessible child = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Accessible call() throws Exception { + return parentContextInnerTemp.getAccessibleChild(childIndexTemp); + } + }, ac); + if ( null != child ) { + final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return child.getAccessibleContext(); + } + }, ac); + if ( null != childContext ) { + AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRole call() throws Exception { + return childContext.getAccessibleRole(); + } + }, ac); + if ( ( AccessibleRole.PUSH_BUTTON == childRole ) || + ( AccessibleRole.TOGGLE_BUTTON == childRole )) { + childX = getAccessibleXcoordFromContext (childContext); + childY = getAccessibleYcoordFromContext (childContext); + childWidth = getAccessibleWidthFromContext (childContext); + childHeight = getAccessibleHeightFromContext (childContext); + if ( (childX < testX) && + ((childY <= targetY) && (targetY <= (childY + childHeight))) ) { + childName = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleName(); + } + }, ac); + if ( null != childName ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object."); + references.increment (childName); + return childName; + } + childDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleDescription(); + } + }, ac); + if ( null != childDescription ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object."); + references.increment (childDescription); + return childDescription; + } + } + } + } + } + childIndex --; + } + childIndex = testIndex + 1; + while (childIndex <= testIndexMax) { + final int childIndexTemp = childIndex; + final AccessibleContext parentContextInnerTemp = parentContext; + final Accessible child = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Accessible call() throws Exception { + return parentContextInnerTemp.getAccessibleChild(childIndexTemp); + } + }, ac); + if ( null != child ) { + final AccessibleContext childContext = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return child.getAccessibleContext(); + } + }, ac); + if ( null != childContext ) { + AccessibleRole childRole = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRole call() throws Exception { + return childContext.getAccessibleRole(); + } + }, ac); + if ( ( AccessibleRole.PUSH_BUTTON == childRole ) || + ( AccessibleRole.TOGGLE_BUTTON == childRole ) ) { + childX = getAccessibleXcoordFromContext (childContext); + childY = getAccessibleYcoordFromContext (childContext); + childWidth = getAccessibleWidthFromContext (childContext); + childHeight = getAccessibleHeightFromContext (childContext); + if ( (childX < testX) && + ((childY <= targetY) && (targetY <= (childY + childHeight))) ) { + childName = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleName(); + } + }, ac); + if ( null != childName ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Name of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object."); + references.increment (childName); + return childName; + } + childDescription = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return childContext.getAccessibleDescription(); + } + }, ac); + if ( null != childDescription ) { + debugString ("bk -- The Virtual Accessible Name was obtained from Accessible Description of a PUSH_BUTTON or TOGGLE_BUTTON object positioned to the left of the object."); + references.increment (childDescription); + return childDescription; + } + } + } + } + } + childIndex ++; + } + } + return null; + } else { + debugString ("AccessBridge::getVirtualAccessibleNameFromContext error - ac == null."); + return null; + } + } + + /** + * returns the AccessibleDescription from an AccessibleContext + */ + private String getAccessibleDescriptionFromContext(final AccessibleContext ac) { + if (ac != null) { + String s = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return ac.getAccessibleDescription(); + } + }, ac); + if (s != null) { + references.increment(s); + debugString("Returning AccessibleDescription from Context: " + s); + return s; + } + } else { + debugString("getAccessibleDescriptionFromContext; ac = null"); + } + return null; + } + + /** + * returns the AccessibleRole from an AccessibleContext + */ + private String getAccessibleRoleStringFromContext(final AccessibleContext ac) { + if (ac != null) { + AccessibleRole role = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRole call() throws Exception { + return ac.getAccessibleRole(); + } + }, ac); + if (role != null) { + String s = role.toDisplayString(Locale.US); + if (s != null) { + references.increment(s); + debugString("Returning AccessibleRole from Context: " + s); + return s; + } + } + } else { + debugString("getAccessibleRoleStringFromContext; ac = null"); + } + return null; + } + + /** + * return the AccessibleRole from an AccessibleContext in the en_US locale + */ + private String getAccessibleRoleStringFromContext_en_US(final AccessibleContext ac) { + return getAccessibleRoleStringFromContext(ac); + } + + /** + * return the AccessibleStates from an AccessibleContext + */ + private String getAccessibleStatesStringFromContext(final AccessibleContext ac) { + if (ac != null) { + AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleStateSet call() throws Exception { + return ac.getAccessibleStateSet(); + } + }, ac); + if (stateSet != null) { + String s = stateSet.toString(); + if (s != null && + s.indexOf(AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US)) == -1) { + // Indicate whether this component manages its own + // children + AccessibleRole role = ac.getAccessibleRole(); + if (role == AccessibleRole.LIST || + role == AccessibleRole.TABLE || + role == AccessibleRole.TREE) { + s += ","; + s += AccessibleState.MANAGES_DESCENDANTS.toDisplayString(Locale.US); + } + references.increment(s); + debugString("Returning AccessibleStateSet from Context: " + s); + return s; + } + } + } else { + debugString("getAccessibleStatesStringFromContext; ac = null"); + } + return null; + } + + /** + * returns the AccessibleStates from an AccessibleContext in the en_US locale + */ + private String getAccessibleStatesStringFromContext_en_US(final AccessibleContext ac) { + if (ac != null) { + AccessibleStateSet stateSet = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleStateSet call() throws Exception { + return ac.getAccessibleStateSet(); + } + }, ac); + if (stateSet != null) { + String s = ""; + AccessibleState[] states = stateSet.toArray(); + if (states != null && states.length > 0) { + s = states[0].toDisplayString(Locale.US); + for (int i = 1; i < states.length; i++) { + s = s + "," + states[i].toDisplayString(Locale.US); + } + } + references.increment(s); + debugString("Returning AccessibleStateSet en_US from Context: " + s); + return s; + } + } + debugString("getAccessibleStatesStringFromContext; ac = null"); + return null; + } + + /** + * returns the AccessibleParent from an AccessibleContext + */ + private AccessibleContext getAccessibleParentFromContext(final AccessibleContext ac) { + if (ac==null) + return null; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + Accessible a = ac.getAccessibleParent(); + if (a != null) { + AccessibleContext apc = a.getAccessibleContext(); + if (apc != null) { + return apc; + } + } + return null; + } + }, ac); + } + + /** + * returns the AccessibleIndexInParent from an AccessibleContext + */ + private int getAccessibleIndexInParentFromContext(final AccessibleContext ac) { + if (ac==null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return ac.getAccessibleIndexInParent(); + } + }, ac); + } + + /** + * returns the AccessibleChild count from an AccessibleContext + */ + private int getAccessibleChildrenCountFromContext(final AccessibleContext ac) { + if (ac==null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return ac.getAccessibleChildrenCount(); + } + }, ac); + } + + /** + * returns the AccessibleChild Context from an AccessibleContext + */ + private AccessibleContext getAccessibleChildFromContext(final AccessibleContext ac, final int index) { + + if (ac == null) { + return null; + } + + final JTable table = InvocationUtils.invokeAndWait(new Callable() { + @Override + public JTable call() throws Exception { + // work-around for AccessibleJTable.getCurrentAccessibleContext returning + // wrong renderer component when cell contains more than one component + Accessible parent = ac.getAccessibleParent(); + if (parent != null) { + int indexInParent = ac.getAccessibleIndexInParent(); + Accessible child = + parent.getAccessibleContext().getAccessibleChild(indexInParent); + if (child instanceof JTable) { + return (JTable) child; + } + } + return null; + } + }, ac); + + if (table == null) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + Accessible a = ac.getAccessibleChild(index); + if (a != null) { + return a.getAccessibleContext(); + } + return null; + } + }, ac); + } + + final AccessibleTable at = getAccessibleTableFromContext(ac); + + final int row = getAccessibleTableRow(at, index); + final int column = getAccessibleTableColumn(at, index); + + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + TableCellRenderer renderer = table.getCellRenderer(row, column); + if (renderer == null) { + Class columnClass = table.getColumnClass(column); + renderer = table.getDefaultRenderer(columnClass); + } + Component component = + renderer.getTableCellRendererComponent(table, table.getValueAt(row, column), + false, false, row, column); + if (component instanceof Accessible) { + return component.getAccessibleContext(); + } + return null; + } + }, ac); + } + + /** + * returns the AccessibleComponent bounds on screen from an AccessibleContext + */ + private Rectangle getAccessibleBoundsOnScreenFromContext(final AccessibleContext ac) { + if(ac==null) + return null; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Rectangle call() throws Exception { + AccessibleComponent acmp = ac.getAccessibleComponent(); + if (acmp != null) { + Rectangle r = acmp.getBounds(); + if (r != null) { + try { + Point p = acmp.getLocationOnScreen(); + if (p != null) { + r.x = p.x; + r.y = p.y; + return r; + } + } catch (Exception e) { + return null; + } + } + } + return null; + } + }, ac); + } + + /** + * returns the AccessibleComponent x-coord from an AccessibleContext + */ + private int getAccessibleXcoordFromContext(AccessibleContext ac) { + if (ac != null) { + Rectangle r = getAccessibleBoundsOnScreenFromContext(ac); + if (r != null) { + debugString(" - Returning Accessible x coord from Context: " + r.x); + return r.x; + } + } else { + debugString("getAccessibleXcoordFromContext ac = null"); + } + return -1; + } + + /** + * returns the AccessibleComponent y-coord from an AccessibleContext + */ + private int getAccessibleYcoordFromContext(AccessibleContext ac) { + debugString("getAccessibleYcoordFromContext() called"); + if (ac != null) { + Rectangle r = getAccessibleBoundsOnScreenFromContext(ac); + if (r != null) { + return r.y; + } + } else { + debugString("getAccessibleYcoordFromContext; ac = null"); + } + return -1; + } + + /** + * returns the AccessibleComponent height from an AccessibleContext + */ + private int getAccessibleHeightFromContext(AccessibleContext ac) { + if (ac != null) { + Rectangle r = getAccessibleBoundsOnScreenFromContext(ac); + if (r != null) { + return r.height; + } + } else { + debugString("getAccessibleHeightFromContext; ac = null"); + } + return -1; + } + + /** + * returns the AccessibleComponent width from an AccessibleContext + */ + private int getAccessibleWidthFromContext(AccessibleContext ac) { + if (ac != null) { + Rectangle r = getAccessibleBoundsOnScreenFromContext(ac); + if (r != null) { + return r.width; + } + } else { + debugString("getAccessibleWidthFromContext; ac = null"); + } + return -1; + } + + + /** + * returns the AccessibleComponent from an AccessibleContext + */ + private AccessibleComponent getAccessibleComponentFromContext(AccessibleContext ac) { + if (ac != null) { + AccessibleComponent acmp = ac.getAccessibleComponent(); + if (acmp != null) { + debugString("Returning AccessibleComponent Context"); + return acmp; + } + } else { + debugString("getAccessibleComponentFromContext; ac = null"); + } + return null; + } + + /** + * returns the AccessibleAction from an AccessibleContext + */ + private AccessibleAction getAccessibleActionFromContext(final AccessibleContext ac) { + debugString("Returning AccessibleAction Context"); + return ac == null ? null : InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleAction call() throws Exception { + return ac.getAccessibleAction(); + } + }, ac); + } + + /** + * returns the AccessibleSelection from an AccessibleContext + */ + private AccessibleSelection getAccessibleSelectionFromContext(final AccessibleContext ac) { + return ac == null ? null : InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleSelection call() throws Exception { + return ac.getAccessibleSelection(); + } + }, ac); + } + + /** + * return the AccessibleText from an AccessibleContext + */ + private AccessibleText getAccessibleTextFromContext(final AccessibleContext ac) { + return ac == null ? null : InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleText call() throws Exception { + return ac.getAccessibleText(); + } + }, ac); + } + + /** + * return the AccessibleComponent from an AccessibleContext + */ + private AccessibleValue getAccessibleValueFromContext(final AccessibleContext ac) { + return ac == null ? null : InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleValue call() throws Exception { + return ac.getAccessibleValue(); + } + }, ac); + } + + /* ===== AccessibleText methods ===== */ + + /** + * returns the bounding rectangle for the text cursor + * XXX + */ + private Rectangle getCaretLocation(final AccessibleContext ac) { + debugString("getCaretLocation"); + if (ac==null) + return null; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Rectangle call() throws Exception { + // workaround for JAAPI not returning cursor bounding rectangle + Rectangle r = null; + Accessible parent = ac.getAccessibleParent(); + if (parent instanceof Accessible) { + int indexInParent = ac.getAccessibleIndexInParent(); + Accessible child = + parent.getAccessibleContext().getAccessibleChild(indexInParent); + + if (child instanceof JTextComponent) { + JTextComponent text = (JTextComponent) child; + try { + r = text.modelToView(text.getCaretPosition()); + if (r != null) { + Point p = text.getLocationOnScreen(); + r.translate(p.x, p.y); + } + } catch (BadLocationException ble) { + } + } + } + return r; + } + }, ac); + } + + /** + * returns the x-coordinate for the text cursor rectangle + */ + private int getCaretLocationX(AccessibleContext ac) { + Rectangle r = getCaretLocation(ac); + if (r != null) { + return r.x; + } else { + return -1; + } + } + + /** + * returns the y-coordinate for the text cursor rectangle + */ + private int getCaretLocationY(AccessibleContext ac) { + Rectangle r = getCaretLocation(ac); + if (r != null) { + return r.y; + } else { + return -1; + } + } + + /** + * returns the height for the text cursor rectangle + */ + private int getCaretLocationHeight(AccessibleContext ac) { + Rectangle r = getCaretLocation(ac); + if (r != null) { + return r.height; + } else { + return -1; + } + } + + /** + * returns the width for the text cursor rectangle + */ + private int getCaretLocationWidth(AccessibleContext ac) { + Rectangle r = getCaretLocation(ac); + if (r != null) { + return r.width; + } else { + return -1; + } + } + + /** + * returns the character count from an AccessibleContext + */ + private int getAccessibleCharCountFromContext(final AccessibleContext ac) { + if (ac==null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + return at.getCharCount(); + } + return -1; + } + }, ac); + } + + /** + * returns the caret position from an AccessibleContext + */ + private int getAccessibleCaretPositionFromContext(final AccessibleContext ac) { + if (ac==null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + return at.getCaretPosition(); + } + return -1; + } + }, ac); + } + + /** + * Return the index at a specific point from an AccessibleContext + * Point(x, y) is in screen coordinates. + */ + private int getAccessibleIndexAtPointFromContext(final AccessibleContext ac, + final int x, final int y) { + debugString("getAccessibleIndexAtPointFromContext: x = "+x+"; y = "+y); + if (ac==null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + AccessibleComponent acomp = ac.getAccessibleComponent(); + if (at != null && acomp != null) { + // Convert x and y from screen coordinates to + // local coordinates. + try { + Point p = acomp.getLocationOnScreen(); + int x1, y1; + if (p != null) { + x1 = x - p.x; + if (x1 < 0) { + x1 = 0; + } + y1 = y - p.y; + if (y1 < 0) { + y1 = 0; + } + + Point newPoint = new Point(x1, y1); + int indexAtPoint = at.getIndexAtPoint(new Point(x1, y1)); + return indexAtPoint; + } + } catch (Exception e) { + } + } + return -1; + } + }, ac); + } + + /** + * return the letter at a specific point from an AccessibleContext + */ + private String getAccessibleLetterAtIndexFromContext(final AccessibleContext ac, final int index) { + if (ac != null) { + String s = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at == null) return null; + return at.getAtIndex(AccessibleText.CHARACTER, index); + } + }, ac); + if (s != null) { + references.increment(s); + return s; + } + } else { + debugString("getAccessibleLetterAtIndexFromContext; ac = null"); + } + return null; + } + + /** + * return the word at a specific point from an AccessibleContext + */ + private String getAccessibleWordAtIndexFromContext(final AccessibleContext ac, final int index) { + if (ac != null) { + String s = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at == null) return null; + return at.getAtIndex(AccessibleText.WORD, index); + } + }, ac); + if (s != null) { + references.increment(s); + return s; + } + } else { + debugString("getAccessibleWordAtIndexFromContext; ac = null"); + } + return null; + } + + /** + * return the sentence at a specific point from an AccessibleContext + */ + private String getAccessibleSentenceAtIndexFromContext(final AccessibleContext ac, final int index) { + if (ac != null) { + String s = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at == null) return null; + return at.getAtIndex(AccessibleText.SENTENCE, index); + } + }, ac); + if (s != null) { + references.increment(s); + return s; + } + } else { + debugString("getAccessibleSentenceAtIndexFromContext; ac = null"); + } + return null; + } + + /** + * return the text selection start from an AccessibleContext + */ + private int getAccessibleTextSelectionStartFromContext(final AccessibleContext ac) { + if (ac == null) return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + return at.getSelectionStart(); + } + return -1; + } + }, ac); + } + + /** + * return the text selection end from an AccessibleContext + */ + private int getAccessibleTextSelectionEndFromContext(final AccessibleContext ac) { + if (ac == null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + return at.getSelectionEnd(); + } + return -1; + } + }, ac); + } + + /** + * return the selected text from an AccessibleContext + */ + private String getAccessibleTextSelectedTextFromContext(final AccessibleContext ac) { + if (ac != null) { + String s = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at == null) return null; + return at.getSelectedText(); + } + }, ac); + if (s != null) { + references.increment(s); + return s; + } + } else { + debugString("getAccessibleTextSelectedTextFromContext; ac = null"); + } + return null; + } + + /** + * return the attribute string at a given index from an AccessibleContext + */ + private String getAccessibleAttributesAtIndexFromContext(final AccessibleContext ac, + final int index) { + if (ac == null) + return null; + AttributeSet as = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AttributeSet call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + return at.getCharacterAttribute(index); + } + return null; + } + }, ac); + String s = expandStyleConstants(as); + if (s != null) { + references.increment(s); + return s; + } + return null; + } + + /** + * Get line info: left index of line + * + * algorithm: cast back, doubling each time, + * 'till find line boundaries + * + * return -1 if we can't get the info (e.g. index or at passed in + * is bogus; etc.) + */ + private int getAccessibleTextLineLeftBoundsFromContext(final AccessibleContext ac, + final int index) { + if (ac == null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + int lineStart; + int offset; + Rectangle charRect; + Rectangle indexRect = at.getCharacterBounds(index); + int textLen = at.getCharCount(); + if (indexRect == null) { + return -1; + } + // find the start of the line + // + offset = 1; + lineStart = index - offset < 0 ? 0 : index - offset; + charRect = at.getCharacterBounds(lineStart); + // slouch behind beginning of line + while (charRect != null + && charRect.y >= indexRect.y + && lineStart > 0) { + offset = offset << 1; + lineStart = index - offset < 0 ? 0 : index - offset; + charRect = at.getCharacterBounds(lineStart); + } + if (lineStart == 0) { // special case: we're on the first line! + // we found it! + } else { + offset = offset >> 1; // know boundary within last expansion + // ground forward to beginning of line + while (offset > 0) { + charRect = at.getCharacterBounds(lineStart + offset); + if (charRect.y < indexRect.y) { // still before line + lineStart += offset; + } else { + // leave lineStart alone, it's close! + } + offset = offset >> 1; + } + // subtract one 'cause we're already too far... + lineStart += 1; + } + return lineStart; + } + return -1; + } + }, ac); + } + + /** + * Get line info: right index of line + * + * algorithm: cast back, doubling each time, + * 'till find line boundaries + * + * return -1 if we can't get the info (e.g. index or at passed in + * is bogus; etc.) + */ + private int getAccessibleTextLineRightBoundsFromContext(final AccessibleContext ac, final int index) { + if(ac == null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + int lineEnd; + int offset; + Rectangle charRect; + Rectangle indexRect = at.getCharacterBounds(index); + int textLen = at.getCharCount(); + if (indexRect == null) { + return -1; + } + // find the end of the line + // + offset = 1; + lineEnd = index + offset > textLen - 1 + ? textLen - 1 : index + offset; + charRect = at.getCharacterBounds(lineEnd); + // push past end of line + while (charRect != null && + charRect.y <= indexRect.y && + lineEnd < textLen - 1) { + offset = offset << 1; + lineEnd = index + offset > textLen - 1 + ? textLen - 1 : index + offset; + charRect = at.getCharacterBounds(lineEnd); + } + if (lineEnd == textLen - 1) { // special case: on the last line! + // we found it! + } else { + offset = offset >> 1; // know boundary within last expansion + // pull back to end of line + while (offset > 0) { + charRect = at.getCharacterBounds(lineEnd - offset); + if (charRect.y > indexRect.y) { // still beyond line + lineEnd -= offset; + } else { + // leave lineEnd alone, it's close! + } + offset = offset >> 1; + } + // subtract one 'cause we're already too far... + lineEnd -= 1; + } + return lineEnd; + } + return -1; + } + }, ac); + } + + /** + * Get a range of text; null if indicies are bogus + */ + private String getAccessibleTextRangeFromContext(final AccessibleContext ac, + final int start, final int end) { + String s = InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + if (ac != null) { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + // start - end is inclusive + if (start > end) { + return null; + } + if (end >= at.getCharCount()) { + return null; + } + StringBuffer buf = new StringBuffer(end - start + 1); + for (int i = start; i <= end; i++) { + buf.append(at.getAtIndex(AccessibleText.CHARACTER, i)); + } + return buf.toString(); + } + } + return null; + } + }, ac); + if (s != null) { + references.increment(s); + return s; + } else { + return null; + } + } + + /** + * return the AttributeSet object at a given index from an AccessibleContext + */ + private AttributeSet getAccessibleAttributeSetAtIndexFromContext(final AccessibleContext ac, + final int index) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AttributeSet call() throws Exception { + if (ac != null) { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + AttributeSet as = at.getCharacterAttribute(index); + if (as != null) { + AccessBridge.this.references.increment(as); + return as; + } + } + } + return null; + } + }, ac); + } + + + /** + * return the bounding rectangle at index from an AccessibleContext + */ + private Rectangle getAccessibleTextRectAtIndexFromContext(final AccessibleContext ac, + final int index) { + // want to do this in global coords, so need to combine w/ac global coords + Rectangle r = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Rectangle call() throws Exception { + // want to do this in global coords, so need to combine w/ac global coords + if (ac != null) { + AccessibleText at = ac.getAccessibleText(); + if (at != null) { + Rectangle rect = at.getCharacterBounds(index); + if (rect != null) { + String s = at.getAtIndex(AccessibleText.CHARACTER, index); + if (s != null && s.equals("\n")) { + rect.width = 0; + } + return rect; + } + } + } + return null; + } + }, ac); + Rectangle acRect = getAccessibleBoundsOnScreenFromContext(ac); + if (r != null && acRect != null) { + r.translate(acRect.x, acRect.y); + return r; + } + return null; + } + + /** + * return the AccessibleText character x-coord at index from an AccessibleContext + */ + private int getAccessibleXcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) { + if (ac != null) { + Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index); + if (r != null) { + return r.x; + } + } else { + debugString("getAccessibleXcoordTextRectAtIndexFromContext; ac = null"); + } + return -1; + } + + /** + * return the AccessibleText character y-coord at index from an AccessibleContext + */ + private int getAccessibleYcoordTextRectAtIndexFromContext(AccessibleContext ac, int index) { + if (ac != null) { + Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index); + if (r != null) { + return r.y; + } + } else { + debugString("getAccessibleYcoordTextRectAtIndexFromContext; ac = null"); + } + return -1; + } + + /** + * return the AccessibleText character height at index from an AccessibleContext + */ + private int getAccessibleHeightTextRectAtIndexFromContext(AccessibleContext ac, int index) { + if (ac != null) { + Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index); + if (r != null) { + return r.height; + } + } else { + debugString("getAccessibleHeightTextRectAtIndexFromContext; ac = null"); + } + return -1; + } + + /** + * return the AccessibleText character width at index from an AccessibleContext + */ + private int getAccessibleWidthTextRectAtIndexFromContext(AccessibleContext ac, int index) { + if (ac != null) { + Rectangle r = getAccessibleTextRectAtIndexFromContext(ac, index); + if (r != null) { + return r.width; + } + } else { + debugString("getAccessibleWidthTextRectAtIndexFromContext; ac = null"); + } + return -1; + } + + /* ===== AttributeSet methods for AccessibleText ===== */ + + /** + * return the bold setting from an AttributeSet + */ + private boolean getBoldFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.isBold(as); + } else { + debugString("getBoldFromAttributeSet; as = null"); + } + return false; + } + + /** + * return the italic setting from an AttributeSet + */ + private boolean getItalicFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.isItalic(as); + } else { + debugString("getItalicFromAttributeSet; as = null"); + } + return false; + } + + /** + * return the underline setting from an AttributeSet + */ + private boolean getUnderlineFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.isUnderline(as); + } else { + debugString("getUnderlineFromAttributeSet; as = null"); + } + return false; + } + + /** + * return the strikethrough setting from an AttributeSet + */ + private boolean getStrikethroughFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.isStrikeThrough(as); + } else { + debugString("getStrikethroughFromAttributeSet; as = null"); + } + return false; + } + + /** + * return the superscript setting from an AttributeSet + */ + private boolean getSuperscriptFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.isSuperscript(as); + } else { + debugString("getSuperscriptFromAttributeSet; as = null"); + } + return false; + } + + /** + * return the subscript setting from an AttributeSet + */ + private boolean getSubscriptFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.isSubscript(as); + } else { + debugString("getSubscriptFromAttributeSet; as = null"); + } + return false; + } + + /** + * return the background color from an AttributeSet + */ + private String getBackgroundColorFromAttributeSet(AttributeSet as) { + if (as != null) { + String s = StyleConstants.getBackground(as).toString(); + if (s != null) { + references.increment(s); + return s; + } + } else { + debugString("getBackgroundColorFromAttributeSet; as = null"); + } + return null; + } + + /** + * return the foreground color from an AttributeSet + */ + private String getForegroundColorFromAttributeSet(AttributeSet as) { + if (as != null) { + String s = StyleConstants.getForeground(as).toString(); + if (s != null) { + references.increment(s); + return s; + } + } else { + debugString("getForegroundColorFromAttributeSet; as = null"); + } + return null; + } + + /** + * return the font family from an AttributeSet + */ + private String getFontFamilyFromAttributeSet(AttributeSet as) { + if (as != null) { + String s = StyleConstants.getFontFamily(as).toString(); + if (s != null) { + references.increment(s); + return s; + } + } else { + debugString("getFontFamilyFromAttributeSet; as = null"); + } + return null; + } + + /** + * return the font size from an AttributeSet + */ + private int getFontSizeFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.getFontSize(as); + } else { + debugString("getFontSizeFromAttributeSet; as = null"); + } + return -1; + } + + /** + * return the alignment from an AttributeSet + */ + private int getAlignmentFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.getAlignment(as); + } else { + debugString("getAlignmentFromAttributeSet; as = null"); + } + return -1; + } + + /** + * return the BiDi level from an AttributeSet + */ + private int getBidiLevelFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.getBidiLevel(as); + } else { + debugString("getBidiLevelFromAttributeSet; as = null"); + } + return -1; + } + + + /** + * return the first line indent from an AttributeSet + */ + private float getFirstLineIndentFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.getFirstLineIndent(as); + } else { + debugString("getFirstLineIndentFromAttributeSet; as = null"); + } + return -1; + } + + /** + * return the left indent from an AttributeSet + */ + private float getLeftIndentFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.getLeftIndent(as); + } else { + debugString("getLeftIndentFromAttributeSet; as = null"); + } + return -1; + } + + /** + * return the right indent from an AttributeSet + */ + private float getRightIndentFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.getRightIndent(as); + } else { + debugString("getRightIndentFromAttributeSet; as = null"); + } + return -1; + } + + /** + * return the line spacing from an AttributeSet + */ + private float getLineSpacingFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.getLineSpacing(as); + } else { + debugString("getLineSpacingFromAttributeSet; as = null"); + } + return -1; + } + + /** + * return the space above from an AttributeSet + */ + private float getSpaceAboveFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.getSpaceAbove(as); + } else { + debugString("getSpaceAboveFromAttributeSet; as = null"); + } + return -1; + } + + /** + * return the space below from an AttributeSet + */ + private float getSpaceBelowFromAttributeSet(AttributeSet as) { + if (as != null) { + return StyleConstants.getSpaceBelow(as); + } else { + debugString("getSpaceBelowFromAttributeSet; as = null"); + } + return -1; + } + + /** + * Enumerate all StyleConstants in the AttributeSet + * + * We need to check explicitly, 'cause of the HTML package conversion + * mechanism (they may not be stored as StyleConstants, just translated + * to them when asked). + * + * (Use convenience methods where they are defined...) + * + * Not checking the following (which the IBM SNS guidelines says + * should be defined): + * - ComponentElementName + * - IconElementName + * - NameAttribute + * - ResolveAttribute + */ + private String expandStyleConstants(AttributeSet as) { + Color c; + Object o; + String attrString = ""; + + // ---------- check for various Character Constants + + attrString += "BidiLevel = " + StyleConstants.getBidiLevel(as); + + final Component comp = StyleConstants.getComponent(as); + if (comp != null) { + if (comp instanceof Accessible) { + final AccessibleContext ac = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return comp.getAccessibleContext(); + } + }, comp); + if (ac != null) { + attrString += "; Accessible Component = " + InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return ac.getAccessibleName(); + } + }, ac); + } else { + attrString += "; Innaccessible Component = " + comp; + } + } else { + attrString += "; Innaccessible Component = " + comp; + } + } + + Icon i = StyleConstants.getIcon(as); + if (i != null) { + if (i instanceof ImageIcon) { + attrString += "; ImageIcon = " + ((ImageIcon) i).getDescription(); + } else { + attrString += "; Icon = " + i; + } + } + + attrString += "; FontFamily = " + StyleConstants.getFontFamily(as); + + attrString += "; FontSize = " + StyleConstants.getFontSize(as); + + if (StyleConstants.isBold(as)) { + attrString += "; bold"; + } + + if (StyleConstants.isItalic(as)) { + attrString += "; italic"; + } + + if (StyleConstants.isUnderline(as)) { + attrString += "; underline"; + } + + if (StyleConstants.isStrikeThrough(as)) { + attrString += "; strikethrough"; + } + + if (StyleConstants.isSuperscript(as)) { + attrString += "; superscript"; + } + + if (StyleConstants.isSubscript(as)) { + attrString += "; subscript"; + } + + c = StyleConstants.getForeground(as); + if (c != null) { + attrString += "; Foreground = " + c; + } + + c = StyleConstants.getBackground(as); + if (c != null) { + attrString += "; Background = " + c; + } + + attrString += "; FirstLineIndent = " + StyleConstants.getFirstLineIndent(as); + + attrString += "; RightIndent = " + StyleConstants.getRightIndent(as); + + attrString += "; LeftIndent = " + StyleConstants.getLeftIndent(as); + + attrString += "; LineSpacing = " + StyleConstants.getLineSpacing(as); + + attrString += "; SpaceAbove = " + StyleConstants.getSpaceAbove(as); + + attrString += "; SpaceBelow = " + StyleConstants.getSpaceBelow(as); + + attrString += "; Alignment = " + StyleConstants.getAlignment(as); + + TabSet ts = StyleConstants.getTabSet(as); + if (ts != null) { + attrString += "; TabSet = " + ts; + } + + return attrString; + } + + + /* ===== AccessibleValue methods ===== */ + + /** + * return the AccessibleValue current value from an AccessibleContext + * returned using a String 'cause the value is a java Number + * + */ + private String getCurrentAccessibleValueFromContext(final AccessibleContext ac) { + if (ac != null) { + final Number value = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Number call() throws Exception { + AccessibleValue av = ac.getAccessibleValue(); + if (av == null) return null; + return av.getCurrentAccessibleValue(); + } + }, ac); + if (value != null) { + String s = value.toString(); + if (s != null) { + references.increment(s); + return s; + } + } + } else { + debugString("getCurrentAccessibleValueFromContext; ac = null"); + } + return null; + } + + /** + * return the AccessibleValue maximum value from an AccessibleContext + * returned using a String 'cause the value is a java Number + * + */ + private String getMaximumAccessibleValueFromContext(final AccessibleContext ac) { + if (ac != null) { + final Number value = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Number call() throws Exception { + AccessibleValue av = ac.getAccessibleValue(); + if (av == null) return null; + return av.getMaximumAccessibleValue(); + } + }, ac); + if (value != null) { + String s = value.toString(); + if (s != null) { + references.increment(s); + return s; + } + } + } else { + debugString("getMaximumAccessibleValueFromContext; ac = null"); + } + return null; + } + + /** + * return the AccessibleValue minimum value from an AccessibleContext + * returned using a String 'cause the value is a java Number + * + */ + private String getMinimumAccessibleValueFromContext(final AccessibleContext ac) { + if (ac != null) { + final Number value = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Number call() throws Exception { + AccessibleValue av = ac.getAccessibleValue(); + if (av == null) return null; + return av.getMinimumAccessibleValue(); + } + }, ac); + if (value != null) { + String s = value.toString(); + if (s != null) { + references.increment(s); + return s; + } + } + } else { + debugString("getMinimumAccessibleValueFromContext; ac = null"); + } + return null; + } + + + /* ===== AccessibleSelection methods ===== */ + + /** + * add to the AccessibleSelection of an AccessibleContext child i + * + */ + private void addAccessibleSelectionFromContext(final AccessibleContext ac, final int i) { + try { + InvocationUtils.invokeAndWait(new Callable() { + @Override + public Object call() throws Exception { + if (ac != null) { + AccessibleSelection as = ac.getAccessibleSelection(); + if (as != null) { + as.addAccessibleSelection(i); + } + } + return null; + } + }, ac); + } catch(Exception e){} + } + + /** + * clear all of the AccessibleSelection of an AccessibleContex + * + */ + private void clearAccessibleSelectionFromContext(final AccessibleContext ac) { + try { + InvocationUtils.invokeAndWait(new Callable() { + @Override + public Object call() throws Exception { + AccessibleSelection as = ac.getAccessibleSelection(); + if (as != null) { + as.clearAccessibleSelection(); + } + return null; + } + }, ac); + } catch(Exception e){} + + } + + /** + * get the AccessibleContext of the i-th AccessibleSelection of an AccessibleContext + * + */ + private AccessibleContext getAccessibleSelectionFromContext(final AccessibleContext ac, final int i) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + if (ac != null) { + AccessibleSelection as = ac.getAccessibleSelection(); + if (as != null) { + Accessible a = as.getAccessibleSelection(i); + if (a == null) + return null; + else + return a.getAccessibleContext(); + } + } + return null; + } + }, ac); + } + + /** + * get number of things selected in the AccessibleSelection of an AccessibleContext + * + */ + private int getAccessibleSelectionCountFromContext(final AccessibleContext ac) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + if (ac != null) { + AccessibleSelection as = ac.getAccessibleSelection(); + if (as != null) { + return as.getAccessibleSelectionCount(); + } + } + return -1; + } + }, ac); + } + + /** + * return true if the i-th child of the AccessibleSelection of an AccessibleContext is selected + * + */ + private boolean isAccessibleChildSelectedFromContext(final AccessibleContext ac, final int i) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + if (ac != null) { + AccessibleSelection as = ac.getAccessibleSelection(); + if (as != null) { + return as.isAccessibleChildSelected(i); + } + } + return false; + } + }, ac); + } + + /** + * remove the i-th child from the AccessibleSelection of an AccessibleContext + * + */ + private void removeAccessibleSelectionFromContext(final AccessibleContext ac, final int i) { + InvocationUtils.invokeAndWait(new Callable() { + @Override + public Object call() throws Exception { + if (ac != null) { + AccessibleSelection as = ac.getAccessibleSelection(); + if (as != null) { + as.removeAccessibleSelection(i); + } + } + return null; + } + }, ac); + } + + /** + * select all (if possible) of the children of the AccessibleSelection of an AccessibleContext + * + */ + private void selectAllAccessibleSelectionFromContext(final AccessibleContext ac) { + InvocationUtils.invokeAndWait(new Callable() { + @Override + public Object call() throws Exception { + if (ac != null) { + AccessibleSelection as = ac.getAccessibleSelection(); + if (as != null) { + as.selectAllAccessibleSelection(); + } + } + return null; + } + }, ac); + } + + // ======== AccessibleTable ======== + + ConcurrentHashMap hashtab = new ConcurrentHashMap<>(); + + /** + * returns the AccessibleTable for an AccessibleContext + */ + private AccessibleTable getAccessibleTableFromContext(final AccessibleContext ac) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleTable call() throws Exception { + if (ac != null) { + AccessibleTable at = ac.getAccessibleTable(); + if (at != null) { + AccessBridge.this.hashtab.put(at, ac); + return at; + } + } + return null; + } + }, ac); + } + + + /* + * returns the AccessibleContext that contains an AccessibleTable + */ + private AccessibleContext getContextFromAccessibleTable(AccessibleTable at) { + return hashtab.get(at); + } + + /* + * returns the row count for an AccessibleTable + */ + private int getAccessibleTableRowCount(final AccessibleContext ac) { + debugString("##### getAccessibleTableRowCount"); + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + if (ac != null) { + AccessibleTable at = ac.getAccessibleTable(); + if (at != null) { + return at.getAccessibleRowCount(); + } + } + return -1; + } + }, ac); + } + + /* + * returns the column count for an AccessibleTable + */ + private int getAccessibleTableColumnCount(final AccessibleContext ac) { + debugString("##### getAccessibleTableColumnCount"); + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + if (ac != null) { + AccessibleTable at = ac.getAccessibleTable(); + if (at != null) { + return at.getAccessibleColumnCount(); + } + } + return -1; + } + }, ac); + } + + /* + * returns the AccessibleContext for an AccessibleTable cell + */ + private AccessibleContext getAccessibleTableCellAccessibleContext(final AccessibleTable at, + final int row, final int column) { + debugString("getAccessibleTableCellAccessibleContext: at = "+at.getClass()); + if (at == null) return null; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + if (!(at instanceof AccessibleContext)) { + Accessible a = at.getAccessibleAt(row, column); + if (a != null) { + return a.getAccessibleContext(); + } + } else { + // work-around for AccessibleJTable.getCurrentAccessibleContext returning + // wrong renderer component when cell contains more than one component + AccessibleContext ac = (AccessibleContext) at; + Accessible parent = ac.getAccessibleParent(); + if (parent != null) { + int indexInParent = ac.getAccessibleIndexInParent(); + Accessible child = + parent.getAccessibleContext().getAccessibleChild(indexInParent); + if (child instanceof JTable) { + JTable table = (JTable) child; + + TableCellRenderer renderer = table.getCellRenderer(row, column); + if (renderer == null) { + Class columnClass = table.getColumnClass(column); + renderer = table.getDefaultRenderer(columnClass); + } + Component component = + renderer.getTableCellRendererComponent(table, table.getValueAt(row, column), + false, false, row, column); + if (component instanceof Accessible) { + return component.getAccessibleContext(); + } + } + } + } + return null; + } + }, getContextFromAccessibleTable(at)); + } + + /* + * returns the index of a cell at a given row and column in an AccessibleTable + */ + private int getAccessibleTableCellIndex(final AccessibleTable at, int row, int column) { + debugString("##### getAccessibleTableCellIndex: at="+at); + if (at != null) { + int cellIndex = row * + InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return at.getAccessibleColumnCount(); + } + }, getContextFromAccessibleTable(at)) + + column; + debugString(" ##### getAccessibleTableCellIndex="+cellIndex); + return cellIndex; + } + debugString(" ##### getAccessibleTableCellIndex FAILED"); + return -1; + } + + /* + * returns the row extent of a cell at a given row and column in an AccessibleTable + */ + private int getAccessibleTableCellRowExtent(final AccessibleTable at, final int row, final int column) { + debugString("##### getAccessibleTableCellRowExtent"); + if (at != null) { + int rowExtent = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return at.getAccessibleRowExtentAt(row, column); + } + }, + getContextFromAccessibleTable(at)); + debugString(" ##### getAccessibleTableCellRowExtent="+rowExtent); + return rowExtent; + } + debugString(" ##### getAccessibleTableCellRowExtent FAILED"); + return -1; + } + + /* + * returns the column extent of a cell at a given row and column in an AccessibleTable + */ + private int getAccessibleTableCellColumnExtent(final AccessibleTable at, final int row, final int column) { + debugString("##### getAccessibleTableCellColumnExtent"); + if (at != null) { + int columnExtent = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return at.getAccessibleColumnExtentAt(row, column); + } + }, + getContextFromAccessibleTable(at)); + debugString(" ##### getAccessibleTableCellColumnExtent="+columnExtent); + return columnExtent; + } + debugString(" ##### getAccessibleTableCellColumnExtent FAILED"); + return -1; + } + + /* + * returns whether a cell is selected at a given row and column in an AccessibleTable + */ + private boolean isAccessibleTableCellSelected(final AccessibleTable at, final int row, + final int column) { + debugString("##### isAccessibleTableCellSelected: ["+row+"]["+column+"]"); + if (at == null) + return false; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + boolean isSelected = false; + Accessible a = at.getAccessibleAt(row, column); + if (a != null) { + AccessibleContext ac = a.getAccessibleContext(); + if (ac == null) + return false; + AccessibleStateSet as = ac.getAccessibleStateSet(); + if (as != null) { + isSelected = as.contains(AccessibleState.SELECTED); + } + } + return isSelected; + } + }, getContextFromAccessibleTable(at)); + } + + /* + * returns an AccessibleTable that represents the row header in an + * AccessibleTable + */ + private AccessibleTable getAccessibleTableRowHeader(final AccessibleContext ac) { + debugString(" ##### getAccessibleTableRowHeader called"); + AccessibleTable at = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleTable call() throws Exception { + if (ac != null) { + AccessibleTable at = ac.getAccessibleTable(); + if (at != null) { + return at.getAccessibleRowHeader(); + } + } + return null; + } + }, ac); + if (at != null) { + hashtab.put(at, ac); + } + return at; + } + + /* + * returns an AccessibleTable that represents the column header in an + * AccessibleTable + */ + private AccessibleTable getAccessibleTableColumnHeader(final AccessibleContext ac) { + debugString("##### getAccessibleTableColumnHeader"); + if (ac == null) + return null; + AccessibleTable at = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleTable call() throws Exception { + // workaround for getAccessibleColumnHeader NPE + // when the table header is null + Accessible parent = ac.getAccessibleParent(); + if (parent != null) { + int indexInParent = ac.getAccessibleIndexInParent(); + Accessible child = + parent.getAccessibleContext().getAccessibleChild(indexInParent); + if (child instanceof JTable) { + JTable table = (JTable) child; + if (table.getTableHeader() == null) { + return null; + } + } + } + AccessibleTable at = ac.getAccessibleTable(); + if (at != null) { + return at.getAccessibleColumnHeader(); + } + return null; + } + }, ac); + if (at != null) { + hashtab.put(at, ac); + } + return at; + } + + /* + * returns the number of row headers in an AccessibleTable that represents + * the row header in an AccessibleTable + */ + private int getAccessibleTableRowHeaderRowCount(AccessibleContext ac) { + + debugString(" ##### getAccessibleTableRowHeaderRowCount called"); + if (ac != null) { + final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac); + if (atRowHeader != null) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + if (atRowHeader != null) { + return atRowHeader.getAccessibleRowCount(); + } + return -1; + } + }, ac); + } + } + return -1; + } + + /* + * returns the number of column headers in an AccessibleTable that represents + * the row header in an AccessibleTable + */ + private int getAccessibleTableRowHeaderColumnCount(AccessibleContext ac) { + debugString(" ##### getAccessibleTableRowHeaderColumnCount called"); + if (ac != null) { + final AccessibleTable atRowHeader = getAccessibleTableRowHeader(ac); + if (atRowHeader != null) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + if (atRowHeader != null) { + return atRowHeader.getAccessibleColumnCount(); + } + return -1; + } + }, ac); + } + } + debugString(" ##### getAccessibleTableRowHeaderColumnCount FAILED"); + return -1; + } + + /* + * returns the number of row headers in an AccessibleTable that represents + * the column header in an AccessibleTable + */ + private int getAccessibleTableColumnHeaderRowCount(AccessibleContext ac) { + + debugString("##### getAccessibleTableColumnHeaderRowCount"); + if (ac != null) { + final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac); + if (atColumnHeader != null) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + if (atColumnHeader != null) { + return atColumnHeader.getAccessibleRowCount(); + } + return -1; + } + }, ac); + } + } + debugString(" ##### getAccessibleTableColumnHeaderRowCount FAILED"); + return -1; + } + + /* + * returns the number of column headers in an AccessibleTable that represents + * the column header in an AccessibleTable + */ + private int getAccessibleTableColumnHeaderColumnCount(AccessibleContext ac) { + + debugString("##### getAccessibleTableColumnHeaderColumnCount"); + if (ac != null) { + final AccessibleTable atColumnHeader = getAccessibleTableColumnHeader(ac); + if (atColumnHeader != null) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + if (atColumnHeader != null) { + return atColumnHeader.getAccessibleColumnCount(); + } + return -1; + } + }, ac); + } + } + debugString(" ##### getAccessibleTableColumnHeaderColumnCount FAILED"); + return -1; + } + + /* + * returns the description of a row header in an AccessibleTable + */ + private AccessibleContext getAccessibleTableRowDescription(final AccessibleTable table, + final int row) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + if (table != null) { + Accessible a = table.getAccessibleRowDescription(row); + if (a != null) { + return a.getAccessibleContext(); + } + } + return null; + } + }, getContextFromAccessibleTable(table)); + } + + /* + * returns the description of a column header in an AccessibleTable + */ + private AccessibleContext getAccessibleTableColumnDescription(final AccessibleTable at, + final int column) { + if (at == null) + return null; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + Accessible a = at.getAccessibleColumnDescription(column); + if (a != null) { + return a.getAccessibleContext(); + } + return null; + } + }, getContextFromAccessibleTable(at)); + } + + /* + * returns the number of rows selected in an AccessibleTable + */ + private int getAccessibleTableRowSelectionCount(final AccessibleTable at) { + if (at != null) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + int[] selections = at.getSelectedAccessibleRows(); + if (selections != null) + return selections.length; + else + return -1; + } + }, getContextFromAccessibleTable(at)); + } + return -1; + } + + /* + * returns the row number of the i-th selected row in an AccessibleTable + */ + private int getAccessibleTableRowSelections(final AccessibleTable at, final int i) { + if (at != null) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + int[] selections = at.getSelectedAccessibleRows(); + if (selections.length > i) { + return selections[i]; + } + return -1; + } + }, getContextFromAccessibleTable(at)); + } + return -1; + } + + /* + * returns whether a row is selected in an AccessibleTable + */ + private boolean isAccessibleTableRowSelected(final AccessibleTable at, + final int row) { + if (at == null) + return false; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + return at.isAccessibleRowSelected(row); + } + }, getContextFromAccessibleTable(at)); + } + + /* + * returns whether a column is selected in an AccessibleTable + */ + private boolean isAccessibleTableColumnSelected(final AccessibleTable at, + final int column) { + if (at == null) + return false; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + return at.isAccessibleColumnSelected(column); + } + }, getContextFromAccessibleTable(at)); + } + + /* + * returns the number of columns selected in an AccessibleTable + */ + private int getAccessibleTableColumnSelectionCount(final AccessibleTable at) { + if (at == null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + int[] selections = at.getSelectedAccessibleColumns(); + if (selections != null) + return selections.length; + else + return -1; + } + }, getContextFromAccessibleTable(at)); + } + + /* + * returns the row number of the i-th selected row in an AccessibleTable + */ + private int getAccessibleTableColumnSelections(final AccessibleTable at, final int i) { + if (at == null) + return -1; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + int[] selections = at.getSelectedAccessibleColumns(); + if (selections != null && selections.length > i) { + return selections[i]; + } + return -1; + } + }, getContextFromAccessibleTable(at)); + } + + /* ===== AccessibleExtendedTable (since 1.4) ===== */ + + /* + * returns the row number for a cell at a given index in an AccessibleTable + */ + private int getAccessibleTableRow(final AccessibleTable at, int index) { + if (at == null) + return -1; + int colCount=InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return at.getAccessibleColumnCount(); + } + }, getContextFromAccessibleTable(at)); + return index / colCount; + } + + /* + * returns the column number for a cell at a given index in an AccessibleTable + */ + private int getAccessibleTableColumn(final AccessibleTable at, int index) { + if (at == null) + return -1; + int colCount=InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return at.getAccessibleColumnCount(); + } + }, getContextFromAccessibleTable(at)); + return index % colCount; + } + + /* + * returns the index for a cell at a given row and column in an + * AccessibleTable + */ + private int getAccessibleTableIndex(final AccessibleTable at, int row, int column) { + if (at == null) + return -1; + int colCount = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return at.getAccessibleColumnCount(); + } + }, getContextFromAccessibleTable(at)); + return row * colCount + column; + } + + // ===== AccessibleRelationSet ===== + + /* + * returns the number of relations in the AccessibleContext's + * AccessibleRelationSet + */ + private int getAccessibleRelationCount(final AccessibleContext ac) { + { + if (ac != null) { + AccessibleRelationSet ars = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleRelationSet call() throws Exception { + return ac.getAccessibleRelationSet(); + } + }, ac); + if (ars != null) + return ars.size(); + } + } + return 0; + } + + /* + * returns the ith relation key in the AccessibleContext's + * AccessibleRelationSet + */ + private String getAccessibleRelationKey(final AccessibleContext ac, final int i) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + if (ac != null) { + AccessibleRelationSet ars = ac.getAccessibleRelationSet(); + if (ars != null) { + AccessibleRelation[] relations = ars.toArray(); + if (relations != null && i >= 0 && i < relations.length) { + return relations[i].getKey(); + } + } + } + return null; + } + }, ac); + } + + /* + * returns the number of targets in a relation in the AccessibleContext's + * AccessibleRelationSet + */ + private int getAccessibleRelationTargetCount(final AccessibleContext ac, final int i) { + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + if (ac != null) { + AccessibleRelationSet ars = ac.getAccessibleRelationSet(); + if (ars != null) { + AccessibleRelation[] relations = ars.toArray(); + if (relations != null && i >= 0 && i < relations.length) { + Object[] targets = relations[i].getTarget(); + return targets.length; + } + } + } + return -1; + } + }, ac); + } + + /* + * returns the jth target in the ith relation in the AccessibleContext's + * AccessibleRelationSet + */ + private AccessibleContext getAccessibleRelationTarget(final AccessibleContext ac, + final int i, final int j) { + debugString("***** getAccessibleRelationTarget"); + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + if (ac != null) { + AccessibleRelationSet ars = ac.getAccessibleRelationSet(); + if (ars != null) { + AccessibleRelation[] relations = ars.toArray(); + if (relations != null && i >= 0 && i < relations.length) { + Object[] targets = relations[i].getTarget(); + if (targets != null && j >= 0 & j < targets.length) { + Object o = targets[j]; + if (o instanceof Accessible) { + return ((Accessible) o).getAccessibleContext(); + } + } + } + } + } + return null; + } + }, ac); + } + + // ========= AccessibleHypertext ========= + + private Map hyperTextContextMap = new WeakHashMap<>(); + private Map hyperLinkContextMap = new WeakHashMap<>(); + + /* + * Returns the AccessibleHypertext + */ + private AccessibleHypertext getAccessibleHypertext(final AccessibleContext ac) { + debugString("getAccessibleHyperlink"); + if (ac==null) + return null; + AccessibleHypertext hypertext = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleHypertext call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (!(at instanceof AccessibleHypertext)) { + return null; + } + return ((AccessibleHypertext) at); + } + }, ac); + hyperTextContextMap.put(hypertext, ac); + return hypertext; + } + + /* + * Returns the number of AccessibleHyperlinks + */ + private int getAccessibleHyperlinkCount(AccessibleContext ac) { + debugString("getAccessibleHyperlinkCount"); + if (ac == null) { + return 0; + } + final AccessibleHypertext hypertext = getAccessibleHypertext(ac); + if (hypertext == null) { + return 0; + } + //return hypertext.getLinkCount(); + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return hypertext.getLinkCount(); + } + }, ac); + } + + /* + * Returns the hyperlink at the specified index + */ + private AccessibleHyperlink getAccessibleHyperlink(final AccessibleHypertext hypertext, final int i) { + debugString("getAccessibleHyperlink"); + if (hypertext == null) { + return null; + } + AccessibleContext ac = hyperTextContextMap.get(hypertext); + if ( i < 0 || i >= + InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return hypertext.getLinkCount(); + } + }, ac) ) { + return null; + } + AccessibleHyperlink acLink = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleHyperlink call() throws Exception { + AccessibleHyperlink link = hypertext.getLink(i); + if (link == null || (!link.isValid())) { + return null; + } + return link; + } + }, ac); + hyperLinkContextMap.put(acLink, ac); + return acLink; + } + + /* + * Returns the hyperlink object description + */ + private String getAccessibleHyperlinkText(final AccessibleHyperlink link) { + debugString("getAccessibleHyperlinkText"); + if (link == null) { + return null; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + Object o = link.getAccessibleActionDescription(0); + if (o != null) { + return o.toString(); + } + return null; + } + }, hyperLinkContextMap.get(link)); + } + + /* + * Returns the hyperlink URL + */ + private String getAccessibleHyperlinkURL(final AccessibleHyperlink link) { + debugString("getAccessibleHyperlinkURL"); + if (link == null) { + return null; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + Object o = link.getAccessibleActionObject(0); + if (o != null) { + return o.toString(); + } else { + return null; + } + } + }, hyperLinkContextMap.get(link)); + } + + /* + * Returns the start index of the hyperlink text + */ + private int getAccessibleHyperlinkStartIndex(final AccessibleHyperlink link) { + debugString("getAccessibleHyperlinkStartIndex"); + if (link == null) { + return -1; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return link.getStartIndex(); + } + }, hyperLinkContextMap.get(link)); + } + + /* + * Returns the end index of the hyperlink text + */ + private int getAccessibleHyperlinkEndIndex(final AccessibleHyperlink link) { + debugString("getAccessibleHyperlinkEndIndex"); + if (link == null) { + return -1; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return link.getEndIndex(); + } + }, hyperLinkContextMap.get(link)); + } + + /* + * Returns the index into an array of hyperlinks that + * is associated with this character index, or -1 if there + * is no hyperlink associated with this index. + */ + private int getAccessibleHypertextLinkIndex(final AccessibleHypertext hypertext, final int charIndex) { + debugString("getAccessibleHypertextLinkIndex: charIndex = "+charIndex); + if (hypertext == null) { + return -1; + } + int linkIndex = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return hypertext.getLinkIndex(charIndex); + } + }, hyperTextContextMap.get(hypertext)); + debugString("getAccessibleHypertextLinkIndex returning "+linkIndex); + return linkIndex; + } + + /* + * Actives the hyperlink + */ + private boolean activateAccessibleHyperlink(final AccessibleContext ac, + final AccessibleHyperlink link) { + //debugString("activateAccessibleHyperlink: link = "+link.getClass()); + if (link == null) { + return false; + } + boolean retval = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + return link.doAccessibleAction(0); + } + }, ac); + debugString("activateAccessibleHyperlink: returning = "+retval); + return retval; + } + + + // ============ AccessibleKeyBinding ============= + + /* + * returns the component mnemonic + */ + private KeyStroke getMnemonic(final AccessibleContext ac) { + if (ac == null) + return null; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public KeyStroke call() throws Exception { + AccessibleComponent comp = ac.getAccessibleComponent(); + if (!(comp instanceof AccessibleExtendedComponent)) { + return null; + } + AccessibleExtendedComponent aec = (AccessibleExtendedComponent) comp; + if (aec != null) { + AccessibleKeyBinding akb = aec.getAccessibleKeyBinding(); + if (akb != null) { + Object o = akb.getAccessibleKeyBinding(0); + if (o instanceof KeyStroke) { + return (KeyStroke) o; + } + } + } + return null; + } + }, ac); + } + + /* + * returns the JMenuItem accelerator + */ + private KeyStroke getAccelerator(final AccessibleContext ac) { + // workaround for getAccessibleKeyBinding not returning the + // JMenuItem accelerator + if (ac == null) + return null; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public KeyStroke call() throws Exception { + Accessible parent = ac.getAccessibleParent(); + if (parent instanceof Accessible) { + int indexInParent = ac.getAccessibleIndexInParent(); + Accessible child = + parent.getAccessibleContext().getAccessibleChild(indexInParent); + if (child instanceof JMenuItem) { + JMenuItem menuItem = (JMenuItem) child; + if (menuItem == null) + return null; + KeyStroke keyStroke = menuItem.getAccelerator(); + return keyStroke; + } + } + return null; + } + }, ac); + } + + /* + * returns 1-24 to indicate which F key is being used for a shortcut or 0 otherwise + */ + private int fKeyNumber(KeyStroke keyStroke) { + if (keyStroke == null) + return 0; + int fKey = 0; + String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode()); + if (keyText != null && (keyText.length() == 2 || keyText.length() == 3)) { + String prefix = keyText.substring(0, 1); + if (prefix.equals("F")) { + try { + int suffix = Integer.parseInt(keyText.substring(1)); + if (suffix >= 1 && suffix <= 24) { + fKey = suffix; + } + } catch (Exception e) { // ignore NumberFormatException + } + } + } + return fKey; + } + + /* + * returns one of several important control characters or 0 otherwise + */ + private int controlCode(KeyStroke keyStroke) { + if (keyStroke == null) + return 0; + int code = keyStroke.getKeyCode(); + switch (code) { + case KeyEvent.VK_BACK_SPACE: + case KeyEvent.VK_DELETE: + case KeyEvent.VK_DOWN: + case KeyEvent.VK_END: + case KeyEvent.VK_HOME: + case KeyEvent.VK_INSERT: + case KeyEvent.VK_KP_DOWN: + case KeyEvent.VK_KP_LEFT: + case KeyEvent.VK_KP_RIGHT: + case KeyEvent.VK_KP_UP: + case KeyEvent.VK_LEFT: + case KeyEvent.VK_PAGE_DOWN: + case KeyEvent.VK_PAGE_UP: + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_UP: + break; + default: + code = 0; + break; + } + return code; + } + + /* + * returns the KeyStoke character + */ + private char getKeyChar(KeyStroke keyStroke) { + // If the shortcut is an FKey return 1-24 + if (keyStroke == null) + return 0; + int fKey = fKeyNumber(keyStroke); + if (fKey != 0) { + // return 0x00000001 through 0x00000018 + debugString(" Shortcut is: F" + fKey); + return (char)fKey; + } + // If the accelerator is a control character, return it + int keyCode = controlCode(keyStroke); + if (keyCode != 0) { + debugString(" Shortcut is control character: " + Integer.toHexString(keyCode)); + return (char)keyCode; + } + String keyText = KeyEvent.getKeyText(keyStroke.getKeyCode()); + debugString(" Shortcut is: " + keyText); + if (keyText != null || keyText.length() > 0) { + CharSequence seq = keyText.subSequence(0, 1); + if (seq != null || seq.length() > 0) { + return seq.charAt(0); + } + } + return 0; + } + + /* + * returns the KeyStroke modifiers as an int + */ + private int getModifiers(KeyStroke keyStroke) { + if (keyStroke == null) + return 0; + debugString("In AccessBridge.getModifiers"); + // modifiers is a bit strip where bits 0-7 indicate a traditional modifier + // such as Ctrl/Alt/Shift, bit 8 indicates an F key shortcut, and bit 9 indicates + // a control code shortcut such as the delete key. + + int modifiers = 0; + // Is the shortcut an FKey? + if (fKeyNumber(keyStroke) != 0) { + modifiers |= 1 << 8; + } + // Is the shortcut a control code? + if (controlCode(keyStroke) != 0) { + modifiers |= 1 << 9; + } + // The following is needed in order to handle translated modifiers. + // getKeyModifiersText doesn't work because for example in German Strg is + // returned for Ctrl. + + // There can be more than one modifier, e.g. if the modifier is ctrl + shift + B + // the toString text is "shift ctrl pressed B". Need to parse through that. + StringTokenizer st = new StringTokenizer(keyStroke.toString()); + while (st.hasMoreTokens()) { + String text = st.nextToken(); + // Meta+Ctrl+Alt+Shift + // 0-3 are shift, ctrl, meta, alt + // 4-7 are for Solaris workstations (though not being used) + if (text.startsWith("met")) { + debugString(" found meta"); + modifiers |= ActionEvent.META_MASK; + } + if (text.startsWith("ctr")) { + debugString(" found ctrl"); + modifiers |= ActionEvent.CTRL_MASK; + } + if (text.startsWith("alt")) { + debugString(" found alt"); + modifiers |= ActionEvent.ALT_MASK; + } + if (text.startsWith("shi")) { + debugString(" found shift"); + modifiers |= ActionEvent.SHIFT_MASK; + } + } + debugString(" returning modifiers: 0x" + Integer.toHexString(modifiers)); + return modifiers; + } + + /* + * returns the number of key bindings associated with this context + */ + private int getAccessibleKeyBindingsCount(AccessibleContext ac) { + if (ac == null) + return 0; + int count = 0; + + if (getMnemonic(ac) != null) { + count++; + } + if (getAccelerator(ac) != null) { + count++; + } + return count; + } + + /* + * returns the key binding character at the specified index + */ + private char getAccessibleKeyBindingChar(AccessibleContext ac, int index) { + if (ac == null) + return 0; + if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic + KeyStroke keyStroke = getAccelerator(ac); + if (keyStroke != null) { + return getKeyChar(keyStroke); + } + } + if (index == 0) { // mnemonic + KeyStroke keyStroke = getMnemonic(ac); + if (keyStroke != null) { + return getKeyChar(keyStroke); + } + } else if (index == 1) { // accelerator + KeyStroke keyStroke = getAccelerator(ac); + if (keyStroke != null) { + return getKeyChar(keyStroke); + } + } + return 0; + } + + /* + * returns the key binding modifiers at the specified index + */ + private int getAccessibleKeyBindingModifiers(AccessibleContext ac, int index) { + if (ac == null) + return 0; + if((index == 0) && getMnemonic(ac)==null) {// special case when there is no mnemonic + KeyStroke keyStroke = getAccelerator(ac); + if (keyStroke != null) { + return getModifiers(keyStroke); + } + } + if (index == 0) { // mnemonic + KeyStroke keyStroke = getMnemonic(ac); + if (keyStroke != null) { + return getModifiers(keyStroke); + } + } else if (index == 1) { // accelerator + KeyStroke keyStroke = getAccelerator(ac); + if (keyStroke != null) { + return getModifiers(keyStroke); + } + } + return 0; + } + + // ========== AccessibleIcon ============ + + /* + * return the number of icons associated with this context + */ + private int getAccessibleIconsCount(final AccessibleContext ac) { + debugString("getAccessibleIconsCount"); + if (ac == null) { + return 0; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleIcon[] ai = ac.getAccessibleIcon(); + if (ai == null) { + return 0; + } + return ai.length; + } + }, ac); + } + + /* + * return icon description at the specified index + */ + private String getAccessibleIconDescription(final AccessibleContext ac, final int index) { + debugString("getAccessibleIconDescription: index = "+index); + if (ac == null) { + return null; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + AccessibleIcon[] ai = ac.getAccessibleIcon(); + if (ai == null || index < 0 || index >= ai.length) { + return null; + } + return ai[index].getAccessibleIconDescription(); + } + }, ac); + } + + /* + * return icon height at the specified index + */ + private int getAccessibleIconHeight(final AccessibleContext ac, final int index) { + debugString("getAccessibleIconHeight: index = "+index); + if (ac == null) { + return 0; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleIcon[] ai = ac.getAccessibleIcon(); + if (ai == null || index < 0 || index >= ai.length) { + return 0; + } + return ai[index].getAccessibleIconHeight(); + } + }, ac); + } + + /* + * return icon width at the specified index + */ + private int getAccessibleIconWidth(final AccessibleContext ac, final int index) { + debugString("getAccessibleIconWidth: index = "+index); + if (ac == null) { + return 0; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleIcon[] ai = ac.getAccessibleIcon(); + if (ai == null || index < 0 || index >= ai.length) { + return 0; + } + return ai[index].getAccessibleIconWidth(); + } + }, ac); + } + + // ========= AccessibleAction =========== + + /* + * return the number of icons associated with this context + */ + private int getAccessibleActionsCount(final AccessibleContext ac) { + debugString("getAccessibleActionsCount"); + if (ac == null) { + return 0; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + AccessibleAction aa = ac.getAccessibleAction(); + if (aa == null) + return 0; + return aa.getAccessibleActionCount(); + } + }, ac); + } + + /* + * return icon description at the specified index + */ + private String getAccessibleActionName(final AccessibleContext ac, final int index) { + debugString("getAccessibleActionName: index = "+index); + if (ac == null) { + return null; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + AccessibleAction aa = ac.getAccessibleAction(); + if (aa == null) { + return null; + } + return aa.getAccessibleActionDescription(index); + } + }, ac); + } + /* + * return icon description at the specified index + */ + private boolean doAccessibleActions(final AccessibleContext ac, final String name) { + debugString("doAccessibleActions: action name = "+name); + if (ac == null || name == null) { + return false; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + AccessibleAction aa = ac.getAccessibleAction(); + if (aa == null) { + return false; + } + int index = -1; + int numActions = aa.getAccessibleActionCount(); + for (int i = 0; i < numActions; i++) { + String actionName = aa.getAccessibleActionDescription(i); + if (name.equals(actionName)) { + index = i; + break; + } + } + if (index == -1) { + return false; + } + boolean retval = aa.doAccessibleAction(index); + return retval; + } + }, ac); + } + + /* ===== AT utility methods ===== */ + + /** + * Sets the contents of an AccessibleContext that + * implements AccessibleEditableText with the + * specified text string. + * Returns whether successful. + */ + private boolean setTextContents(final AccessibleContext ac, final String text) { + debugString("setTextContents: ac = "+ac+"; text = "+text); + + if (! (ac instanceof AccessibleEditableText)) { + debugString(" ac not instanceof AccessibleEditableText: "+ac); + return false; + } + if (text == null) { + debugString(" text is null"); + return false; + } + + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + // check whether the text field is editable + AccessibleStateSet ass = ac.getAccessibleStateSet(); + if (!ass.contains(AccessibleState.ENABLED)) { + return false; + } + ((AccessibleEditableText) ac).setTextContents(text); + return true; + } + }, ac); + } + + /** + * Returns the Accessible Context of an Internal Frame object that is + * the ancestor of a given object. If the object is an Internal Frame + * object or an Internal Frame ancestor object was found, returns the + * object's AccessibleContext. + * If there is no ancestor object that has an Accessible Role of + * Internal Frame, returns (AccessibleContext)0. + */ + private AccessibleContext getInternalFrame (AccessibleContext ac) { + return getParentWithRole(ac, AccessibleRole.INTERNAL_FRAME.toString()); + } + + /** + * Returns the Accessible Context for the top level object in + * a Java Window. This is same Accessible Context that is obtained + * from GetAccessibleContextFromHWND for that window. Returns + * (AccessibleContext)0 on error. + */ + private AccessibleContext getTopLevelObject (final AccessibleContext ac) { + debugString("getTopLevelObject; ac = "+ac); + if (ac == null) { + return null; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + if (ac.getAccessibleRole() == AccessibleRole.DIALOG) { + // return the dialog, not the parent window + return ac; + } + + Accessible parent = ac.getAccessibleParent(); + if (parent == null) { + return ac; + } + Accessible tmp = parent; + while (tmp != null && tmp.getAccessibleContext() != null) { + AccessibleContext ac2 = tmp.getAccessibleContext(); + if (ac2 != null && ac2.getAccessibleRole() == AccessibleRole.DIALOG) { + // return the dialog, not the parent window + return ac2; + } + parent = tmp; + tmp = parent.getAccessibleContext().getAccessibleParent(); + } + return parent.getAccessibleContext(); + } + }, ac); + } + + /** + * Returns the parent AccessibleContext that has the specified AccessibleRole. + * Returns null on error or if the AccessibleContext does not exist. + */ + private AccessibleContext getParentWithRole (final AccessibleContext ac, + final String roleName) { + debugString("getParentWithRole; ac = "+ac); + debugString("role = "+roleName); + if (ac == null || roleName == null) { + return null; + } + + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + AccessibleRole role = AccessBridge.this.accessibleRoleMap.get(roleName); + if (role == null) { + return ac; + } + + Accessible parent = ac.getAccessibleParent(); + if (parent == null && ac.getAccessibleRole() == role) { + return ac; + } + + Accessible tmp = parent; + AccessibleContext tmp_ac = null; + + while (tmp != null && (tmp_ac = tmp.getAccessibleContext()) != null) { + AccessibleRole ar = tmp_ac.getAccessibleRole(); + if (ar == role) { + // found + return tmp_ac; + } + parent = tmp; + tmp = parent.getAccessibleContext().getAccessibleParent(); + } + // not found + return null; + } + }, ac); + } + + /** + * Returns the parent AccessibleContext that has the specified AccessibleRole. + * Otherwise, returns the top level object for the Java Window. + * Returns (AccessibleContext)0 on error. + */ + private AccessibleContext getParentWithRoleElseRoot (AccessibleContext ac, + String roleName) { + AccessibleContext retval = getParentWithRole(ac, roleName); + if (retval == null) { + retval = getTopLevelObject(ac); + } + return retval; + } + + /** + * Returns how deep in the object hierarchy a given object is. + * The top most object in the object hierarchy has an object depth of 0. + * Returns -1 on error. + */ + private int getObjectDepth(final AccessibleContext ac) { + debugString("getObjectDepth: ac = "+ac); + + if (ac == null) { + return -1; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + int count = 0; + Accessible parent = ac.getAccessibleParent(); + if (parent == null) { + return count; + } + Accessible tmp = parent; + while (tmp != null && tmp.getAccessibleContext() != null) { + parent = tmp; + tmp = parent.getAccessibleContext().getAccessibleParent(); + count++; + } + return count; + } + }, ac); + } + + /** + * Returns the Accessible Context of the current ActiveDescendent of an object. + * Returns (AccessibleContext)0 on error. + */ + private AccessibleContext getActiveDescendent (final AccessibleContext ac) { + debugString("getActiveDescendent: ac = "+ac); + if (ac == null) { + return null; + } + // workaround for JTree bug where the only possible active + // descendent is the JTree root + final Accessible parent = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Accessible call() throws Exception { + return ac.getAccessibleParent(); + } + }, ac); + + if (parent != null) { + Accessible child = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Accessible call() throws Exception { + int indexInParent = ac.getAccessibleIndexInParent(); + return parent.getAccessibleContext().getAccessibleChild(indexInParent); + } + }, ac); + + if (child instanceof JTree) { + // return the selected node + final JTree tree = (JTree)child; + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + return new AccessibleJTreeNode(tree, + tree.getSelectionPath(), + null); + } + }, child); + } + } + + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + AccessibleSelection as = ac.getAccessibleSelection(); + if (as == null) { + return null; + } + // assume single selection + if (as.getAccessibleSelectionCount() != 1) { + return null; + } + Accessible a = as.getAccessibleSelection(0); + if (a == null) { + return null; + } + return a.getAccessibleContext(); + } + }, ac); + } + + + /** + * Additional methods for Teton + */ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. + * Returns whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + private String getJAWSAccessibleName(final AccessibleContext ac) { + debugString("getJAWSAccessibleName"); + if (ac == null) { + return null; + } + // placeholder + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return ac.getAccessibleName(); + } + }, ac); + } + + /** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ + private boolean requestFocus(final AccessibleContext ac) { + debugString("requestFocus"); + if (ac == null) { + return false; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + AccessibleComponent acomp = ac.getAccessibleComponent(); + if (acomp == null) { + return false; + } + acomp.requestFocus(); + return ac.getAccessibleStateSet().contains(AccessibleState.FOCUSED); + } + }, ac); + } + + /** + * Selects text between two indices. Selection includes the + * text at the start index and the text at the end index. Returns + * whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ + private boolean selectTextRange(final AccessibleContext ac, final int startIndex, final int endIndex) { + debugString("selectTextRange: start = "+startIndex+"; end = "+endIndex); + if (ac == null) { + return false; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (!(at instanceof AccessibleEditableText)) { + return false; + } + ((AccessibleEditableText) at).selectText(startIndex, endIndex); + + boolean result = at.getSelectionStart() == startIndex && + at.getSelectionEnd() == endIndex; + return result; + } + }, ac); + } + + /** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ + private boolean setCaretPosition(final AccessibleContext ac, final int position) { + debugString("setCaretPosition: position = "+position); + if (ac == null) { + return false; + } + return InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + AccessibleText at = ac.getAccessibleText(); + if (!(at instanceof AccessibleEditableText)) { + return false; + } + ((AccessibleEditableText) at).selectText(position, position); + return at.getCaretPosition() == position; + } + }, ac); + } + + /** + * Gets the number of visible children of an AccessibleContext. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + private int _visibleChildrenCount; + private AccessibleContext _visibleChild; + private int _currentVisibleIndex; + private boolean _foundVisibleChild; + + private int getVisibleChildrenCount(AccessibleContext ac) { + debugString("getVisibleChildrenCount"); + if (ac == null) { + return -1; + } + _visibleChildrenCount = 0; + _getVisibleChildrenCount(ac); + debugString(" _visibleChildrenCount = "+_visibleChildrenCount); + return _visibleChildrenCount; + } + + /* + * Recursively descends AccessibleContext and gets the number + * of visible children + */ + private void _getVisibleChildrenCount(final AccessibleContext ac) { + if (ac == null) + return; + int numChildren = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return ac.getAccessibleChildrenCount(); + } + }, ac); + for (int i = 0; i < numChildren; i++) { + final int idx = i; + final AccessibleContext ac2 = InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + Accessible a = ac.getAccessibleChild(idx); + if (a != null) + return a.getAccessibleContext(); + else + return null; + } + }, ac); + if ( ac2 == null || + (!InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING); + } + }, ac)) + ) { + continue; + } + _visibleChildrenCount++; + + if (InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return ac2.getAccessibleChildrenCount(); + } + }, ac) > 0 ) { + _getVisibleChildrenCount(ac2); + } + } + } + + /** + * Gets the visible child of an AccessibleContext at the + * specified index + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + private AccessibleContext getVisibleChild(AccessibleContext ac, int index) { + debugString("getVisibleChild: index = "+index); + if (ac == null) { + return null; + } + _visibleChild = null; + _currentVisibleIndex = 0; + _foundVisibleChild = false; + _getVisibleChild(ac, index); + + if (_visibleChild != null) { + debugString( " getVisibleChild: found child = " + + InvocationUtils.invokeAndWait(new Callable() { + @Override + public String call() throws Exception { + return AccessBridge.this._visibleChild.getAccessibleName(); + } + }, ac) ); + } + return _visibleChild; + } + + /* + * Recursively searchs AccessibleContext and finds the visible component + * at the specified index + */ + private void _getVisibleChild(final AccessibleContext ac, final int index) { + if (_visibleChild != null) { + return; + } + + int numChildren = InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return ac.getAccessibleChildrenCount(); + } + }, ac); + for (int i = 0; i < numChildren; i++) { + final int idx=i; + final AccessibleContext ac2=InvocationUtils.invokeAndWait(new Callable() { + @Override + public AccessibleContext call() throws Exception { + Accessible a = ac.getAccessibleChild(idx); + if (a == null) + return null; + else + return a.getAccessibleContext(); + } + }, ac); + if (ac2 == null || + (!InvocationUtils.invokeAndWait(new Callable() { + @Override + public Boolean call() throws Exception { + return ac2.getAccessibleStateSet().contains(AccessibleState.SHOWING); + } + }, ac))) { + continue; + } + if (!_foundVisibleChild && _currentVisibleIndex == index) { + _visibleChild = ac2; + _foundVisibleChild = true; + return; + } + _currentVisibleIndex++; + + if ( InvocationUtils.invokeAndWait(new Callable() { + @Override + public Integer call() throws Exception { + return ac2.getAccessibleChildrenCount(); + } + }, ac) > 0 ) { + _getVisibleChild(ac2, index); + } + } + } + + + /* ===== Java object memory management code ===== */ + + /** + * Class to track object references to ensure the + * Java VM doesn't garbage collect them + */ + private class ObjectReferences { + + private class Reference { + private int value; + + Reference(int i) { + value = i; + } + + public String toString() { + return ("refCount: " + value); + } + } + + /** + * table object references, to keep 'em from being garbage collected + */ + private ConcurrentHashMap refs; + + /** + * Constructor + */ + ObjectReferences() { + refs = new ConcurrentHashMap<>(4); + } + + /** + * Debugging: dump the contents of ObjectReferences' refs Hashtable + */ + String dump() { + return refs.toString(); + } + + /** + * Increment ref count; set to 1 if we have no references for it + */ + void increment(Object o) { + if (o == null){ + debugString("ObjectReferences::increment - Passed in object is null"); + return; + } + + if (refs.containsKey(o)) { + (refs.get(o)).value++; + } else { + refs.put(o, new Reference(1)); + } + } + + /** + * Decrement ref count; remove if count drops to 0 + */ + void decrement(Object o) { + Reference aRef = refs.get(o); + if (aRef != null) { + aRef.value--; + if (aRef.value == 0) { + refs.remove(o); + } else if (aRef.value < 0) { + debugString("ERROR: decrementing reference count below 0"); + } + } else { + debugString("ERROR: object to decrement not in ObjectReferences table"); + } + } + + } + + /* ===== event handling code ===== */ + + /** + * native method for handling property change events + */ + private native void propertyCaretChange(PropertyChangeEvent e, + AccessibleContext src, + int oldValue, int newValue); + private native void propertyDescriptionChange(PropertyChangeEvent e, + AccessibleContext src, + String oldValue, String newValue); + private native void propertyNameChange(PropertyChangeEvent e, + AccessibleContext src, + String oldValue, String newValue); + private native void propertySelectionChange(PropertyChangeEvent e, + AccessibleContext src); + private native void propertyStateChange(PropertyChangeEvent e, + AccessibleContext src, + String oldValue, String newValue); + private native void propertyTextChange(PropertyChangeEvent e, + AccessibleContext src); + private native void propertyValueChange(PropertyChangeEvent e, + AccessibleContext src, + String oldValue, String newValue); + private native void propertyVisibleDataChange(PropertyChangeEvent e, + AccessibleContext src); + private native void propertyChildChange(PropertyChangeEvent e, + AccessibleContext src, + AccessibleContext oldValue, + AccessibleContext newValue); + private native void propertyActiveDescendentChange(PropertyChangeEvent e, + AccessibleContext src, + AccessibleContext oldValue, + AccessibleContext newValue); + + private native void javaShutdown(); + + /** + * native methods for handling focus events + */ + private native void focusGained(FocusEvent e, AccessibleContext src); + private native void focusLost(FocusEvent e, AccessibleContext src); + + /** + * native method for handling caret events + */ + private native void caretUpdate(CaretEvent e, AccessibleContext src); + + /** + * native methods for handling mouse events + */ + private native void mouseClicked(MouseEvent e, AccessibleContext src); + private native void mouseEntered(MouseEvent e, AccessibleContext src); + private native void mouseExited(MouseEvent e, AccessibleContext src); + private native void mousePressed(MouseEvent e, AccessibleContext src); + private native void mouseReleased(MouseEvent e, AccessibleContext src); + + /** + * native methods for handling menu & popupMenu events + */ + private native void menuCanceled(MenuEvent e, AccessibleContext src); + private native void menuDeselected(MenuEvent e, AccessibleContext src); + private native void menuSelected(MenuEvent e, AccessibleContext src); + private native void popupMenuCanceled(PopupMenuEvent e, AccessibleContext src); + private native void popupMenuWillBecomeInvisible(PopupMenuEvent e, + AccessibleContext src); + private native void popupMenuWillBecomeVisible(PopupMenuEvent e, + AccessibleContext src); + + /* ===== event definitions ===== */ + + private static final long PROPERTY_CHANGE_EVENTS = 1; + private static final long FOCUS_GAINED_EVENTS = 2; + private static final long FOCUS_LOST_EVENTS = 4; + private static final long FOCUS_EVENTS = (FOCUS_GAINED_EVENTS | FOCUS_LOST_EVENTS); + + private static final long CARET_UPATE_EVENTS = 8; + private static final long CARET_EVENTS = CARET_UPATE_EVENTS; + + private static final long MOUSE_CLICKED_EVENTS = 16; + private static final long MOUSE_ENTERED_EVENTS = 32; + private static final long MOUSE_EXITED_EVENTS = 64; + private static final long MOUSE_PRESSED_EVENTS = 128; + private static final long MOUSE_RELEASED_EVENTS = 256; + private static final long MOUSE_EVENTS = (MOUSE_CLICKED_EVENTS | MOUSE_ENTERED_EVENTS | + MOUSE_EXITED_EVENTS | MOUSE_PRESSED_EVENTS | + MOUSE_RELEASED_EVENTS); + + private static final long MENU_CANCELED_EVENTS = 512; + private static final long MENU_DESELECTED_EVENTS = 1024; + private static final long MENU_SELECTED_EVENTS = 2048; + private static final long MENU_EVENTS = (MENU_CANCELED_EVENTS | MENU_DESELECTED_EVENTS | + MENU_SELECTED_EVENTS); + + private static final long POPUPMENU_CANCELED_EVENTS = 4096; + private static final long POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS = 8192; + private static final long POPUPMENU_WILL_BECOME_VISIBLE_EVENTS = 16384; + private static final long POPUPMENU_EVENTS = (POPUPMENU_CANCELED_EVENTS | + POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS | + POPUPMENU_WILL_BECOME_VISIBLE_EVENTS); + + /* These use their own numbering scheme, to ensure sufficient expansion room */ + private static final long PROPERTY_NAME_CHANGE_EVENTS = 1; + private static final long PROPERTY_DESCRIPTION_CHANGE_EVENTS = 2; + private static final long PROPERTY_STATE_CHANGE_EVENTS = 4; + private static final long PROPERTY_VALUE_CHANGE_EVENTS = 8; + private static final long PROPERTY_SELECTION_CHANGE_EVENTS = 16; + private static final long PROPERTY_TEXT_CHANGE_EVENTS = 32; + private static final long PROPERTY_CARET_CHANGE_EVENTS = 64; + private static final long PROPERTY_VISIBLEDATA_CHANGE_EVENTS = 128; + private static final long PROPERTY_CHILD_CHANGE_EVENTS = 256; + private static final long PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS = 512; + + + private static final long PROPERTY_EVENTS = (PROPERTY_NAME_CHANGE_EVENTS | + PROPERTY_DESCRIPTION_CHANGE_EVENTS | + PROPERTY_STATE_CHANGE_EVENTS | + PROPERTY_VALUE_CHANGE_EVENTS | + PROPERTY_SELECTION_CHANGE_EVENTS | + PROPERTY_TEXT_CHANGE_EVENTS | + PROPERTY_CARET_CHANGE_EVENTS | + PROPERTY_VISIBLEDATA_CHANGE_EVENTS | + PROPERTY_CHILD_CHANGE_EVENTS | + PROPERTY_ACTIVEDESCENDENT_CHANGE_EVENTS); + + /** + * The EventHandler class listens for Java events and + * forwards them to the AT + */ + private class EventHandler implements PropertyChangeListener, + FocusListener, CaretListener, + MenuListener, PopupMenuListener, + MouseListener, WindowListener, + ChangeListener { + + private AccessBridge accessBridge; + private long javaEventMask = 0; + private long accessibilityEventMask = 0; + + EventHandler(AccessBridge bridge) { + accessBridge = bridge; + + // Register to receive WINDOW_OPENED and WINDOW_CLOSED + // events. Add the event source as a native window + // handler is it implements NativeWindowHandler. + // SwingEventMonitor.addWindowListener(this); + } + + // --------- Event Notification Registration methods + + /** + * Invoked the first time a window is made visible. + */ + public void windowOpened(WindowEvent e) { + // If the window is a NativeWindowHandler, add it. + Object o = null; + if (e != null) + o = e.getSource(); + if (o instanceof NativeWindowHandler) { + addNativeWindowHandler((NativeWindowHandler)o); + } + } + + /** + * Invoked when the user attempts to close the window + * from the window's system menu. If the program does not + * explicitly hide or dispose the window while processing + * this event, the window close operation will be canceled. + */ + public void windowClosing(WindowEvent e) {} + + /** + * Invoked when a window has been closed as the result + * of calling dispose on the window. + */ + public void windowClosed(WindowEvent e) { + // If the window is a NativeWindowHandler, remove it. + Object o = null; + if (e != null) + o = e.getSource(); + if (o instanceof NativeWindowHandler) { + removeNativeWindowHandler((NativeWindowHandler)o); + } + } + + /** + * Invoked when a window is changed from a normal to a + * minimized state. For many platforms, a minimized window + * is displayed as the icon specified in the window's + * iconImage property. + * @see java.awt.Frame#setIconImage + */ + public void windowIconified(WindowEvent e) {} + + /** + * Invoked when a window is changed from a minimized + * to a normal state. + */ + public void windowDeiconified(WindowEvent e) {} + + /** + * Invoked when the Window is set to be the active Window. Only a Frame or + * a Dialog can be the active Window. The native windowing system may + * denote the active Window or its children with special decorations, such + * as a highlighted title bar. The active Window is always either the + * focused Window, or the first Frame or Dialog that is an owner of the + * focused Window. + */ + public void windowActivated(WindowEvent e) {} + + /** + * Invoked when a Window is no longer the active Window. Only a Frame or a + * Dialog can be the active Window. The native windowing system may denote + * the active Window or its children with special decorations, such as a + * highlighted title bar. The active Window is always either the focused + * Window, or the first Frame or Dialog that is an owner of the focused + * Window. + */ + public void windowDeactivated(WindowEvent e) {} + + /** + * Turn on event monitoring for the event type passed in + * If necessary, add the appropriate event listener (if + * no other event of that type is being listened for) + */ + void addJavaEventNotification(long type) { + long newEventMask = javaEventMask | type; + /* + if ( ((javaEventMask & PROPERTY_EVENTS) == 0) && + ((newEventMask & PROPERTY_EVENTS) != 0) ) { + AccessibilityEventMonitor.addPropertyChangeListener(this); + } + */ + if ( ((javaEventMask & FOCUS_EVENTS) == 0) && + ((newEventMask & FOCUS_EVENTS) != 0) ) { + SwingEventMonitor.addFocusListener(this); + } + if ( ((javaEventMask & CARET_EVENTS) == 0) && + ((newEventMask & CARET_EVENTS) != 0) ) { + SwingEventMonitor.addCaretListener(this); + } + if ( ((javaEventMask & MOUSE_EVENTS) == 0) && + ((newEventMask & MOUSE_EVENTS) != 0) ) { + SwingEventMonitor.addMouseListener(this); + } + if ( ((javaEventMask & MENU_EVENTS) == 0) && + ((newEventMask & MENU_EVENTS) != 0) ) { + SwingEventMonitor.addMenuListener(this); + SwingEventMonitor.addPopupMenuListener(this); + } + if ( ((javaEventMask & POPUPMENU_EVENTS) == 0) && + ((newEventMask & POPUPMENU_EVENTS) != 0) ) { + SwingEventMonitor.addPopupMenuListener(this); + } + + javaEventMask = newEventMask; + } + + /** + * Turn off event monitoring for the event type passed in + * If necessary, remove the appropriate event listener (if + * no other event of that type is being listened for) + */ + void removeJavaEventNotification(long type) { + long newEventMask = javaEventMask & (~type); + /* + if ( ((javaEventMask & PROPERTY_EVENTS) != 0) && + ((newEventMask & PROPERTY_EVENTS) == 0) ) { + AccessibilityEventMonitor.removePropertyChangeListener(this); + } + */ + if (((javaEventMask & FOCUS_EVENTS) != 0) && + ((newEventMask & FOCUS_EVENTS) == 0)) { + SwingEventMonitor.removeFocusListener(this); + } + if (((javaEventMask & CARET_EVENTS) != 0) && + ((newEventMask & CARET_EVENTS) == 0)) { + SwingEventMonitor.removeCaretListener(this); + } + if (((javaEventMask & MOUSE_EVENTS) == 0) && + ((newEventMask & MOUSE_EVENTS) != 0)) { + SwingEventMonitor.removeMouseListener(this); + } + if (((javaEventMask & MENU_EVENTS) == 0) && + ((newEventMask & MENU_EVENTS) != 0)) { + SwingEventMonitor.removeMenuListener(this); + } + if (((javaEventMask & POPUPMENU_EVENTS) == 0) && + ((newEventMask & POPUPMENU_EVENTS) != 0)) { + SwingEventMonitor.removePopupMenuListener(this); + } + + javaEventMask = newEventMask; + } + + /** + * Turn on event monitoring for the event type passed in + * If necessary, add the appropriate event listener (if + * no other event of that type is being listened for) + */ + void addAccessibilityEventNotification(long type) { + long newEventMask = accessibilityEventMask | type; + if ( ((accessibilityEventMask & PROPERTY_EVENTS) == 0) && + ((newEventMask & PROPERTY_EVENTS) != 0) ) { + AccessibilityEventMonitor.addPropertyChangeListener(this); + } + accessibilityEventMask = newEventMask; + } + + /** + * Turn off event monitoring for the event type passed in + * If necessary, remove the appropriate event listener (if + * no other event of that type is being listened for) + */ + void removeAccessibilityEventNotification(long type) { + long newEventMask = accessibilityEventMask & (~type); + if ( ((accessibilityEventMask & PROPERTY_EVENTS) != 0) && + ((newEventMask & PROPERTY_EVENTS) == 0) ) { + AccessibilityEventMonitor.removePropertyChangeListener(this); + } + accessibilityEventMask = newEventMask; + } + + /** + * ------- property change event glue + */ + // This is invoked on the EDT , as + public void propertyChange(PropertyChangeEvent e) { + + accessBridge.debugString("propertyChange(" + e.toString() + ") called"); + + if (e != null && (accessibilityEventMask & PROPERTY_EVENTS) != 0) { + Object o = e.getSource(); + AccessibleContext ac; + + if (o instanceof AccessibleContext) { + ac = (AccessibleContext) o; + } else { + Accessible a = Translator.getAccessible(e.getSource()); + if (a == null) + return; + else + ac = a.getAccessibleContext(); + } + if (ac != null) { + InvocationUtils.registerAccessibleContext(ac, AppContext.getAppContext()); + + accessBridge.debugString("AccessibleContext: " + ac); + String propertyName = e.getPropertyName(); + + if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CARET_PROPERTY) == 0) { + int oldValue = 0; + int newValue = 0; + + if (e.getOldValue() instanceof Integer) { + oldValue = ((Integer) e.getOldValue()).intValue(); + } + if (e.getNewValue() instanceof Integer) { + newValue = ((Integer) e.getNewValue()).intValue(); + } + accessBridge.debugString(" - about to call propertyCaretChange()"); + accessBridge.debugString(" old value: " + oldValue + "new value: " + newValue); + accessBridge.propertyCaretChange(e, ac, oldValue, newValue); + + } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY) == 0) { + String oldValue = null; + String newValue = null; + + if (e.getOldValue() != null) { + oldValue = e.getOldValue().toString(); + } + if (e.getNewValue() != null) { + newValue = e.getNewValue().toString(); + } + accessBridge.debugString(" - about to call propertyDescriptionChange()"); + accessBridge.debugString(" old value: " + oldValue + "new value: " + newValue); + accessBridge.propertyDescriptionChange(e, ac, oldValue, newValue); + + } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_NAME_PROPERTY) == 0) { + String oldValue = null; + String newValue = null; + + if (e.getOldValue() != null) { + oldValue = e.getOldValue().toString(); + } + if (e.getNewValue() != null) { + newValue = e.getNewValue().toString(); + } + accessBridge.debugString(" - about to call propertyNameChange()"); + accessBridge.debugString(" old value: " + oldValue + " new value: " + newValue); + accessBridge.propertyNameChange(e, ac, oldValue, newValue); + + } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_SELECTION_PROPERTY) == 0) { + accessBridge.debugString(" - about to call propertySelectionChange() " + ac + " " + Thread.currentThread() + " " + e.getSource()); + + accessBridge.propertySelectionChange(e, ac); + + } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_STATE_PROPERTY) == 0) { + String oldValue = null; + String newValue = null; + + // Localization fix requested by Oliver for EA-1 + if (e.getOldValue() != null) { + AccessibleState oldState = (AccessibleState) e.getOldValue(); + oldValue = oldState.toDisplayString(Locale.US); + } + if (e.getNewValue() != null) { + AccessibleState newState = (AccessibleState) e.getNewValue(); + newValue = newState.toDisplayString(Locale.US); + } + + accessBridge.debugString(" - about to call propertyStateChange()"); + accessBridge.propertyStateChange(e, ac, oldValue, newValue); + + } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_TEXT_PROPERTY) == 0) { + accessBridge.debugString(" - about to call propertyTextChange()"); + accessBridge.propertyTextChange(e, ac); + + } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VALUE_PROPERTY) == 0) { // strings 'cause of floating point, etc. + String oldValue = null; + String newValue = null; + + if (e.getOldValue() != null) { + oldValue = e.getOldValue().toString(); + } + if (e.getNewValue() != null) { + newValue = e.getNewValue().toString(); + } + accessBridge.debugString(" - about to call propertyDescriptionChange()"); + accessBridge.propertyValueChange(e, ac, oldValue, newValue); + + } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_VISIBLE_DATA_PROPERTY) == 0) { + accessBridge.propertyVisibleDataChange(e, ac); + + } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_CHILD_PROPERTY) == 0) { + AccessibleContext oldAC = null; + AccessibleContext newAC = null; + Accessible a; + + if (e.getOldValue() instanceof AccessibleContext) { + oldAC = (AccessibleContext) e.getOldValue(); + InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext()); + } + if (e.getNewValue() instanceof AccessibleContext) { + newAC = (AccessibleContext) e.getNewValue(); + InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext()); + } + accessBridge.debugString(" - about to call propertyChildChange()"); + accessBridge.debugString(" old AC: " + oldAC + "new AC: " + newAC); + accessBridge.propertyChildChange(e, ac, oldAC, newAC); + + } else if (propertyName.compareTo(AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0) { + handleActiveDescendentEvent(e, ac); + } + } + } + } + + /* + * Handle an ActiveDescendent PropertyChangeEvent. This + * method works around a JTree bug where ActiveDescendent + * PropertyChangeEvents have the wrong parent. + */ + private AccessibleContext prevAC = null; // previous AccessibleContext + + private void handleActiveDescendentEvent(PropertyChangeEvent e, + AccessibleContext ac) { + if (e == null || ac == null) + return; + AccessibleContext oldAC = null; + AccessibleContext newAC = null; + Accessible a; + + // get the old active descendent + if (e.getOldValue() instanceof Accessible) { + oldAC = ((Accessible) e.getOldValue()).getAccessibleContext(); + } else if (e.getOldValue() instanceof Component) { + a = Translator.getAccessible(e.getOldValue()); + if (a != null) { + oldAC = a.getAccessibleContext(); + } + } + if (oldAC != null) { + Accessible parent = oldAC.getAccessibleParent(); + if (parent instanceof JTree) { + // use the previous AccessibleJTreeNode + oldAC = prevAC; + } + } + + // get the new active descendent + if (e.getNewValue() instanceof Accessible) { + newAC = ((Accessible) e.getNewValue()).getAccessibleContext(); + } else if (e.getNewValue() instanceof Component) { + a = Translator.getAccessible(e.getNewValue()); + if (a != null) { + newAC = a.getAccessibleContext(); + } + } + if (newAC != null) { + Accessible parent = newAC.getAccessibleParent(); + if (parent instanceof JTree) { + // use a new AccessibleJTreeNode with the right parent + JTree tree = (JTree)parent; + newAC = new AccessibleJTreeNode(tree, + tree.getSelectionPath(), + null); + } + } + prevAC = newAC; + + accessBridge.debugString(" - about to call propertyActiveDescendentChange()"); + accessBridge.debugString(" AC: " + ac); + accessBridge.debugString(" old AC: " + oldAC + "new AC: " + newAC); + + InvocationUtils.registerAccessibleContext(oldAC, AppContext.getAppContext()); + InvocationUtils.registerAccessibleContext(newAC, AppContext.getAppContext()); + accessBridge.propertyActiveDescendentChange(e, ac, oldAC, newAC); + } + + /** + * ------- focus event glue + */ + private boolean stateChangeListenerAdded = false; + + public void focusGained(FocusEvent e) { + processFocusGained(); + } + + public void stateChanged(ChangeEvent e) { + processFocusGained(); + } + + private void processFocusGained() { + Component focusOwner = KeyboardFocusManager. + getCurrentKeyboardFocusManager().getFocusOwner(); + if (focusOwner == null) { + return; + } + + // Only menus and popup selections are handled by the JRootPane. + if (focusOwner instanceof JRootPane) { + MenuElement [] path = + MenuSelectionManager.defaultManager().getSelectedPath(); + if (path.length > 1) { + Component penult = path[path.length-2].getComponent(); + Component last = path[path.length-1].getComponent(); + + if (last instanceof JPopupMenu) { + // This is a popup with nothing in the popup + // selected. The menu itself is selected. + FocusEvent e = new FocusEvent(penult, FocusEvent.FOCUS_GAINED); + AccessibleContext context = penult.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, SunToolkit.targetToAppContext(penult)); + accessBridge.focusGained(e, context); + } else if (penult instanceof JPopupMenu) { + // This is a popup with an item selected + FocusEvent e = + new FocusEvent(last, FocusEvent.FOCUS_GAINED); + accessBridge.debugString(" - about to call focusGained()"); + AccessibleContext focusedAC = last.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(last)); + accessBridge.debugString(" AC: " + focusedAC); + accessBridge.focusGained(e, focusedAC); + } + } + } else { + // The focus owner has the selection. + if (focusOwner instanceof Accessible) { + FocusEvent e = new FocusEvent(focusOwner, + FocusEvent.FOCUS_GAINED); + accessBridge.debugString(" - about to call focusGained()"); + AccessibleContext focusedAC = focusOwner.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(focusedAC, SunToolkit.targetToAppContext(focusOwner)); + accessBridge.debugString(" AC: " + focusedAC); + accessBridge.focusGained(e, focusedAC); + } + } + } + + public void focusLost(FocusEvent e) { + if (e != null && (javaEventMask & FOCUS_LOST_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + accessBridge.debugString(" - about to call focusLost()"); + accessBridge.debugString(" AC: " + a.getAccessibleContext()); + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.focusLost(e, context); + } + } + } + + /** + * ------- caret event glue + */ + public void caretUpdate(CaretEvent e) { + if (e != null && (javaEventMask & CARET_UPATE_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.caretUpdate(e, context); + } + } + } + + /** + * ------- mouse event glue + */ + + public void mouseClicked(MouseEvent e) { + if (e != null && (javaEventMask & MOUSE_CLICKED_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.mouseClicked(e, context); + } + } + } + + public void mouseEntered(MouseEvent e) { + if (e != null && (javaEventMask & MOUSE_ENTERED_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.mouseEntered(e, context); + } + } + } + + public void mouseExited(MouseEvent e) { + if (e != null && (javaEventMask & MOUSE_EXITED_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.mouseExited(e, context); + } + } + } + + public void mousePressed(MouseEvent e) { + if (e != null && (javaEventMask & MOUSE_PRESSED_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.mousePressed(e, context); + } + } + } + + public void mouseReleased(MouseEvent e) { + if (e != null && (javaEventMask & MOUSE_RELEASED_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.mouseReleased(e, context); + } + } + } + + /** + * ------- menu event glue + */ + public void menuCanceled(MenuEvent e) { + if (e != null && (javaEventMask & MENU_CANCELED_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.menuCanceled(e, context); + } + } + } + + public void menuDeselected(MenuEvent e) { + if (e != null && (javaEventMask & MENU_DESELECTED_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.menuDeselected(e, context); + } + } + } + + public void menuSelected(MenuEvent e) { + if (e != null && (javaEventMask & MENU_SELECTED_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.menuSelected(e, context); + } + } + } + + public void popupMenuCanceled(PopupMenuEvent e) { + if (e != null && (javaEventMask & POPUPMENU_CANCELED_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.popupMenuCanceled(e, context); + } + } + } + + public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { + if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_INVISIBLE_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.popupMenuWillBecomeInvisible(e, context); + } + } + } + + public void popupMenuWillBecomeVisible(PopupMenuEvent e) { + if (e != null && (javaEventMask & POPUPMENU_WILL_BECOME_VISIBLE_EVENTS) != 0) { + Accessible a = Translator.getAccessible(e.getSource()); + if (a != null) { + AccessibleContext context = a.getAccessibleContext(); + InvocationUtils.registerAccessibleContext(context, AppContext.getAppContext()); + accessBridge.popupMenuWillBecomeVisible(e, context); + } + } + } + + } // End of EventHandler Class + + // --------- Event Notification Registration methods + + /** + * Wrapper method around eventHandler.addJavaEventNotification() + */ + private void addJavaEventNotification(final long type) { + EventQueue.invokeLater(new Runnable() { + public void run(){ + eventHandler.addJavaEventNotification(type); + } + }); + } + + /** + * Wrapper method around eventHandler.removeJavaEventNotification() + */ + private void removeJavaEventNotification(final long type) { + EventQueue.invokeLater(new Runnable() { + public void run(){ + eventHandler.removeJavaEventNotification(type); + } + }); + } + + + /** + * Wrapper method around eventHandler.addAccessibilityEventNotification() + */ + private void addAccessibilityEventNotification(final long type) { + EventQueue.invokeLater(new Runnable() { + public void run(){ + eventHandler.addAccessibilityEventNotification(type); + } + }); + } + + /** + * Wrapper method around eventHandler.removeAccessibilityEventNotification() + */ + private void removeAccessibilityEventNotification(final long type) { + EventQueue.invokeLater(new Runnable() { + public void run(){ + eventHandler.removeAccessibilityEventNotification(type); + } + }); + } + + /** + ****************************************************** + * All AccessibleRoles + * + * We shouldn't have to do this since it requires us + * to synchronize the allAccessibleRoles array when + * the AccessibleRoles class interface changes. However, + * there is no Accessibility API method to get all + * AccessibleRoles + ****************************************************** + */ + private AccessibleRole [] allAccessibleRoles = { + /** + * Object is used to alert the user about something. + */ + AccessibleRole.ALERT, + + /** + * The header for a column of data. + */ + AccessibleRole.COLUMN_HEADER, + + /** + * Object that can be drawn into and is used to trap + * events. + * @see #FRAME + * @see #GLASS_PANE + * @see #LAYERED_PANE + */ + AccessibleRole.CANVAS, + + /** + * A list of choices the user can select from. Also optionally + * allows the user to enter a choice of their own. + */ + AccessibleRole.COMBO_BOX, + + /** + * An iconified internal frame in a DESKTOP_PANE. + * @see #DESKTOP_PANE + * @see #INTERNAL_FRAME + */ + AccessibleRole.DESKTOP_ICON, + + /** + * A frame-like object that is clipped by a desktop pane. The + * desktop pane, internal frame, and desktop icon objects are + * often used to create multiple document interfaces within an + * application. + * @see #DESKTOP_ICON + * @see #DESKTOP_PANE + * @see #FRAME + */ + AccessibleRole.INTERNAL_FRAME, + + /** + * A pane that supports internal frames and + * iconified versions of those internal frames. + * @see #DESKTOP_ICON + * @see #INTERNAL_FRAME + */ + AccessibleRole.DESKTOP_PANE, + + /** + * A specialized pane whose primary use is inside a DIALOG + * @see #DIALOG + */ + AccessibleRole.OPTION_PANE, + + /** + * A top level window with no title or border. + * @see #FRAME + * @see #DIALOG + */ + AccessibleRole.WINDOW, + + /** + * A top level window with a title bar, border, menu bar, etc. It is + * often used as the primary window for an application. + * @see #DIALOG + * @see #CANVAS + * @see #WINDOW + */ + AccessibleRole.FRAME, + + /** + * A top level window with title bar and a border. A dialog is similar + * to a frame, but it has fewer properties and is often used as a + * secondary window for an application. + * @see #FRAME + * @see #WINDOW + */ + AccessibleRole.DIALOG, + + /** + * A specialized dialog that lets the user choose a color. + */ + AccessibleRole.COLOR_CHOOSER, + + + /** + * A pane that allows the user to navigate through + * and select the contents of a directory. May be used + * by a file chooser. + * @see #FILE_CHOOSER + */ + AccessibleRole.DIRECTORY_PANE, + + /** + * A specialized dialog that displays the files in the directory + * and lets the user select a file, browse a different directory, + * or specify a filename. May use the directory pane to show the + * contents of a directory. + * @see #DIRECTORY_PANE + */ + AccessibleRole.FILE_CHOOSER, + + /** + * An object that fills up space in a user interface. It is often + * used in interfaces to tweak the spacing between components, + * but serves no other purpose. + */ + AccessibleRole.FILLER, + + /** + * A hypertext anchor + */ + // AccessibleRole.HYPERLINK, + + /** + * A small fixed size picture, typically used to decorate components. + */ + AccessibleRole.ICON, + + /** + * An object used to present an icon or short string in an interface. + */ + AccessibleRole.LABEL, + + /** + * A specialized pane that has a glass pane and a layered pane as its + * children. + * @see #GLASS_PANE + * @see #LAYERED_PANE + */ + AccessibleRole.ROOT_PANE, + + /** + * A pane that is guaranteed to be painted on top + * of all panes beneath it. + * @see #ROOT_PANE + * @see #CANVAS + */ + AccessibleRole.GLASS_PANE, + + /** + * A specialized pane that allows its children to be drawn in layers, + * providing a form of stacking order. This is usually the pane that + * holds the menu bar as well as the pane that contains most of the + * visual components in a window. + * @see #GLASS_PANE + * @see #ROOT_PANE + */ + AccessibleRole.LAYERED_PANE, + + /** + * An object that presents a list of objects to the user and allows the + * user to select one or more of them. A list is usually contained + * within a scroll pane. + * @see #SCROLL_PANE + * @see #LIST_ITEM + */ + AccessibleRole.LIST, + + /** + * An object that presents an element in a list. A list is usually + * contained within a scroll pane. + * @see #SCROLL_PANE + * @see #LIST + */ + AccessibleRole.LIST_ITEM, + + /** + * An object usually drawn at the top of the primary dialog box of + * an application that contains a list of menus the user can choose + * from. For example, a menu bar might contain menus for "File," + * "Edit," and "Help." + * @see #MENU + * @see #POPUP_MENU + * @see #LAYERED_PANE + */ + AccessibleRole.MENU_BAR, + + /** + * A temporary window that is usually used to offer the user a + * list of choices, and then hides when the user selects one of + * those choices. + * @see #MENU + * @see #MENU_ITEM + */ + AccessibleRole.POPUP_MENU, + + /** + * An object usually found inside a menu bar that contains a list + * of actions the user can choose from. A menu can have any object + * as its children, but most often they are menu items, other menus, + * or rudimentary objects such as radio buttons, check boxes, or + * separators. For example, an application may have an "Edit" menu + * that contains menu items for "Cut" and "Paste." + * @see #MENU_BAR + * @see #MENU_ITEM + * @see #SEPARATOR + * @see #RADIO_BUTTON + * @see #CHECK_BOX + * @see #POPUP_MENU + */ + AccessibleRole.MENU, + + /** + * An object usually contained in a menu that presents an action + * the user can choose. For example, the "Cut" menu item in an + * "Edit" menu would be an action the user can select to cut the + * selected area of text in a document. + * @see #MENU_BAR + * @see #SEPARATOR + * @see #POPUP_MENU + */ + AccessibleRole.MENU_ITEM, + + /** + * An object usually contained in a menu to provide a visual + * and logical separation of the contents in a menu. For example, + * the "File" menu of an application might contain menu items for + * "Open," "Close," and "Exit," and will place a separator between + * "Close" and "Exit" menu items. + * @see #MENU + * @see #MENU_ITEM + */ + AccessibleRole.SEPARATOR, + + /** + * An object that presents a series of panels (or page tabs), one at a + * time, through some mechanism provided by the object. The most common + * mechanism is a list of tabs at the top of the panel. The children of + * a page tab list are all page tabs. + * @see #PAGE_TAB + */ + AccessibleRole.PAGE_TAB_LIST, + + /** + * An object that is a child of a page tab list. Its sole child is + * the panel that is to be presented to the user when the user + * selects the page tab from the list of tabs in the page tab list. + * @see #PAGE_TAB_LIST + */ + AccessibleRole.PAGE_TAB, + + /** + * A generic container that is often used to group objects. + */ + AccessibleRole.PANEL, + + /** + * An object used to indicate how much of a task has been completed. + */ + AccessibleRole.PROGRESS_BAR, + + /** + * A text object used for passwords, or other places where the + * text contents is not shown visibly to the user + */ + AccessibleRole.PASSWORD_TEXT, + + /** + * An object the user can manipulate to tell the application to do + * something. + * @see #CHECK_BOX + * @see #TOGGLE_BUTTON + * @see #RADIO_BUTTON + */ + AccessibleRole.PUSH_BUTTON, + + /** + * A specialized push button that can be checked or unchecked, but + * does not provide a separate indicator for the current state. + * @see #PUSH_BUTTON + * @see #CHECK_BOX + * @see #RADIO_BUTTON + */ + AccessibleRole.TOGGLE_BUTTON, + + /** + * A choice that can be checked or unchecked and provides a + * separate indicator for the current state. + * @see #PUSH_BUTTON + * @see #TOGGLE_BUTTON + * @see #RADIO_BUTTON + */ + AccessibleRole.CHECK_BOX, + + /** + * A specialized check box that will cause other radio buttons in the + * same group to become unchecked when this one is checked. + * @see #PUSH_BUTTON + * @see #TOGGLE_BUTTON + * @see #CHECK_BOX + */ + AccessibleRole.RADIO_BUTTON, + + /** + * The header for a row of data. + */ + AccessibleRole.ROW_HEADER, + + /** + * An object that allows a user to incrementally view a large amount + * of information. Its children can include scroll bars and a viewport. + * @see #SCROLL_BAR + * @see #VIEWPORT + */ + AccessibleRole.SCROLL_PANE, + + /** + * An object usually used to allow a user to incrementally view a + * large amount of data. Usually used only by a scroll pane. + * @see #SCROLL_PANE + */ + AccessibleRole.SCROLL_BAR, + + /** + * An object usually used in a scroll pane. It represents the portion + * of the entire data that the user can see. As the user manipulates + * the scroll bars, the contents of the viewport can change. + * @see #SCROLL_PANE + */ + AccessibleRole.VIEWPORT, + + /** + * An object that allows the user to select from a bounded range. For + * example, a slider might be used to select a number between 0 and 100. + */ + AccessibleRole.SLIDER, + + /** + * A specialized panel that presents two other panels at the same time. + * Between the two panels is a divider the user can manipulate to make + * one panel larger and the other panel smaller. + */ + AccessibleRole.SPLIT_PANE, + + /** + * An object used to present information in terms of rows and columns. + * An example might include a spreadsheet application. + */ + AccessibleRole.TABLE, + + /** + * An object that presents text to the user. The text is usually + * editable by the user as opposed to a label. + * @see #LABEL + */ + AccessibleRole.TEXT, + + /** + * An object used to present hierarchical information to the user. + * The individual nodes in the tree can be collapsed and expanded + * to provide selective disclosure of the tree's contents. + */ + AccessibleRole.TREE, + + /** + * A bar or palette usually composed of push buttons or toggle buttons. + * It is often used to provide the most frequently used functions for an + * application. + */ + AccessibleRole.TOOL_BAR, + + /** + * An object that provides information about another object. The + * accessibleDescription property of the tool tip is often displayed + * to the user in a small "help bubble" when the user causes the + * mouse to hover over the object associated with the tool tip. + */ + AccessibleRole.TOOL_TIP, + + /** + * An AWT component, but nothing else is known about it. + * @see #SWING_COMPONENT + * @see #UNKNOWN + */ + AccessibleRole.AWT_COMPONENT, + + /** + * A Swing component, but nothing else is known about it. + * @see #AWT_COMPONENT + * @see #UNKNOWN + */ + AccessibleRole.SWING_COMPONENT, + + /** + * The object contains some Accessible information, but its role is + * not known. + * @see #AWT_COMPONENT + * @see #SWING_COMPONENT + */ + AccessibleRole.UNKNOWN, + + // These roles are only available in JDK 1.4 + + /** + * A STATUS_BAR is an simple component that can contain + * multiple labels of status information to the user. + AccessibleRole.STATUS_BAR, + + /** + * A DATE_EDITOR is a component that allows users to edit + * java.util.Date and java.util.Time objects + AccessibleRole.DATE_EDITOR, + + /** + * A SPIN_BOX is a simple spinner component and its main use + * is for simple numbers. + AccessibleRole.SPIN_BOX, + + /** + * A FONT_CHOOSER is a component that lets the user pick various + * attributes for fonts. + AccessibleRole.FONT_CHOOSER, + + /** + * A GROUP_BOX is a simple container that contains a border + * around it and contains components inside it. + AccessibleRole.GROUP_BOX + + /** + * Since JDK 1.5 + * + * A text header + + AccessibleRole.HEADER, + + /** + * A text footer + + AccessibleRole.FOOTER, + + /** + * A text paragraph + + AccessibleRole.PARAGRAPH, + + /** + * A ruler is an object used to measure distance + + AccessibleRole.RULER, + + /** + * A role indicating the object acts as a formula for + * calculating a value. An example is a formula in + * a spreadsheet cell. + AccessibleRole.EDITBAR + */ + }; + + /** + * This class implements accessibility support for the + * JTree child. It provides an implementation of the + * Java Accessibility API appropriate to tree nodes. + * + * Copied from JTree.java to work around a JTree bug where + * ActiveDescendent PropertyChangeEvents contain the wrong + * parent. + */ + /** + * This class in invoked on the EDT as its part of ActiveDescendant, + * hence the calls do not need to be specifically made on the EDT + */ + private class AccessibleJTreeNode extends AccessibleContext + implements Accessible, AccessibleComponent, AccessibleSelection, + AccessibleAction { + + private JTree tree = null; + private TreeModel treeModel = null; + private Object obj = null; + private TreePath path = null; + private Accessible accessibleParent = null; + private int index = 0; + private boolean isLeaf = false; + + /** + * Constructs an AccessibleJTreeNode + */ + AccessibleJTreeNode(JTree t, TreePath p, Accessible ap) { + tree = t; + path = p; + accessibleParent = ap; + if (t != null) + treeModel = t.getModel(); + if (p != null) { + obj = p.getLastPathComponent(); + if (treeModel != null && obj != null) { + isLeaf = treeModel.isLeaf(obj); + } + } + debugString("AccessibleJTreeNode: name = "+getAccessibleName()+"; TreePath = "+p+"; parent = "+ap); + } + + private TreePath getChildTreePath(int i) { + // Tree nodes can't be so complex that they have + // two sets of children -> we're ignoring that case + if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) { + return null; + } else { + Object childObj = treeModel.getChild(obj, i); + Object[] objPath = path.getPath(); + Object[] objChildPath = new Object[objPath.length+1]; + java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length); + objChildPath[objChildPath.length-1] = childObj; + return new TreePath(objChildPath); + } + } + + /** + * Get the AccessibleContext associated with this tree node. + * In the implementation of the Java Accessibility API for + * this class, return this object, which is its own + * AccessibleContext. + * + * @return this object + */ + public AccessibleContext getAccessibleContext() { + return this; + } + + private AccessibleContext getCurrentAccessibleContext() { + Component c = getCurrentComponent(); + if (c instanceof Accessible) { + return (c.getAccessibleContext()); + } else { + return null; + } + } + + private Component getCurrentComponent() { + debugString("AccessibleJTreeNode: getCurrentComponent"); + // is the object visible? + // if so, get row, selected, focus & leaf state, + // and then get the renderer component and return it + if (tree != null && tree.isVisible(path)) { + TreeCellRenderer r = tree.getCellRenderer(); + if (r == null) { + debugString(" returning null 1"); + return null; + } + TreeUI ui = tree.getUI(); + if (ui != null) { + int row = ui.getRowForPath(tree, path); + boolean selected = tree.isPathSelected(path); + boolean expanded = tree.isExpanded(path); + boolean hasFocus = false; // how to tell?? -PK + Component retval = r.getTreeCellRendererComponent(tree, obj, + selected, expanded, + isLeaf, row, hasFocus); + debugString(" returning = "+retval.getClass()); + return retval; + } + } + debugString(" returning null 2"); + return null; + } + + // AccessibleContext methods + + /** + * Get the accessible name of this object. + * + * @return the localized name of the object; null if this + * object does not have a name + */ + public String getAccessibleName() { + debugString("AccessibleJTreeNode: getAccessibleName"); + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + String name = ac.getAccessibleName(); + if ((name != null) && (!name.isEmpty())) { + String retval = ac.getAccessibleName(); + debugString(" returning "+retval); + return retval; + } else { + return null; + } + } + if ((accessibleName != null) && (accessibleName.isEmpty())) { + return accessibleName; + } else { + return null; + } + } + + /** + * Set the localized accessible name of this object. + * + * @param s the new localized name of the object. + */ + public void setAccessibleName(String s) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + ac.setAccessibleName(s); + } else { + super.setAccessibleName(s); + } + } + + // + // *** should check tooltip text for desc. (needs MouseEvent) + // + /** + * Get the accessible description of this object. + * + * @return the localized description of the object; null if + * this object does not have a description + */ + public String getAccessibleDescription() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + return ac.getAccessibleDescription(); + } else { + return super.getAccessibleDescription(); + } + } + + /** + * Set the accessible description of this object. + * + * @param s the new localized description of the object + */ + public void setAccessibleDescription(String s) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + ac.setAccessibleDescription(s); + } else { + super.setAccessibleDescription(s); + } + } + + /** + * Get the role of this object. + * + * @return an instance of AccessibleRole describing the role of the object + * @see AccessibleRole + */ + public AccessibleRole getAccessibleRole() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + return ac.getAccessibleRole(); + } else { + return AccessibleRole.UNKNOWN; + } + } + + /** + * Get the state set of this object. + * + * @return an instance of AccessibleStateSet containing the + * current state set of the object + * @see AccessibleState + */ + public AccessibleStateSet getAccessibleStateSet() { + if (tree == null) + return null; + AccessibleContext ac = getCurrentAccessibleContext(); + AccessibleStateSet states; + int row = tree.getUI().getRowForPath(tree,path); + int lsr = tree.getLeadSelectionRow(); + if (ac != null) { + states = ac.getAccessibleStateSet(); + } else { + states = new AccessibleStateSet(); + } + // need to test here, 'cause the underlying component + // is a cellRenderer, which is never showing... + if (isShowing()) { + states.add(AccessibleState.SHOWING); + } else if (states.contains(AccessibleState.SHOWING)) { + states.remove(AccessibleState.SHOWING); + } + if (isVisible()) { + states.add(AccessibleState.VISIBLE); + } else if (states.contains(AccessibleState.VISIBLE)) { + states.remove(AccessibleState.VISIBLE); + } + if (tree.isPathSelected(path)){ + states.add(AccessibleState.SELECTED); + } + if (lsr == row) { + states.add(AccessibleState.ACTIVE); + } + if (!isLeaf) { + states.add(AccessibleState.EXPANDABLE); + } + if (tree.isExpanded(path)) { + states.add(AccessibleState.EXPANDED); + } else { + states.add(AccessibleState.COLLAPSED); + } + if (tree.isEditable()) { + states.add(AccessibleState.EDITABLE); + } + return states; + } + + /** + * Get the Accessible parent of this object. + * + * @return the Accessible parent of this object; null if this + * object does not have an Accessible parent + */ + public Accessible getAccessibleParent() { + // someone wants to know, so we need to create our parent + // if we don't have one (hey, we're a talented kid!) + if (accessibleParent == null && path != null) { + Object[] objPath = path.getPath(); + if (objPath.length > 1) { + Object objParent = objPath[objPath.length-2]; + if (treeModel != null) { + index = treeModel.getIndexOfChild(objParent, obj); + } + Object[] objParentPath = new Object[objPath.length-1]; + java.lang.System.arraycopy(objPath, 0, objParentPath, + 0, objPath.length-1); + TreePath parentPath = new TreePath(objParentPath); + accessibleParent = new AccessibleJTreeNode(tree, + parentPath, + null); + this.setAccessibleParent(accessibleParent); + } else if (treeModel != null) { + accessibleParent = tree; // we're the top! + index = 0; // we're an only child! + this.setAccessibleParent(accessibleParent); + } + } + return accessibleParent; + } + + /** + * Get the index of this object in its accessible parent. + * + * @return the index of this object in its parent; -1 if this + * object does not have an accessible parent. + * @see #getAccessibleParent + */ + public int getAccessibleIndexInParent() { + // index is invalid 'till we have an accessibleParent... + if (accessibleParent == null) { + getAccessibleParent(); + } + if (path != null) { + Object[] objPath = path.getPath(); + if (objPath.length > 1) { + Object objParent = objPath[objPath.length-2]; + if (treeModel != null) { + index = treeModel.getIndexOfChild(objParent, obj); + } + } + } + return index; + } + + /** + * Returns the number of accessible children in the object. + * + * @return the number of accessible children in the object. + */ + public int getAccessibleChildrenCount() { + // Tree nodes can't be so complex that they have + // two sets of children -> we're ignoring that case + if (obj != null && treeModel != null) { + return treeModel.getChildCount(obj); + } + return 0; + } + + /** + * Return the specified Accessible child of the object. + * + * @param i zero-based index of child + * @return the Accessible child of the object + */ + public Accessible getAccessibleChild(int i) { + // Tree nodes can't be so complex that they have + // two sets of children -> we're ignoring that case + if (i < 0 || i >= getAccessibleChildrenCount() || path == null || treeModel == null) { + return null; + } else { + Object childObj = treeModel.getChild(obj, i); + Object[] objPath = path.getPath(); + Object[] objChildPath = new Object[objPath.length+1]; + java.lang.System.arraycopy(objPath, 0, objChildPath, 0, objPath.length); + objChildPath[objChildPath.length-1] = childObj; + TreePath childPath = new TreePath(objChildPath); + return new AccessibleJTreeNode(tree, childPath, this); + } + } + + /** + * Gets the locale of the component. If the component does not have + * a locale, then the locale of its parent is returned. + * + * @return This component's locale. If this component does not have + * a locale, the locale of its parent is returned. + * @exception IllegalComponentStateException + * If the Component does not have its own locale and has not yet + * been added to a containment hierarchy such that the locale can be + * determined from the containing parent. + * @see #setLocale + */ + public Locale getLocale() { + if (tree == null) + return null; + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + return ac.getLocale(); + } else { + return tree.getLocale(); + } + } + + /** + * Add a PropertyChangeListener to the listener list. + * The listener is registered for all properties. + * + * @param l The PropertyChangeListener to be added + */ + public void addPropertyChangeListener(PropertyChangeListener l) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + ac.addPropertyChangeListener(l); + } else { + super.addPropertyChangeListener(l); + } + } + + /** + * Remove a PropertyChangeListener from the listener list. + * This removes a PropertyChangeListener that was registered + * for all properties. + * + * @param l The PropertyChangeListener to be removed + */ + public void removePropertyChangeListener(PropertyChangeListener l) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + ac.removePropertyChangeListener(l); + } else { + super.removePropertyChangeListener(l); + } + } + + /** + * Get the AccessibleAction associated with this object. In the + * implementation of the Java Accessibility API for this class, + * return this object, which is responsible for implementing the + * AccessibleAction interface on behalf of itself. + * + * @return this object + */ + public AccessibleAction getAccessibleAction() { + return this; + } + + /** + * Get the AccessibleComponent associated with this object. In the + * implementation of the Java Accessibility API for this class, + * return this object, which is responsible for implementing the + * AccessibleComponent interface on behalf of itself. + * + * @return this object + */ + public AccessibleComponent getAccessibleComponent() { + return this; // to override getBounds() + } + + /** + * Get the AccessibleSelection associated with this object if one + * exists. Otherwise return null. + * + * @return the AccessibleSelection, or null + */ + public AccessibleSelection getAccessibleSelection() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null && isLeaf) { + return getCurrentAccessibleContext().getAccessibleSelection(); + } else { + return this; + } + } + + /** + * Get the AccessibleText associated with this object if one + * exists. Otherwise return null. + * + * @return the AccessibleText, or null + */ + public AccessibleText getAccessibleText() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + return getCurrentAccessibleContext().getAccessibleText(); + } else { + return null; + } + } + + /** + * Get the AccessibleValue associated with this object if one + * exists. Otherwise return null. + * + * @return the AccessibleValue, or null + */ + public AccessibleValue getAccessibleValue() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + return getCurrentAccessibleContext().getAccessibleValue(); + } else { + return null; + } + } + + + // AccessibleComponent methods + + /** + * Get the background color of this object. + * + * @return the background color, if supported, of the object; + * otherwise, null + */ + public Color getBackground() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + return ((AccessibleComponent) ac).getBackground(); + } else { + Component c = getCurrentComponent(); + if (c != null) { + return c.getBackground(); + } else { + return null; + } + } + } + + /** + * Set the background color of this object. + * + * @param c the new Color for the background + */ + public void setBackground(Color c) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).setBackground(c); + } else { + Component cp = getCurrentComponent(); + if ( cp != null) { + cp.setBackground(c); + } + } + } + + + /** + * Get the foreground color of this object. + * + * @return the foreground color, if supported, of the object; + * otherwise, null + */ + public Color getForeground() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + return ((AccessibleComponent) ac).getForeground(); + } else { + Component c = getCurrentComponent(); + if (c != null) { + return c.getForeground(); + } else { + return null; + } + } + } + + public void setForeground(Color c) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).setForeground(c); + } else { + Component cp = getCurrentComponent(); + if (cp != null) { + cp.setForeground(c); + } + } + } + + public Cursor getCursor() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + return ((AccessibleComponent) ac).getCursor(); + } else { + Component c = getCurrentComponent(); + if (c != null) { + return c.getCursor(); + } else { + Accessible ap = getAccessibleParent(); + if (ap instanceof AccessibleComponent) { + return ((AccessibleComponent) ap).getCursor(); + } else { + return null; + } + } + } + } + + public void setCursor(Cursor c) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).setCursor(c); + } else { + Component cp = getCurrentComponent(); + if (cp != null) { + cp.setCursor(c); + } + } + } + + public Font getFont() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + return ((AccessibleComponent) ac).getFont(); + } else { + Component c = getCurrentComponent(); + if (c != null) { + return c.getFont(); + } else { + return null; + } + } + } + + public void setFont(Font f) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).setFont(f); + } else { + Component c = getCurrentComponent(); + if (c != null) { + c.setFont(f); + } + } + } + + public FontMetrics getFontMetrics(Font f) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + return ((AccessibleComponent) ac).getFontMetrics(f); + } else { + Component c = getCurrentComponent(); + if (c != null) { + return c.getFontMetrics(f); + } else { + return null; + } + } + } + + public boolean isEnabled() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + return ((AccessibleComponent) ac).isEnabled(); + } else { + Component c = getCurrentComponent(); + if (c != null) { + return c.isEnabled(); + } else { + return false; + } + } + } + + public void setEnabled(boolean b) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).setEnabled(b); + } else { + Component c = getCurrentComponent(); + if (c != null) { + c.setEnabled(b); + } + } + } + + public boolean isVisible() { + if (tree == null) + return false; + Rectangle pathBounds = tree.getPathBounds(path); + Rectangle parentBounds = tree.getVisibleRect(); + if ( pathBounds != null && parentBounds != null && + parentBounds.intersects(pathBounds) ) { + return true; + } else { + return false; + } + } + + public void setVisible(boolean b) { + } + + public boolean isShowing() { + return (tree.isShowing() && isVisible()); + } + + public boolean contains(Point p) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + Rectangle r = ((AccessibleComponent) ac).getBounds(); + return r.contains(p); + } else { + Component c = getCurrentComponent(); + if (c != null) { + Rectangle r = c.getBounds(); + return r.contains(p); + } else { + return getBounds().contains(p); + } + } + } + + public Point getLocationOnScreen() { + if (tree != null) { + Point treeLocation = tree.getLocationOnScreen(); + Rectangle pathBounds = tree.getPathBounds(path); + if (treeLocation != null && pathBounds != null) { + Point nodeLocation = new Point(pathBounds.x, + pathBounds.y); + nodeLocation.translate(treeLocation.x, treeLocation.y); + return nodeLocation; + } else { + return null; + } + } else { + return null; + } + } + + private Point getLocationInJTree() { + Rectangle r = tree.getPathBounds(path); + if (r != null) { + return r.getLocation(); + } else { + return null; + } + } + + public Point getLocation() { + Rectangle r = getBounds(); + if (r != null) { + return r.getLocation(); + } else { + return null; + } + } + + public void setLocation(Point p) { + } + + public Rectangle getBounds() { + if (tree == null) + return null; + Rectangle r = tree.getPathBounds(path); + Accessible parent = getAccessibleParent(); + if (parent instanceof AccessibleJTreeNode) { + Point parentLoc = ((AccessibleJTreeNode) parent).getLocationInJTree(); + if (parentLoc != null && r != null) { + r.translate(-parentLoc.x, -parentLoc.y); + } else { + return null; // not visible! + } + } + return r; + } + + public void setBounds(Rectangle r) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).setBounds(r); + } else { + Component c = getCurrentComponent(); + if (c != null) { + c.setBounds(r); + } + } + } + + public Dimension getSize() { + return getBounds().getSize(); + } + + public void setSize (Dimension d) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).setSize(d); + } else { + Component c = getCurrentComponent(); + if (c != null) { + c.setSize(d); + } + } + } + + /** + * Returns the Accessible child, if one exists, + * contained at the local coordinate Point. + * Otherwise returns null. + * + * @param p point in local coordinates of this + * Accessible + * @return the Accessible, if it exists, + * at the specified location; else null + */ + public Accessible getAccessibleAt(Point p) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + return ((AccessibleComponent) ac).getAccessibleAt(p); + } else { + return null; + } + } + + public boolean isFocusTraversable() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + return ((AccessibleComponent) ac).isFocusTraversable(); + } else { + Component c = getCurrentComponent(); + if (c != null) { + return c.isFocusable(); + } else { + return false; + } + } + } + + public void requestFocus() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).requestFocus(); + } else { + Component c = getCurrentComponent(); + if (c != null) { + c.requestFocus(); + } + } + } + + public void addFocusListener(FocusListener l) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).addFocusListener(l); + } else { + Component c = getCurrentComponent(); + if (c != null) { + c.addFocusListener(l); + } + } + } + + public void removeFocusListener(FocusListener l) { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac instanceof AccessibleComponent) { + ((AccessibleComponent) ac).removeFocusListener(l); + } else { + Component c = getCurrentComponent(); + if (c != null) { + c.removeFocusListener(l); + } + } + } + + // AccessibleSelection methods + + /** + * Returns the number of items currently selected. + * If no items are selected, the return value will be 0. + * + * @return the number of items currently selected. + */ + public int getAccessibleSelectionCount() { + int count = 0; + int childCount = getAccessibleChildrenCount(); + for (int i = 0; i < childCount; i++) { + TreePath childPath = getChildTreePath(i); + if (tree.isPathSelected(childPath)) { + count++; + } + } + return count; + } + + /** + * Returns an Accessible representing the specified selected item + * in the object. If there isn't a selection, or there are + * fewer items selected than the integer passed in, the return + * value will be null. + * + * @param i the zero-based index of selected items + * @return an Accessible containing the selected item + */ + public Accessible getAccessibleSelection(int i) { + int childCount = getAccessibleChildrenCount(); + if (i < 0 || i >= childCount) { + return null; // out of range + } + int count = 0; + for (int j = 0; j < childCount && i >= count; j++) { + TreePath childPath = getChildTreePath(j); + if (tree.isPathSelected(childPath)) { + if (count == i) { + return new AccessibleJTreeNode(tree, childPath, this); + } else { + count++; + } + } + } + return null; + } + + /** + * Returns true if the current child of this object is selected. + * + * @param i the zero-based index of the child in this Accessible + * object. + * @see AccessibleContext#getAccessibleChild + */ + public boolean isAccessibleChildSelected(int i) { + int childCount = getAccessibleChildrenCount(); + if (i < 0 || i >= childCount) { + return false; // out of range + } else { + TreePath childPath = getChildTreePath(i); + return tree.isPathSelected(childPath); + } + } + + /** + * Adds the specified selected item in the object to the object's + * selection. If the object supports multiple selections, + * the specified item is added to any existing selection, otherwise + * it replaces any existing selection in the object. If the + * specified item is already selected, this method has no effect. + * + * @param i the zero-based index of selectable items + */ + public void addAccessibleSelection(int i) { + if (tree == null) + return; + TreeModel model = tree.getModel(); + if (model != null) { + if (i >= 0 && i < getAccessibleChildrenCount()) { + TreePath path = getChildTreePath(i); + tree.addSelectionPath(path); + } + } + } + + /** + * Removes the specified selected item in the object from the + * object's + * selection. If the specified item isn't currently selected, this + * method has no effect. + * + * @param i the zero-based index of selectable items + */ + public void removeAccessibleSelection(int i) { + if (tree == null) + return; + TreeModel model = tree.getModel(); + if (model != null) { + if (i >= 0 && i < getAccessibleChildrenCount()) { + TreePath path = getChildTreePath(i); + tree.removeSelectionPath(path); + } + } + } + + /** + * Clears the selection in the object, so that nothing in the + * object is selected. + */ + public void clearAccessibleSelection() { + int childCount = getAccessibleChildrenCount(); + for (int i = 0; i < childCount; i++) { + removeAccessibleSelection(i); + } + } + + /** + * Causes every selected item in the object to be selected + * if the object supports multiple selections. + */ + public void selectAllAccessibleSelection() { + if (tree == null) + return; + TreeModel model = tree.getModel(); + if (model != null) { + int childCount = getAccessibleChildrenCount(); + TreePath path; + for (int i = 0; i < childCount; i++) { + path = getChildTreePath(i); + tree.addSelectionPath(path); + } + } + } + + // AccessibleAction methods + + /** + * Returns the number of accessible actions available in this + * tree node. If this node is not a leaf, there is at least + * one action (toggle expand), in addition to any available + * on the object behind the TreeCellRenderer. + * + * @return the number of Actions in this object + */ + public int getAccessibleActionCount() { + AccessibleContext ac = getCurrentAccessibleContext(); + if (ac != null) { + AccessibleAction aa = ac.getAccessibleAction(); + if (aa != null) { + return (aa.getAccessibleActionCount() + (isLeaf ? 0 : 1)); + } + } + return isLeaf ? 0 : 1; + } + + /** + * Return a description of the specified action of the tree node. + * If this node is not a leaf, there is at least one action + * description (toggle expand), in addition to any available + * on the object behind the TreeCellRenderer. + * + * @param i zero-based index of the actions + * @return a description of the action + */ + public String getAccessibleActionDescription(int i) { + if (i < 0 || i >= getAccessibleActionCount()) { + return null; + } + AccessibleContext ac = getCurrentAccessibleContext(); + if (i == 0) { + // TIGER - 4766636 + // return AccessibleAction.TOGGLE_EXPAND; + return "toggle expand"; + } else if (ac != null) { + AccessibleAction aa = ac.getAccessibleAction(); + if (aa != null) { + return aa.getAccessibleActionDescription(i - 1); + } + } + return null; + } + + /** + * Perform the specified Action on the tree node. If this node + * is not a leaf, there is at least one action which can be + * done (toggle expand), in addition to any available on the + * object behind the TreeCellRenderer. + * + * @param i zero-based index of actions + * @return true if the the action was performed; else false. + */ + public boolean doAccessibleAction(int i) { + if (i < 0 || i >= getAccessibleActionCount()) { + return false; + } + AccessibleContext ac = getCurrentAccessibleContext(); + if (i == 0) { + if (tree.isExpanded(path)) { + tree.collapsePath(path); + } else { + tree.expandPath(path); + } + return true; + } else if (ac != null) { + AccessibleAction aa = ac.getAccessibleAction(); + if (aa != null) { + return aa.doAccessibleAction(i - 1); + } + } + return false; + } + + } // inner class AccessibleJTreeNode + + /** + * A helper class to perform {@code Callable} objects on the event dispatch thread appropriate + * for the provided {@code AccessibleContext}. + */ + private static class InvocationUtils { + + /** + * Invokes a {@code Callable} in the {@code AppContext} of the given {@code Accessible} + * and waits for it to finish blocking the caller thread. + * + * @param callable the {@code Callable} to invoke + * @param accessible the {@code Accessible} which would be used to find the right context + * for the task execution + * @param type parameter for the result value + * + * @return the result of the {@code Callable} execution + */ + public static T invokeAndWait(final Callable callable, + final Accessible accessible) { + if (accessible instanceof Component) { + return invokeAndWait(callable, (Component)accessible); + } + if (accessible instanceof AccessibleContext) { + // This case also covers the Translator + return invokeAndWait(callable, (AccessibleContext)accessible); + } + throw new RuntimeException("Unmapped Accessible used to dispatch event: " + accessible); + } + + /** + * Invokes a {@code Callable} in the {@code AppContext} of the given {@code Component} + * and waits for it to finish blocking the caller thread. + * + * @param callable the {@code Callable} to invoke + * @param component the {@code Component} which would be used to find the right context + * for the task execution + * @param type parameter for the result value + * + * @return the result of the {@code Callable} execution + */ + public static T invokeAndWait(final Callable callable, + final Component component) { + return invokeAndWait(callable, SunToolkit.targetToAppContext(component)); + } + + /** + * Invokes a {@code Callable} in the {@code AppContext} mapped to the given {@code AccessibleContext} + * and waits for it to finish blocking the caller thread. + * + * @param callable the {@code Callable} to invoke + * @param accessibleContext the {@code AccessibleContext} which would be used to determine the right + * context for the task execution. + * @param type parameter for the result value + * + * @return the result of the {@code Callable} execution + */ + public static T invokeAndWait(final Callable callable, + final AccessibleContext accessibleContext) { + AppContext targetContext = AWTAccessor.getAccessibleContextAccessor() + .getAppContext(accessibleContext); + if (targetContext != null) { + return invokeAndWait(callable, targetContext); + } else { + // Normally this should not happen, unmapped context provided and + // the target AppContext is unknown. + + // Try to recover in case the context is a translator. + if (accessibleContext instanceof Translator) { + Object source = ((Translator)accessibleContext).getSource(); + if (source instanceof Component) { + return invokeAndWait(callable, (Component)source); + } + } + } + throw new RuntimeException("Unmapped AccessibleContext used to dispatch event: " + accessibleContext); + } + + private static T invokeAndWait(final Callable callable, + final AppContext targetAppContext) { + final CallableWrapper wrapper = new CallableWrapper(callable); + try { + invokeAndWait(wrapper, targetAppContext); + T result = wrapper.getResult(); + updateAppContextMap(result, targetAppContext); + return result; + } catch (final Exception e) { + throw new RuntimeException(e); + } + } + + private static void invokeAndWait(final Runnable runnable, + final AppContext appContext) + throws InterruptedException, InvocationTargetException { + + EventQueue eq = SunToolkit.getSystemEventQueueImplPP(appContext); + Object lock = new Object(); + Toolkit source = Toolkit.getDefaultToolkit(); + InvocationEvent event = + new InvocationEvent(source, runnable, lock, true); + synchronized (lock) { + eq.postEvent(event); + lock.wait(); + } + + Throwable eventThrowable = event.getThrowable(); + if (eventThrowable != null) { + throw new InvocationTargetException(eventThrowable); + } + } + + /** + * Maps the {@code AccessibleContext} to the {@code AppContext} which should be used + * to dispatch events related to the {@code AccessibleContext} + * @param accessibleContext the {@code AccessibleContext} for the mapping + * @param targetContext the {@code AppContext} for the mapping + */ + public static void registerAccessibleContext(final AccessibleContext accessibleContext, + final AppContext targetContext) { + if (accessibleContext != null) { + AWTAccessor.getAccessibleContextAccessor().setAppContext(accessibleContext, targetContext); + } + } + + private static void updateAppContextMap(final T accessibleContext, + final AppContext targetContext) { + if (accessibleContext instanceof AccessibleContext) { + registerAccessibleContext((AccessibleContext)accessibleContext, targetContext); + } + } + + private static class CallableWrapper implements Runnable { + private final Callable callable; + private volatile T object; + private Exception e; + + CallableWrapper(final Callable callable) { + this.callable = callable; + } + + public void run() { + try { + if (callable != null) { + object = callable.call(); + } + } catch (final Exception e) { + this.e = e; + } + } + + T getResult() throws Exception { + if (e != null) + throw e; + return object; + } + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/conf/accessibility.properties --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/conf/accessibility.properties Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,6 @@ +# +# Load the Java Access Bridge class into the JVM +# +#assistive_technologies=com.sun.java.accessibility.AccessBridge +#screen_magnifier_present=true + diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to manage AccessBridge debugging + */ + +#include "AccessBridgeDebug.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * print a GetLastError message + */ +char *printError(char *msg) { + LPVOID lpMsgBuf = NULL; + static char retbuf[256]; + + if (msg != NULL) { + strncpy((char *)retbuf, msg, sizeof(retbuf)); + } + if (!FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPTSTR) &lpMsgBuf, + 0, + NULL )) + { + PrintDebugString(" %s: FormatMessage failed", msg); + } else { + PrintDebugString(" %s: %s", msg, (char *)lpMsgBuf); + } + if (lpMsgBuf != NULL) { + strncat((char *)retbuf, ": ", sizeof(retbuf) - strlen(retbuf) - 1); + strncat((char *)retbuf, (char *)lpMsgBuf, sizeof(retbuf) - strlen(retbuf) - 1); + } + return (char *)retbuf; +} + + + /** + * Send debugging info to the appropriate place + */ + void PrintDebugString(char *msg, ...) { +#ifdef DEBUGGING_ON + char buf[1024]; + va_list argprt; + + va_start(argprt, msg); // set up argptr + vsprintf(buf, msg, argprt); +#ifdef SEND_TO_OUTPUT_DEBUG_STRING + OutputDebugString(buf); +#endif +#ifdef SEND_TO_CONSOLE + printf(buf); + printf("\r\n"); +#endif +#endif + } + + /** + * Send Java debugging info to the appropriate place + */ + void PrintJavaDebugString2(char *msg, ...) { +#ifdef JAVA_DEBUGGING_ON + char buf[1024]; + va_list argprt; + + va_start(argprt, msg); // set up argptr + vsprintf(buf, msg, argprt); +#ifdef SEND_TO_OUTPUT_DEBUG_STRING + OutputDebugString(buf); +#endif +#ifdef SEND_TO_CONSOLE + printf(buf); + printf("\r\n"); +#endif +#endif + } + /** + * Wide version of the method to send debugging info to the appropriate place + */ + void wPrintDebugString(wchar_t *msg, ...) { +#ifdef DEBUGGING_ON + char buf[1024]; + char charmsg[256]; + va_list argprt; + + va_start(argprt, msg); // set up argptr + sprintf(charmsg, "%ls", msg); // convert format string to multi-byte + vsprintf(buf, charmsg, argprt); +#ifdef SEND_TO_OUTPUT_DEBUG_STRING + OutputDebugString(buf); +#endif +#ifdef SEND_TO_CONSOLE + printf(buf); + printf("\r\n"); +#endif +#endif + } + + /** + * Wide version of the method to send Java debugging info to the appropriate place + */ + void wPrintJavaDebugString(wchar_t *msg, ...) { +#ifdef JAVA_DEBUGGING_ON + char buf[1024]; + char charmsg[256]; + va_list argprt; + + va_start(argprt, msg); // set up argptr + sprintf(charmsg, "%ls", msg); // convert format string to multi-byte + vsprintf(buf, charmsg, argprt); +#ifdef SEND_TO_OUTPUT_DEBUG_STRING + OutputDebugString(buf); +#endif +#ifdef SEND_TO_CONSOLE + printf(buf); + printf("\r\n"); +#endif +#endif + } +#ifdef __cplusplus +} +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeDebug.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to manage AccessBridge debugging + */ + +#ifndef __AccessBridgeDebug_H__ +#define __AccessBridgeDebug_H__ + +#include +#include + +#ifdef DEBUG +#define DEBUGGING_ON +#define SEND_TO_OUTPUT_DEBUG_STRING +//#define JAVA_DEBUGGING_ON +#endif + +#ifdef DEBUGGING_ON +#define DEBUG_CODE(x) x +#else +#define DEBUG_CODE(x) /* */ +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + char *printError(char *msg); + void PrintDebugString(char *msg, ...); + void PrintJavaDebugString(char *msg, ...); + void wPrintJavaDebugString(wchar_t *msg, ...); + void wPrintDebugString(wchar_t *msg, ...); + +#ifdef __cplusplus +} +#endif + + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/common/AccessBridgeMessages.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeMessages.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * Common AccessBridge IPC message definitions + */ + +#include "AccessBridgeMessages.h" + + +// unique broadcast msg. IDs gotten dymanically + +// wParam == sourceHwnc; lParam = *vmID +UINT theFromJavaHelloMsgID; +// wParam == sourceHwnc; lParam unused +UINT theFromWindowsHelloMsgID; + + +BOOL initBroadcastMessageIDs() { + theFromJavaHelloMsgID = RegisterWindowMessage("AccessBridge-FromJava-Hello"); + theFromWindowsHelloMsgID = RegisterWindowMessage("AccessBridge-FromWindows-Hello"); + + if (theFromJavaHelloMsgID == 0 || theFromWindowsHelloMsgID) { + return FALSE; + } + return TRUE; +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/common/AccessBridgeMessages.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeMessages.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * Common AccessBridge IPC message definitions + */ + +#include +#include + +#ifndef __AccessBridgeMessages_H__ +#define __AccessBridgeMessages_H__ + + +// used for messages between AccessBridge dlls to manage IPC +// In the SendMessage call, the third param (WPARAM) is +// the source HWND (ourAccessBridgeWindow in this case), +// and the fourth param (LPARAM) is the size in bytes of +// the package put into shared memory. +#define AB_MEMORY_MAPPED_FILE_SETUP (WM_USER+0x1000) + +// used for messages between AccessBridge dlls to manage IPC +// In the SendMessage call, the third param (WPARAM) is +// the source HWND (ourAccessBridgeWindow in this case), +// and the fourth param (LPARAM) is the size in bytes of +// the package put into shared memory. +#define AB_MESSAGE_WAITING (WM_USER+0x1001) + +// used for messages from JavaDLL to itself (or perhaps later also +// for messages from WindowsDLL to itself). Used with PostMessage, +// it is called for deferred processing of messages to send across +// to another DLL (or DLLs) +#define AB_MESSAGE_QUEUED (WM_USER+0x1002) + +// used to let other AccessBridge DLLs know that one of the DLLs +// they are communicating with is going away (not reversable) +#define AB_DLL_GOING_AWAY (WM_USER+0x1003) + + +// used as part of the Memory-Mapped file IPC setup. The first +// constant is the query, the second the response, that are put +// into the memory mapped file for reading by the opposite DLL +// to verify that communication is working +#define AB_MEMORY_MAPPED_FILE_OK_QUERY "OK?" +#define AB_MEMORY_MAPPED_FILE_OK_ANSWER "OK!" + + +BOOL initBroadcastMessageIDs(); + + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/common/AccessBridgeStatusWindow.RC --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/common/AccessBridgeStatusWindow.RC Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,175 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +#include "accessBridgeResource.h" + +#define XSTR(x) STR(x) +#define STR(x) #x + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +ACCESSBRIDGESTATUSWINDOW DIALOGEX 160, 78, 209, 163 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CLIENTEDGE +CAPTION "Access Bridge status" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + EDITTEXT cVMID,67,23,121,13,ES_READONLY + EDITTEXT cStatusText,40,147,162,13,ES_READONLY + LTEXT "Java VM ID:",IDC_STATIC,23,25,40,8 + LTEXT "Status:",IDC_STATIC,11,149,23,8 + EDITTEXT cWindowsID,67,39,121,13,ES_READONLY + LTEXT "Windows ID:",IDC_STATIC,21,41,42,8 + EDITTEXT cCallInfo,12,65,184,75,ES_MULTILINE | ES_AUTOVSCROLL | + ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL + GROUPBOX "Call info",IDC_STATIC,4,55,197,90 + EDITTEXT cInvokedByText,67,1,121,13,ES_READONLY + LTEXT "Invoked by:",IDC_STATIC,25,3,38,8 +END + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 186, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + "ACCESSBRIDGESTATUSWINDOW", DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 202 + BOTTOMMARGIN, 160 + END + + "IDD_DIALOG1", DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END +END +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION JDK_FVER + PRODUCTVERSION JDK_FVER + FILEFLAGSMASK 0x3fL +#ifdef DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE JDK_FTYPE + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Java Access Bridge\0" + VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" + VALUE "FileDescription", XSTR(JDK_COMPONENT) "\0" + VALUE "FileVersion", XSTR(JDK_VER) "\0" + VALUE "Full Version", XSTR(JDK_BUILD_ID) "\0" + VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" + VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" + VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" + VALUE "ProductName", XSTR(JDK_NAME) "\0" + VALUE "ProductVersion", XSTR(JDK_VER) "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/common/accessBridgeResource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/common/accessBridgeResource.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +#define cVMID 1001 +#define cWindowsID 1002 +#define cStatusText 1003 +#define cCallInfo 1004 +#define cInvokedByText 1005 +#define IDC_STATIC -1 + +#define cInstallAccessBridge 2001 +#define cRemindThereIsNewJVM 2005 +#define cDoNotRemindThereIsNewJVM 2005 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1032 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/common/resource.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/common/resource.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by AccessBridgeStatusWindow.RC +// +//#define IDB_BITMAP1 102 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1032 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/include/bridge/AccessBridgeCallbacks.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/include/bridge/AccessBridgeCallbacks.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * AccessBridgeCallbacks.h 1.17 05/03/21 + */ + +/* + * Header file defining callback typedefs for Windows routines + * which are called from Java (responding to events, etc.). + */ + +#ifndef __AccessBridgeCallbacks_H__ +#define __AccessBridgeCallbacks_H__ + +#include +#include "AccessBridgePackages.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*AccessBridge_PropertyChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *property, wchar_t *oldValue, wchar_t *newValue); + +typedef void (*AccessBridge_JavaShutdownFP) (long vmID); +typedef void (*AccessBridge_JavaShutdownFP) (long vmID); + +typedef void (*AccessBridge_FocusGainedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_FocusLostFP) (long vmID, JOBJECT64 event, JOBJECT64 source); + +typedef void (*AccessBridge_CaretUpdateFP) (long vmID, JOBJECT64 event, JOBJECT64 source); + +typedef void (*AccessBridge_MouseClickedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MouseEnteredFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MouseExitedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MousePressedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MouseReleasedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); + +typedef void (*AccessBridge_MenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MenuDeselectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_MenuSelectedFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PopupMenuCanceledFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PopupMenuWillBecomeInvisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PopupMenuWillBecomeVisibleFP) (long vmID, JOBJECT64 event, JOBJECT64 source); + +typedef void (*AccessBridge_PropertyNameChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldName, wchar_t *newName); +typedef void (*AccessBridge_PropertyDescriptionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldDescription, wchar_t *newDescription); +typedef void (*AccessBridge_PropertyStateChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldState, wchar_t *newState); +typedef void (*AccessBridge_PropertyValueChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldValue, wchar_t *newValue); +typedef void (*AccessBridge_PropertySelectionChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PropertyTextChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PropertyCaretChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + int oldPosition, int newPosition); +typedef void (*AccessBridge_PropertyVisibleDataChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source); +typedef void (*AccessBridge_PropertyChildChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 source, + JOBJECT64 oldChild, JOBJECT64 newChild); +typedef void (*AccessBridge_PropertyActiveDescendentChangeFP) (long vmID, JOBJECT64 event, + JOBJECT64 source, + JOBJECT64 oldActiveDescendent, + JOBJECT64 newActiveDescendent); + +typedef void (*AccessBridge_PropertyTableModelChangeFP) (long vmID, JOBJECT64 event, JOBJECT64 src, + wchar_t *oldValue, wchar_t *newValue); + +#ifdef __cplusplus +} +#endif + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/include/bridge/AccessBridgeCalls.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/include/bridge/AccessBridgeCalls.c Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,1131 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * @(#)AccessBridgeCalls.c 1.25 05/08/22 + */ + +/* + * Wrapper functions around calls to the AccessBridge DLL + */ + + +#include +#include + + +//#define ACCESSBRIDGE_32 +//#define ACCESSBRIDGE_64 + +#include "AccessBridgeCalls.h" +#include "AccessBridgeDebug.h" + +#ifdef __cplusplus +extern "C" { +#endif + + HINSTANCE theAccessBridgeInstance; + AccessBridgeFPs theAccessBridge; + + BOOL theAccessBridgeInitializedFlag = FALSE; + +#define LOAD_FP(result, type, name) \ + PrintDebugString("LOAD_FP loading: %s ...", name); \ + if ((theAccessBridge.result = \ + (type) GetProcAddress(theAccessBridgeInstance, name)) == (type) 0) { \ + PrintDebugString("LOAD_FP failed: %s", name); \ + return FALSE; \ + } + + BOOL initializeAccessBridge() { + +#ifdef ACCESSBRIDGE_ARCH_32 // For 32bit AT new bridge + theAccessBridgeInstance = LoadLibrary("WINDOWSACCESSBRIDGE-32"); +#else +#ifdef ACCESSBRIDGE_ARCH_64 // For 64bit AT new bridge + theAccessBridgeInstance = LoadLibrary("WINDOWSACCESSBRIDGE-64"); +#else // legacy + theAccessBridgeInstance = LoadLibrary("WINDOWSACCESSBRIDGE"); +#endif +#endif + if (theAccessBridgeInstance != 0) { + LOAD_FP(Windows_run, Windows_runFP, "Windows_run"); + + LOAD_FP(SetJavaShutdown, SetJavaShutdownFP, "setJavaShutdownFP"); + LOAD_FP(SetFocusGained, SetFocusGainedFP, "setFocusGainedFP"); + LOAD_FP(SetFocusLost, SetFocusLostFP, "setFocusLostFP"); + + LOAD_FP(SetCaretUpdate, SetCaretUpdateFP, "setCaretUpdateFP"); + + LOAD_FP(SetMouseClicked, SetMouseClickedFP, "setMouseClickedFP"); + LOAD_FP(SetMouseEntered, SetMouseEnteredFP, "setMouseEnteredFP"); + LOAD_FP(SetMouseExited, SetMouseExitedFP, "setMouseExitedFP"); + LOAD_FP(SetMousePressed, SetMousePressedFP, "setMousePressedFP"); + LOAD_FP(SetMouseReleased, SetMouseReleasedFP, "setMouseReleasedFP"); + + LOAD_FP(SetMenuCanceled, SetMenuCanceledFP, "setMenuCanceledFP"); + LOAD_FP(SetMenuDeselected, SetMenuDeselectedFP, "setMenuDeselectedFP"); + LOAD_FP(SetMenuSelected, SetMenuSelectedFP, "setMenuSelectedFP"); + LOAD_FP(SetPopupMenuCanceled, SetPopupMenuCanceledFP, "setPopupMenuCanceledFP"); + LOAD_FP(SetPopupMenuWillBecomeInvisible, SetPopupMenuWillBecomeInvisibleFP, "setPopupMenuWillBecomeInvisibleFP"); + LOAD_FP(SetPopupMenuWillBecomeVisible, SetPopupMenuWillBecomeVisibleFP, "setPopupMenuWillBecomeVisibleFP"); + + LOAD_FP(SetPropertyNameChange, SetPropertyNameChangeFP, "setPropertyNameChangeFP"); + LOAD_FP(SetPropertyDescriptionChange, SetPropertyDescriptionChangeFP, "setPropertyDescriptionChangeFP"); + LOAD_FP(SetPropertyStateChange, SetPropertyStateChangeFP, "setPropertyStateChangeFP"); + LOAD_FP(SetPropertyValueChange, SetPropertyValueChangeFP, "setPropertyValueChangeFP"); + LOAD_FP(SetPropertySelectionChange, SetPropertySelectionChangeFP, "setPropertySelectionChangeFP"); + LOAD_FP(SetPropertyTextChange, SetPropertyTextChangeFP, "setPropertyTextChangeFP"); + LOAD_FP(SetPropertyCaretChange, SetPropertyCaretChangeFP, "setPropertyCaretChangeFP"); + LOAD_FP(SetPropertyVisibleDataChange, SetPropertyVisibleDataChangeFP, "setPropertyVisibleDataChangeFP"); + LOAD_FP(SetPropertyChildChange, SetPropertyChildChangeFP, "setPropertyChildChangeFP"); + LOAD_FP(SetPropertyActiveDescendentChange, SetPropertyActiveDescendentChangeFP, "setPropertyActiveDescendentChangeFP"); + + LOAD_FP(SetPropertyTableModelChange, SetPropertyTableModelChangeFP, "setPropertyTableModelChangeFP"); + + LOAD_FP(ReleaseJavaObject, ReleaseJavaObjectFP, "releaseJavaObject"); + LOAD_FP(GetVersionInfo, GetVersionInfoFP, "getVersionInfo"); + + LOAD_FP(IsJavaWindow, IsJavaWindowFP, "isJavaWindow"); + LOAD_FP(IsSameObject, IsSameObjectFP, "isSameObject"); + LOAD_FP(GetAccessibleContextFromHWND, GetAccessibleContextFromHWNDFP, "getAccessibleContextFromHWND"); + LOAD_FP(getHWNDFromAccessibleContext, getHWNDFromAccessibleContextFP, "getHWNDFromAccessibleContext"); + + LOAD_FP(GetAccessibleContextAt, GetAccessibleContextAtFP, "getAccessibleContextAt"); + LOAD_FP(GetAccessibleContextWithFocus, GetAccessibleContextWithFocusFP, "getAccessibleContextWithFocus"); + LOAD_FP(GetAccessibleContextInfo, GetAccessibleContextInfoFP, "getAccessibleContextInfo"); + LOAD_FP(GetAccessibleChildFromContext, GetAccessibleChildFromContextFP, "getAccessibleChildFromContext"); + LOAD_FP(GetAccessibleParentFromContext, GetAccessibleParentFromContextFP, "getAccessibleParentFromContext"); + + /* begin AccessibleTable */ + LOAD_FP(getAccessibleTableInfo, getAccessibleTableInfoFP, "getAccessibleTableInfo"); + LOAD_FP(getAccessibleTableCellInfo, getAccessibleTableCellInfoFP, "getAccessibleTableCellInfo"); + + LOAD_FP(getAccessibleTableRowHeader, getAccessibleTableRowHeaderFP, "getAccessibleTableRowHeader"); + LOAD_FP(getAccessibleTableColumnHeader, getAccessibleTableColumnHeaderFP, "getAccessibleTableColumnHeader"); + + LOAD_FP(getAccessibleTableRowDescription, getAccessibleTableRowDescriptionFP, "getAccessibleTableRowDescription"); + LOAD_FP(getAccessibleTableColumnDescription, getAccessibleTableColumnDescriptionFP, "getAccessibleTableColumnDescription"); + + LOAD_FP(getAccessibleTableRowSelectionCount, getAccessibleTableRowSelectionCountFP, + "getAccessibleTableRowSelectionCount"); + LOAD_FP(isAccessibleTableRowSelected, isAccessibleTableRowSelectedFP, + "isAccessibleTableRowSelected"); + LOAD_FP(getAccessibleTableRowSelections, getAccessibleTableRowSelectionsFP, + "getAccessibleTableRowSelections"); + + LOAD_FP(getAccessibleTableColumnSelectionCount, getAccessibleTableColumnSelectionCountFP, + "getAccessibleTableColumnSelectionCount"); + LOAD_FP(isAccessibleTableColumnSelected, isAccessibleTableColumnSelectedFP, + "isAccessibleTableColumnSelected"); + LOAD_FP(getAccessibleTableColumnSelections, getAccessibleTableColumnSelectionsFP, + "getAccessibleTableColumnSelections"); + + LOAD_FP(getAccessibleTableRow, getAccessibleTableRowFP, + "getAccessibleTableRow"); + LOAD_FP(getAccessibleTableColumn, getAccessibleTableColumnFP, + "getAccessibleTableColumn"); + LOAD_FP(getAccessibleTableIndex, getAccessibleTableIndexFP, + "getAccessibleTableIndex"); + + /* end AccessibleTable */ + + /* AccessibleRelationSet */ + LOAD_FP(getAccessibleRelationSet, getAccessibleRelationSetFP, "getAccessibleRelationSet"); + + /* AccessibleHypertext */ + LOAD_FP(getAccessibleHypertext, getAccessibleHypertextFP, "getAccessibleHypertext"); + LOAD_FP(activateAccessibleHyperlink, activateAccessibleHyperlinkFP, "activateAccessibleHyperlink"); + LOAD_FP(getAccessibleHyperlinkCount, getAccessibleHyperlinkCountFP, "getAccessibleHyperlinkCount"); + LOAD_FP(getAccessibleHypertextExt, getAccessibleHypertextExtFP, "getAccessibleHypertextExt"); + LOAD_FP(getAccessibleHypertextLinkIndex, getAccessibleHypertextLinkIndexFP, "getAccessibleHypertextLinkIndex"); + LOAD_FP(getAccessibleHyperlink, getAccessibleHyperlinkFP, "getAccessibleHyperlink"); + + /* Accessible KeyBinding, Icon and Action */ + LOAD_FP(getAccessibleKeyBindings, getAccessibleKeyBindingsFP, "getAccessibleKeyBindings"); + LOAD_FP(getAccessibleIcons, getAccessibleIconsFP, "getAccessibleIcons"); + LOAD_FP(getAccessibleActions, getAccessibleActionsFP, "getAccessibleActions"); + LOAD_FP(doAccessibleActions, doAccessibleActionsFP, "doAccessibleActions"); + + /* AccessibleText */ + LOAD_FP(GetAccessibleTextInfo, GetAccessibleTextInfoFP, "getAccessibleTextInfo"); + LOAD_FP(GetAccessibleTextItems, GetAccessibleTextItemsFP, "getAccessibleTextItems"); + LOAD_FP(GetAccessibleTextSelectionInfo, GetAccessibleTextSelectionInfoFP, "getAccessibleTextSelectionInfo"); + LOAD_FP(GetAccessibleTextAttributes, GetAccessibleTextAttributesFP, "getAccessibleTextAttributes"); + LOAD_FP(GetAccessibleTextRect, GetAccessibleTextRectFP, "getAccessibleTextRect"); + LOAD_FP(GetAccessibleTextLineBounds, GetAccessibleTextLineBoundsFP, "getAccessibleTextLineBounds"); + LOAD_FP(GetAccessibleTextRange, GetAccessibleTextRangeFP, "getAccessibleTextRange"); + + LOAD_FP(GetCurrentAccessibleValueFromContext, GetCurrentAccessibleValueFromContextFP, "getCurrentAccessibleValueFromContext"); + LOAD_FP(GetMaximumAccessibleValueFromContext, GetMaximumAccessibleValueFromContextFP, "getMaximumAccessibleValueFromContext"); + LOAD_FP(GetMinimumAccessibleValueFromContext, GetMinimumAccessibleValueFromContextFP, "getMinimumAccessibleValueFromContext"); + + LOAD_FP(AddAccessibleSelectionFromContext, AddAccessibleSelectionFromContextFP, "addAccessibleSelectionFromContext"); + LOAD_FP(ClearAccessibleSelectionFromContext, ClearAccessibleSelectionFromContextFP, "clearAccessibleSelectionFromContext"); + LOAD_FP(GetAccessibleSelectionFromContext, GetAccessibleSelectionFromContextFP, "getAccessibleSelectionFromContext"); + LOAD_FP(GetAccessibleSelectionCountFromContext, GetAccessibleSelectionCountFromContextFP, "getAccessibleSelectionCountFromContext"); + LOAD_FP(IsAccessibleChildSelectedFromContext, IsAccessibleChildSelectedFromContextFP, "isAccessibleChildSelectedFromContext"); + LOAD_FP(RemoveAccessibleSelectionFromContext, RemoveAccessibleSelectionFromContextFP, "removeAccessibleSelectionFromContext"); + LOAD_FP(SelectAllAccessibleSelectionFromContext, SelectAllAccessibleSelectionFromContextFP, "selectAllAccessibleSelectionFromContext"); + + LOAD_FP(setTextContents, setTextContentsFP, "setTextContents"); + LOAD_FP(getParentWithRole, getParentWithRoleFP, "getParentWithRole"); + LOAD_FP(getTopLevelObject, getTopLevelObjectFP, "getTopLevelObject"); + LOAD_FP(getParentWithRoleElseRoot, getParentWithRoleElseRootFP, "getParentWithRoleElseRoot"); + LOAD_FP(getObjectDepth, getObjectDepthFP, "getObjectDepth"); + LOAD_FP(getActiveDescendent, getActiveDescendentFP, "getActiveDescendent"); + + // additional methods for Teton + LOAD_FP(getVirtualAccessibleName, getVirtualAccessibleNameFP, "getVirtualAccessibleName"); + LOAD_FP(requestFocus, requestFocusFP, "requestFocus"); + LOAD_FP(selectTextRange, selectTextRangeFP, "selectTextRange"); + LOAD_FP(getTextAttributesInRange, getTextAttributesInRangeFP, "getTextAttributesInRange"); + LOAD_FP(getVisibleChildrenCount, getVisibleChildrenCountFP, "getVisibleChildrenCount"); + LOAD_FP(getVisibleChildren, getVisibleChildrenFP, "getVisibleChildren"); + LOAD_FP(setCaretPosition, setCaretPositionFP, "setCaretPosition"); + LOAD_FP(getCaretLocation, getCaretLocationFP, "getCaretLocation"); + + LOAD_FP(getEventsWaiting, getEventsWaitingFP, "getEventsWaiting"); + + theAccessBridge.Windows_run(); + + theAccessBridgeInitializedFlag = TRUE; + PrintDebugString("theAccessBridgeInitializedFlag = TRUE"); + return TRUE; + } else { + return FALSE; + } + } + + + BOOL shutdownAccessBridge() { + BOOL result; + DWORD error; + theAccessBridgeInitializedFlag = FALSE; + if (theAccessBridgeInstance != (HANDLE) 0) { + result = FreeLibrary(theAccessBridgeInstance); + if (result != TRUE) { + error = GetLastError(); + } + return TRUE; + } + return FALSE; + } + + + void SetJavaShutdown(AccessBridge_JavaShutdownFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetJavaShutdown(fp); + } + } + + void SetFocusGained(AccessBridge_FocusGainedFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetFocusGained(fp); + } + } + + void SetFocusLost(AccessBridge_FocusLostFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetFocusLost(fp); + } + } + + + void SetCaretUpdate(AccessBridge_CaretUpdateFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetCaretUpdate(fp); + } + } + + + void SetMouseClicked(AccessBridge_MouseClickedFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetMouseClicked(fp); + } + } + + void SetMouseEntered(AccessBridge_MouseEnteredFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetMouseEntered(fp); + } + } + + void SetMouseExited(AccessBridge_MouseExitedFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetMouseExited(fp); + } + } + + void SetMousePressed(AccessBridge_MousePressedFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetMousePressed(fp); + } + } + + void SetMouseReleased(AccessBridge_MouseReleasedFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetMouseReleased(fp); + } + } + + + void SetMenuCanceled(AccessBridge_MenuCanceledFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetMenuCanceled(fp); + } + } + + void SetMenuDeselected(AccessBridge_MenuDeselectedFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetMenuDeselected(fp); + } + } + + void SetMenuSelected(AccessBridge_MenuSelectedFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetMenuSelected(fp); + } + } + + void SetPopupMenuCanceled(AccessBridge_PopupMenuCanceledFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPopupMenuCanceled(fp); + } + } + + void SetPopupMenuWillBecomeInvisible(AccessBridge_PopupMenuWillBecomeInvisibleFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPopupMenuWillBecomeInvisible(fp); + } + } + + void SetPopupMenuWillBecomeVisible(AccessBridge_PopupMenuWillBecomeVisibleFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPopupMenuWillBecomeVisible(fp); + } + } + + + void SetPropertyNameChange(AccessBridge_PropertyNameChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyNameChange(fp); + } + } + + void SetPropertyDescriptionChange(AccessBridge_PropertyDescriptionChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyDescriptionChange(fp); + } + } + + void SetPropertyStateChange(AccessBridge_PropertyStateChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyStateChange(fp); + } + } + + void SetPropertyValueChange(AccessBridge_PropertyValueChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyValueChange(fp); + } + } + + void SetPropertySelectionChange(AccessBridge_PropertySelectionChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertySelectionChange(fp); + } + } + + void SetPropertyTextChange(AccessBridge_PropertyTextChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyTextChange(fp); + } + } + + void SetPropertyCaretChange(AccessBridge_PropertyCaretChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyCaretChange(fp); + } + } + + void SetPropertyVisibleDataChange(AccessBridge_PropertyVisibleDataChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyVisibleDataChange(fp); + } + } + + void SetPropertyChildChange(AccessBridge_PropertyChildChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyChildChange(fp); + } + } + + void SetPropertyActiveDescendentChange(AccessBridge_PropertyActiveDescendentChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyActiveDescendentChange(fp); + } + } + + void SetPropertyTableModelChange(AccessBridge_PropertyTableModelChangeFP fp) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SetPropertyTableModelChange(fp); + } + } + + /** + * General routines + */ + void ReleaseJavaObject(long vmID, Java_Object object) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.ReleaseJavaObject(vmID, object); + } + } + + BOOL GetVersionInfo(long vmID, AccessBridgeVersionInfo *info) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetVersionInfo(vmID, info); + } + return FALSE; + } + + + /** + * Window routines + */ + BOOL IsJavaWindow(HWND window) { + if (theAccessBridgeInitializedFlag == TRUE) { + BOOL ret ; + ret = theAccessBridge.IsJavaWindow(window); + return ret ; + + } + return FALSE; + } + + + /** + * Returns the virtual machine ID and AccessibleContext for a top-level window + */ + BOOL GetAccessibleContextFromHWND(HWND target, long *vmID, AccessibleContext *ac) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleContextFromHWND(target, vmID, ac); + } + return FALSE; + } + + /** + * Returns the HWND from the AccessibleContext of a top-level window. Returns 0 + * on error or if the AccessibleContext does not refer to a top-level window. + */ + HWND getHWNDFromAccessibleContext(long vmID, JOBJECT64 accesibleContext) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getHWNDFromAccessibleContext(vmID, accesibleContext); + } + return (HWND)0; + } + + /** + * returns whether two objects are the same + */ + BOOL IsSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.IsSameObject(vmID, obj1, obj2); + } + return FALSE; + } + + /** + * Sets editable text contents. The AccessibleContext must implement AccessibleEditableText and + * be editable. The maximum text length is MAX_STRING_SIZE - 1. + * Returns whether successful + */ + BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.setTextContents(vmID, accessibleContext, text); + } + return FALSE; + } + + /** + * Returns the Accessible Context with the specified role that is the + * ancestor of a given object. The role is one of the role strings + * defined in AccessBridgePackages.h + * If there is no ancestor object that has the specified role, + * returns (AccessibleContext)0. + */ + AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext, + const wchar_t *role) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getParentWithRole(vmID, accessibleContext, role); + } + return (AccessibleContext)0; + } + + /** + * Returns the Accessible Context with the specified role that is the + * ancestor of a given object. The role is one of the role strings + * defined in AccessBridgePackages.h. If an object with the specified + * role does not exist, returns the top level object for the Java Window. + * Returns (AccessibleContext)0 on error. + */ + AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext, + const wchar_t *role) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getParentWithRoleElseRoot(vmID, accessibleContext, role); + } + return (AccessibleContext)0; + } + + /** + * Returns the Accessible Context for the top level object in + * a Java Window. This is same Accessible Context that is obtained + * from GetAccessibleContextFromHWND for that window. Returns + * (AccessibleContext)0 on error. + */ + AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getTopLevelObject(vmID, accessibleContext); + } + return (AccessibleContext)0; + } + + /** + * Returns how deep in the object hierarchy a given object is. + * The top most object in the object hierarchy has an object depth of 0. + * Returns -1 on error. + */ + int getObjectDepth (const long vmID, const AccessibleContext accessibleContext) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getObjectDepth(vmID, accessibleContext); + } + return -1; + } + + /** + * Returns the Accessible Context of the current ActiveDescendent of an object. + * This method assumes the ActiveDescendent is the component that is currently + * selected in a container object. + * Returns (AccessibleContext)0 on error or if there is no selection. + */ + AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getActiveDescendent(vmID, accessibleContext); + } + return (AccessibleContext)0; + } + + + /** + * Accessible Context routines + */ + BOOL GetAccessibleContextAt(long vmID, AccessibleContext acParent, + jint x, jint y, AccessibleContext *ac) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleContextAt(vmID, acParent, x, y, ac); + } + return FALSE; + } + + BOOL GetAccessibleContextWithFocus(HWND window, long *vmID, AccessibleContext *ac) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleContextWithFocus(window, vmID, ac); + } + return FALSE; + } + + BOOL GetAccessibleContextInfo(long vmID, AccessibleContext ac, AccessibleContextInfo *info) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleContextInfo(vmID, ac, info); + } + return FALSE; + } + + AccessibleContext GetAccessibleChildFromContext(long vmID, AccessibleContext ac, jint index) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleChildFromContext(vmID, ac, index); + } + return (AccessibleContext) 0; + } + + AccessibleContext GetAccessibleParentFromContext(long vmID, AccessibleContext ac) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleParentFromContext(vmID, ac); + } + return (AccessibleContext) 0; + } + + /* begin AccessibleTable routines */ + + /* + * get information about an AccessibleTable + */ + BOOL getAccessibleTableInfo(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableInfo(vmID, acParent, tableInfo); + } + return FALSE; + } + + /* + * get information about an AccessibleTable cell + */ + BOOL getAccessibleTableCellInfo(long vmID, AccessibleTable accessibleTable, + jint row, jint column, AccessibleTableCellInfo *tableCellInfo) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableCellInfo(vmID, accessibleTable, row, column, tableCellInfo); + } + return FALSE; + } + + /* + * get information about an AccessibleTable row header + */ + BOOL getAccessibleTableRowHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableRowHeader(vmID, acParent, tableInfo); + } + return FALSE; + } + + /* + * get information about an AccessibleTable column header + */ + BOOL getAccessibleTableColumnHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableColumnHeader(vmID, acParent, tableInfo); + } + return FALSE; + } + + /* + * return a description of an AccessibleTable row header + */ + AccessibleContext getAccessibleTableRowDescription(long vmID, AccessibleContext acParent, jint row) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableRowDescription(vmID, acParent, row); + } + return (AccessibleContext)0; + } + + /* + * return a description of an AccessibleTable column header + */ + AccessibleContext getAccessibleTableColumnDescription(long vmID, AccessibleContext acParent, jint column) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableColumnDescription(vmID, acParent, column); + } + return (AccessibleContext)0; + } + + /* + * return the number of rows selected in an AccessibleTable + */ + jint getAccessibleTableRowSelectionCount(long vmID, AccessibleTable table) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableRowSelectionCount(vmID, table); + } + return -1; + } + + /* + * return whether a row is selected in an AccessibleTable + */ + BOOL isAccessibleTableRowSelected(long vmID, AccessibleTable table, jint row) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.isAccessibleTableRowSelected(vmID, table, row); + } + return FALSE; + } + + /* + * get an array of selected rows in an AccessibleTable + */ + BOOL getAccessibleTableRowSelections(long vmID, AccessibleTable table, jint count, jint *selections) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableRowSelections(vmID, table, count, selections); + } + return FALSE; + } + + /* + * return the number of columns selected in an AccessibleTable + */ + jint getAccessibleTableColumnSelectionCount(long vmID, AccessibleTable table) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableColumnSelectionCount(vmID, table); + } + return -1; + } + + /* + * return whether a column is selected in an AccessibleTable + */ + BOOL isAccessibleTableColumnSelected(long vmID, AccessibleTable table, jint column) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.isAccessibleTableColumnSelected(vmID, table, column); + } + return FALSE; + } + + /* + * get an array of columns selected in an AccessibleTable + */ + BOOL getAccessibleTableColumnSelections(long vmID, AccessibleTable table, jint count, jint *selections) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableColumnSelections(vmID, table, count, selections); + } + return FALSE; + } + + /* + * return the row number for a cell at a given index + */ + jint + getAccessibleTableRow(long vmID, AccessibleTable table, jint index) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableRow(vmID, table, index); + } + return -1; + } + + /* + * return the column number for a cell at a given index + */ + jint + getAccessibleTableColumn(long vmID, AccessibleTable table, jint index) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableColumn(vmID, table, index); + } + return -1; + } + + /* + * return the index of a cell at a given row and column + */ + jint + getAccessibleTableIndex(long vmID, AccessibleTable table, jint row, jint column) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleTableIndex(vmID, table, row, column); + } + return -1; + } + + /* end AccessibleTable routines */ + + + /** + * Accessible Text routines + */ + BOOL GetAccessibleTextInfo(long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleTextInfo(vmID, at, textInfo, x, y); + } + return FALSE; + } + + BOOL GetAccessibleTextItems(long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleTextItems(vmID, at, textItems, index); + } + return FALSE; + } + + BOOL GetAccessibleTextSelectionInfo(long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleTextSelectionInfo(vmID, at, textSelection); + } + return FALSE; + } + + BOOL GetAccessibleTextAttributes(long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleTextAttributes(vmID, at, index, attributes); + } + return FALSE; + } + + BOOL GetAccessibleTextRect(long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleTextRect(vmID, at, rectInfo, index); + } + return FALSE; + } + + BOOL GetAccessibleTextLineBounds(long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleTextLineBounds(vmID, at, index, startIndex, endIndex); + } + return FALSE; + } + + BOOL GetAccessibleTextRange(long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleTextRange(vmID, at, start, end, text, len); + } + return FALSE; + } + + /** + * AccessibleRelationSet routines + */ + BOOL getAccessibleRelationSet(long vmID, AccessibleContext accessibleContext, + AccessibleRelationSetInfo *relationSetInfo) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleRelationSet(vmID, accessibleContext, relationSetInfo); + } + return FALSE; + } + + /** + * AccessibleHypertext routines + */ + + // Gets AccessibleHypertext for an AccessibleContext + BOOL getAccessibleHypertext(long vmID, AccessibleContext accessibleContext, + AccessibleHypertextInfo *hypertextInfo) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleHypertext(vmID, accessibleContext, hypertextInfo); + } + return FALSE; + } + + // Activates an AccessibleHyperlink for an AccessibleContext + BOOL activateAccessibleHyperlink(long vmID, AccessibleContext accessibleContext, + AccessibleHyperlink accessibleHyperlink) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.activateAccessibleHyperlink(vmID, accessibleContext, accessibleHyperlink); + } + return FALSE; + } + + /* + * Returns the number of hyperlinks in a component + * Maps to AccessibleHypertext.getLinkCount. + * Returns -1 on error. + */ + jint getAccessibleHyperlinkCount(const long vmID, + const AccessibleContext accessibleContext) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleHyperlinkCount(vmID, accessibleContext); + } + return -1; + } + + /* + * This method is used to iterate through the hyperlinks in a component. It + * returns hypertext information for a component starting at hyperlink index + * nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will + * be returned for each call to this method. + * returns FALSE on error. + */ + BOOL getAccessibleHypertextExt(const long vmID, + const AccessibleContext accessibleContext, + const jint nStartIndex, + /* OUT */ AccessibleHypertextInfo *hypertextInfo) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleHypertextExt(vmID, + accessibleContext, + nStartIndex, + hypertextInfo); + } + return FALSE; + } + + /* + * Returns the index into an array of hyperlinks that is associated with + * a character index in document; + * Maps to AccessibleHypertext.getLinkIndex. + * Returns -1 on error. + */ + jint getAccessibleHypertextLinkIndex(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleHypertextLinkIndex(vmID, + hypertext, + nIndex); + } + return -1; + } + + /* + * Returns the nth hyperlink in a document. + * Maps to AccessibleHypertext.getLink. + * Returns -1 on error + */ + BOOL getAccessibleHyperlink(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex, + /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo) { + + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleHyperlink(vmID, + hypertext, + nIndex, + hyperlinkInfo); + } + return FALSE; + } + + + /* Accessible KeyBindings, Icons and Actions */ + BOOL getAccessibleKeyBindings(long vmID, AccessibleContext accessibleContext, + AccessibleKeyBindings *keyBindings) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleKeyBindings(vmID, accessibleContext, keyBindings); + } + return FALSE; + } + + BOOL getAccessibleIcons(long vmID, AccessibleContext accessibleContext, + AccessibleIcons *icons) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleIcons(vmID, accessibleContext, icons); + } + return FALSE; + } + + BOOL getAccessibleActions(long vmID, AccessibleContext accessibleContext, + AccessibleActions *actions) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getAccessibleActions(vmID, accessibleContext, actions); + } + return FALSE; + } + + BOOL doAccessibleActions(long vmID, AccessibleContext accessibleContext, + AccessibleActionsToDo *actionsToDo, jint *failure) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.doAccessibleActions(vmID, accessibleContext, actionsToDo, failure); + } + return FALSE; + } + + /** + * Accessible Value routines + */ + BOOL GetCurrentAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetCurrentAccessibleValueFromContext(vmID, av, value, len); + } + return FALSE; + } + + BOOL GetMaximumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetMaximumAccessibleValueFromContext(vmID, av, value, len); + } + return FALSE; + } + + BOOL GetMinimumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetMinimumAccessibleValueFromContext(vmID, av, value, len); + } + return FALSE; + } + + + /** + * Accessible Selection routines + */ + void addAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.AddAccessibleSelectionFromContext(vmID, as, i); + } + } + + void clearAccessibleSelectionFromContext(long vmID, AccessibleSelection as) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.ClearAccessibleSelectionFromContext(vmID, as); + } + } + + JOBJECT64 GetAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleSelectionFromContext(vmID, as, i); + } + return (JOBJECT64) 0; + } + + int GetAccessibleSelectionCountFromContext(long vmID, AccessibleSelection as) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.GetAccessibleSelectionCountFromContext(vmID, as); + } + return -1; + } + + BOOL IsAccessibleChildSelectedFromContext(long vmID, AccessibleSelection as, int i) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.IsAccessibleChildSelectedFromContext(vmID, as, i); + } + return FALSE; + } + + void RemoveAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.RemoveAccessibleSelectionFromContext(vmID, as, i); + } + } + + void SelectAllAccessibleSelectionFromContext(long vmID, AccessibleSelection as) { + if (theAccessBridgeInitializedFlag == TRUE) { + theAccessBridge.SelectAllAccessibleSelectionFromContext(vmID, as); + } + } + + /** + * Additional methods for Teton + */ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + BOOL getVirtualAccessibleName(const long vmID, const AccessibleContext accessibleContext, + wchar_t *name, int len) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getVirtualAccessibleName(vmID, accessibleContext, name, len); + } + return FALSE; + } + + /** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ + BOOL requestFocus(const long vmID, const AccessibleContext accessibleContext) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.requestFocus(vmID, accessibleContext); + } + return FALSE; + } + + /** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ + BOOL selectTextRange(const long vmID, const AccessibleContext accessibleContext, + const int startIndex, const int endIndex) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.selectTextRange(vmID, accessibleContext, startIndex, endIndex); + } + return FALSE; + } + + /** + * Get text attributes between two indices. The attribute list includes the text at the + * start index and the text at the end index. Returns whether successful; + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + BOOL getTextAttributesInRange(const long vmID, const AccessibleContext accessibleContext, + const int startIndex, const int endIndex, + AccessibleTextAttributesInfo *attributes, short *len) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getTextAttributesInRange(vmID, accessibleContext, startIndex, + endIndex, attributes, len); + } + return FALSE; + } + + /** + * Returns the number of visible children of a component. Returns -1 on error. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + int getVisibleChildrenCount(const long vmID, const AccessibleContext accessibleContext) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getVisibleChildrenCount(vmID, accessibleContext); + } + return FALSE; + } + + /** + * Gets the visible children of an AccessibleContext. Returns whether successful; + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + BOOL getVisibleChildren(const long vmID, const AccessibleContext accessibleContext, + const int startIndex, VisibleChildrenInfo *visibleChildrenInfo) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getVisibleChildren(vmID, accessibleContext, startIndex, + visibleChildrenInfo); + } + return FALSE; + } + + /** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ + BOOL setCaretPosition(const long vmID, const AccessibleContext accessibleContext, + const int position) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.setCaretPosition(vmID, accessibleContext, position); + } + return FALSE; + } + + /** + * Gets the text caret location + */ + BOOL getCaretLocation(long vmID, AccessibleContext ac, AccessibleTextRectInfo *rectInfo, jint index) { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getCaretLocation(vmID, ac, rectInfo, index); + } + return FALSE; + } + + /** + * Gets the number of events waiting to fire + */ + int getEventsWaiting() { + if (theAccessBridgeInitializedFlag == TRUE) { + return theAccessBridge.getEventsWaiting(); + } + return FALSE; + } + +#ifdef __cplusplus +} +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/include/bridge/AccessBridgeCalls.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/include/bridge/AccessBridgeCalls.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,706 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * Wrapper functions around calls to the AccessBridge DLL + */ + +#include +#include +#include "AccessBridgeCallbacks.h" +#include "AccessBridgePackages.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define null NULL + + typedef JOBJECT64 AccessibleContext; + typedef JOBJECT64 AccessibleText; + typedef JOBJECT64 AccessibleValue; + typedef JOBJECT64 AccessibleSelection; + typedef JOBJECT64 Java_Object; + typedef JOBJECT64 PropertyChangeEvent; + typedef JOBJECT64 FocusEvent; + typedef JOBJECT64 CaretEvent; + typedef JOBJECT64 MouseEvent; + typedef JOBJECT64 MenuEvent; + typedef JOBJECT64 AccessibleTable; + typedef JOBJECT64 AccessibleHyperlink; + typedef JOBJECT64 AccessibleHypertext; + + + typedef void (*Windows_runFP) (); + + typedef void (*SetPropertyChangeFP) (AccessBridge_PropertyChangeFP fp); + + typedef void (*SetJavaShutdownFP) (AccessBridge_JavaShutdownFP fp); + typedef void (*SetFocusGainedFP) (AccessBridge_FocusGainedFP fp); + typedef void (*SetFocusLostFP) (AccessBridge_FocusLostFP fp); + + typedef void (*SetCaretUpdateFP) (AccessBridge_CaretUpdateFP fp); + + typedef void (*SetMouseClickedFP) (AccessBridge_MouseClickedFP fp); + typedef void (*SetMouseEnteredFP) (AccessBridge_MouseEnteredFP fp); + typedef void (*SetMouseExitedFP) (AccessBridge_MouseExitedFP fp); + typedef void (*SetMousePressedFP) (AccessBridge_MousePressedFP fp); + typedef void (*SetMouseReleasedFP) (AccessBridge_MouseReleasedFP fp); + + typedef void (*SetMenuCanceledFP) (AccessBridge_MenuCanceledFP fp); + typedef void (*SetMenuDeselectedFP) (AccessBridge_MenuDeselectedFP fp); + typedef void (*SetMenuSelectedFP) (AccessBridge_MenuSelectedFP fp); + typedef void (*SetPopupMenuCanceledFP) (AccessBridge_PopupMenuCanceledFP fp); + typedef void (*SetPopupMenuWillBecomeInvisibleFP) (AccessBridge_PopupMenuWillBecomeInvisibleFP fp); + typedef void (*SetPopupMenuWillBecomeVisibleFP) (AccessBridge_PopupMenuWillBecomeVisibleFP fp); + + typedef void (*SetPropertyNameChangeFP) (AccessBridge_PropertyNameChangeFP fp); + typedef void (*SetPropertyDescriptionChangeFP) (AccessBridge_PropertyDescriptionChangeFP fp); + typedef void (*SetPropertyStateChangeFP) (AccessBridge_PropertyStateChangeFP fp); + typedef void (*SetPropertyValueChangeFP) (AccessBridge_PropertyValueChangeFP fp); + typedef void (*SetPropertySelectionChangeFP) (AccessBridge_PropertySelectionChangeFP fp); + typedef void (*SetPropertyTextChangeFP) (AccessBridge_PropertyTextChangeFP fp); + typedef void (*SetPropertyCaretChangeFP) (AccessBridge_PropertyCaretChangeFP fp); + typedef void (*SetPropertyVisibleDataChangeFP) (AccessBridge_PropertyVisibleDataChangeFP fp); + typedef void (*SetPropertyChildChangeFP) (AccessBridge_PropertyChildChangeFP fp); + typedef void (*SetPropertyActiveDescendentChangeFP) (AccessBridge_PropertyActiveDescendentChangeFP fp); + + typedef void (*SetPropertyTableModelChangeFP) (AccessBridge_PropertyTableModelChangeFP fp); + + typedef void (*ReleaseJavaObjectFP) (long vmID, Java_Object object); + + typedef BOOL (*GetVersionInfoFP) (long vmID, AccessBridgeVersionInfo *info); + + typedef BOOL (*IsJavaWindowFP) (HWND window); + typedef BOOL (*IsSameObjectFP) (long vmID, JOBJECT64 obj1, JOBJECT64 obj2); + typedef BOOL (*GetAccessibleContextFromHWNDFP) (HWND window, long *vmID, AccessibleContext *ac); + typedef HWND (*getHWNDFromAccessibleContextFP) (long vmID, AccessibleContext ac); + + typedef BOOL (*GetAccessibleContextAtFP) (long vmID, AccessibleContext acParent, + jint x, jint y, AccessibleContext *ac); + typedef BOOL (*GetAccessibleContextWithFocusFP) (HWND window, long *vmID, AccessibleContext *ac); + typedef BOOL (*GetAccessibleContextInfoFP) (long vmID, AccessibleContext ac, AccessibleContextInfo *info); + typedef AccessibleContext (*GetAccessibleChildFromContextFP) (long vmID, AccessibleContext ac, jint i); + typedef AccessibleContext (*GetAccessibleParentFromContextFP) (long vmID, AccessibleContext ac); + + /* begin AccessibleTable */ + typedef BOOL (*getAccessibleTableInfoFP) (long vmID, AccessibleContext ac, AccessibleTableInfo *tableInfo); + typedef BOOL (*getAccessibleTableCellInfoFP) (long vmID, AccessibleTable accessibleTable, + jint row, jint column, AccessibleTableCellInfo *tableCellInfo); + + typedef BOOL (*getAccessibleTableRowHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + typedef BOOL (*getAccessibleTableColumnHeaderFP) (long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + + typedef AccessibleContext (*getAccessibleTableRowDescriptionFP) (long vmID, AccessibleContext acParent, jint row); + typedef AccessibleContext (*getAccessibleTableColumnDescriptionFP) (long vmID, AccessibleContext acParent, jint column); + + typedef jint (*getAccessibleTableRowSelectionCountFP) (long vmID, AccessibleTable table); + typedef BOOL (*isAccessibleTableRowSelectedFP) (long vmID, AccessibleTable table, jint row); + typedef BOOL (*getAccessibleTableRowSelectionsFP) (long vmID, AccessibleTable table, jint count, + jint *selections); + + typedef jint (*getAccessibleTableColumnSelectionCountFP) (long vmID, AccessibleTable table); + typedef BOOL (*isAccessibleTableColumnSelectedFP) (long vmID, AccessibleTable table, jint column); + typedef BOOL (*getAccessibleTableColumnSelectionsFP) (long vmID, AccessibleTable table, jint count, + jint *selections); + + typedef jint (*getAccessibleTableRowFP) (long vmID, AccessibleTable table, jint index); + typedef jint (*getAccessibleTableColumnFP) (long vmID, AccessibleTable table, jint index); + typedef jint (*getAccessibleTableIndexFP) (long vmID, AccessibleTable table, jint row, jint column); + /* end AccessibleTable */ + + /* AccessibleRelationSet */ + typedef BOOL (*getAccessibleRelationSetFP) (long vmID, AccessibleContext accessibleContext, + AccessibleRelationSetInfo *relationSetInfo); + + /* AccessibleHypertext */ + typedef BOOL (*getAccessibleHypertextFP)(long vmID, AccessibleContext accessibleContext, + AccessibleHypertextInfo *hypertextInfo); + + typedef BOOL (*activateAccessibleHyperlinkFP)(long vmID, AccessibleContext accessibleContext, + AccessibleHyperlink accessibleHyperlink); + + typedef jint (*getAccessibleHyperlinkCountFP)(const long vmID, + const AccessibleContext accessibleContext); + + typedef BOOL (*getAccessibleHypertextExtFP) (const long vmID, + const AccessibleContext accessibleContext, + const jint nStartIndex, + AccessibleHypertextInfo *hypertextInfo); + + typedef jint (*getAccessibleHypertextLinkIndexFP)(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex); + + typedef BOOL (*getAccessibleHyperlinkFP)(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex, + AccessibleHyperlinkInfo *hyperlinkInfo); + + + /* Accessible KeyBindings, Icons and Actions */ + typedef BOOL (*getAccessibleKeyBindingsFP)(long vmID, AccessibleContext accessibleContext, + AccessibleKeyBindings *keyBindings); + + typedef BOOL (*getAccessibleIconsFP)(long vmID, AccessibleContext accessibleContext, + AccessibleIcons *icons); + + typedef BOOL (*getAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext, + AccessibleActions *actions); + + typedef BOOL (*doAccessibleActionsFP)(long vmID, AccessibleContext accessibleContext, + AccessibleActionsToDo *actionsToDo, jint *failure); + + + /* AccessibleText */ + + typedef BOOL (*GetAccessibleTextInfoFP) (long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y); + typedef BOOL (*GetAccessibleTextItemsFP) (long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index); + typedef BOOL (*GetAccessibleTextSelectionInfoFP) (long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection); + typedef BOOL (*GetAccessibleTextAttributesFP) (long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes); + typedef BOOL (*GetAccessibleTextRectFP) (long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index); + typedef BOOL (*GetAccessibleTextLineBoundsFP) (long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex); + typedef BOOL (*GetAccessibleTextRangeFP) (long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len); + + typedef BOOL (*GetCurrentAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len); + typedef BOOL (*GetMaximumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len); + typedef BOOL (*GetMinimumAccessibleValueFromContextFP) (long vmID, AccessibleValue av, wchar_t *value, short len); + + typedef void (*AddAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i); + typedef void (*ClearAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as); + typedef JOBJECT64 (*GetAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i); + typedef int (*GetAccessibleSelectionCountFromContextFP) (long vmID, AccessibleSelection as); + typedef BOOL (*IsAccessibleChildSelectedFromContextFP) (long vmID, AccessibleSelection as, int i); + typedef void (*RemoveAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as, int i); + typedef void (*SelectAllAccessibleSelectionFromContextFP) (long vmID, AccessibleSelection as); + + /* Utility methods */ + + typedef BOOL (*setTextContentsFP) (const long vmID, const AccessibleContext ac, const wchar_t *text); + typedef AccessibleContext (*getParentWithRoleFP) (const long vmID, const AccessibleContext ac, const wchar_t *role); + typedef AccessibleContext (*getParentWithRoleElseRootFP) (const long vmID, const AccessibleContext ac, const wchar_t *role); + typedef AccessibleContext (*getTopLevelObjectFP) (const long vmID, const AccessibleContext ac); + typedef int (*getObjectDepthFP) (const long vmID, const AccessibleContext ac); + typedef AccessibleContext (*getActiveDescendentFP) (const long vmID, const AccessibleContext ac); + + + typedef BOOL (*getVirtualAccessibleNameFP) (const long vmID, const AccessibleContext accessibleContext, + wchar_t *name, int len); + + typedef BOOL (*requestFocusFP) (const long vmID, const AccessibleContext accessibleContext); + + typedef BOOL (*selectTextRangeFP) (const long vmID, const AccessibleContext accessibleContext, + const int startIndex, const int endIndex); + + typedef BOOL (*getTextAttributesInRangeFP) (const long vmID, const AccessibleContext accessibleContext, + const int startIndex, const int endIndex, + AccessibleTextAttributesInfo *attributes, short *len); + + typedef int (*getVisibleChildrenCountFP) (const long vmID, const AccessibleContext accessibleContext); + + typedef BOOL (*getVisibleChildrenFP) (const long vmID, const AccessibleContext accessibleContext, + const int startIndex, VisibleChildrenInfo *children); + + typedef BOOL (*setCaretPositionFP) (const long vmID, const AccessibleContext accessibleContext, const int position); + + typedef BOOL (*getCaretLocationFP) (long vmID, AccessibleContext ac, AccessibleTextRectInfo *rectInfo, jint index); + + typedef int (*getEventsWaitingFP) (); + + typedef struct AccessBridgeFPsTag { + Windows_runFP Windows_run; + + SetPropertyChangeFP SetPropertyChange; + + SetJavaShutdownFP SetJavaShutdown; + SetFocusGainedFP SetFocusGained; + SetFocusLostFP SetFocusLost; + + SetCaretUpdateFP SetCaretUpdate; + + SetMouseClickedFP SetMouseClicked; + SetMouseEnteredFP SetMouseEntered; + SetMouseExitedFP SetMouseExited; + SetMousePressedFP SetMousePressed; + SetMouseReleasedFP SetMouseReleased; + + SetMenuCanceledFP SetMenuCanceled; + SetMenuDeselectedFP SetMenuDeselected; + SetMenuSelectedFP SetMenuSelected; + SetPopupMenuCanceledFP SetPopupMenuCanceled; + SetPopupMenuWillBecomeInvisibleFP SetPopupMenuWillBecomeInvisible; + SetPopupMenuWillBecomeVisibleFP SetPopupMenuWillBecomeVisible; + + SetPropertyNameChangeFP SetPropertyNameChange; + SetPropertyDescriptionChangeFP SetPropertyDescriptionChange; + SetPropertyStateChangeFP SetPropertyStateChange; + SetPropertyValueChangeFP SetPropertyValueChange; + SetPropertySelectionChangeFP SetPropertySelectionChange; + SetPropertyTextChangeFP SetPropertyTextChange; + SetPropertyCaretChangeFP SetPropertyCaretChange; + SetPropertyVisibleDataChangeFP SetPropertyVisibleDataChange; + SetPropertyChildChangeFP SetPropertyChildChange; + SetPropertyActiveDescendentChangeFP SetPropertyActiveDescendentChange; + + SetPropertyTableModelChangeFP SetPropertyTableModelChange; + + ReleaseJavaObjectFP ReleaseJavaObject; + GetVersionInfoFP GetVersionInfo; + + IsJavaWindowFP IsJavaWindow; + IsSameObjectFP IsSameObject; + GetAccessibleContextFromHWNDFP GetAccessibleContextFromHWND; + getHWNDFromAccessibleContextFP getHWNDFromAccessibleContext; + + GetAccessibleContextAtFP GetAccessibleContextAt; + GetAccessibleContextWithFocusFP GetAccessibleContextWithFocus; + GetAccessibleContextInfoFP GetAccessibleContextInfo; + GetAccessibleChildFromContextFP GetAccessibleChildFromContext; + GetAccessibleParentFromContextFP GetAccessibleParentFromContext; + + getAccessibleTableInfoFP getAccessibleTableInfo; + getAccessibleTableCellInfoFP getAccessibleTableCellInfo; + + getAccessibleTableRowHeaderFP getAccessibleTableRowHeader; + getAccessibleTableColumnHeaderFP getAccessibleTableColumnHeader; + + getAccessibleTableRowDescriptionFP getAccessibleTableRowDescription; + getAccessibleTableColumnDescriptionFP getAccessibleTableColumnDescription; + + getAccessibleTableRowSelectionCountFP getAccessibleTableRowSelectionCount; + isAccessibleTableRowSelectedFP isAccessibleTableRowSelected; + getAccessibleTableRowSelectionsFP getAccessibleTableRowSelections; + + getAccessibleTableColumnSelectionCountFP getAccessibleTableColumnSelectionCount; + isAccessibleTableColumnSelectedFP isAccessibleTableColumnSelected; + getAccessibleTableColumnSelectionsFP getAccessibleTableColumnSelections; + + getAccessibleTableRowFP getAccessibleTableRow; + getAccessibleTableColumnFP getAccessibleTableColumn; + getAccessibleTableIndexFP getAccessibleTableIndex; + + getAccessibleRelationSetFP getAccessibleRelationSet; + + getAccessibleHypertextFP getAccessibleHypertext; + activateAccessibleHyperlinkFP activateAccessibleHyperlink; + getAccessibleHyperlinkCountFP getAccessibleHyperlinkCount; + getAccessibleHypertextExtFP getAccessibleHypertextExt; + getAccessibleHypertextLinkIndexFP getAccessibleHypertextLinkIndex; + getAccessibleHyperlinkFP getAccessibleHyperlink; + + getAccessibleKeyBindingsFP getAccessibleKeyBindings; + getAccessibleIconsFP getAccessibleIcons; + getAccessibleActionsFP getAccessibleActions; + doAccessibleActionsFP doAccessibleActions; + + GetAccessibleTextInfoFP GetAccessibleTextInfo; + GetAccessibleTextItemsFP GetAccessibleTextItems; + GetAccessibleTextSelectionInfoFP GetAccessibleTextSelectionInfo; + GetAccessibleTextAttributesFP GetAccessibleTextAttributes; + GetAccessibleTextRectFP GetAccessibleTextRect; + GetAccessibleTextLineBoundsFP GetAccessibleTextLineBounds; + GetAccessibleTextRangeFP GetAccessibleTextRange; + + GetCurrentAccessibleValueFromContextFP GetCurrentAccessibleValueFromContext; + GetMaximumAccessibleValueFromContextFP GetMaximumAccessibleValueFromContext; + GetMinimumAccessibleValueFromContextFP GetMinimumAccessibleValueFromContext; + + AddAccessibleSelectionFromContextFP AddAccessibleSelectionFromContext; + ClearAccessibleSelectionFromContextFP ClearAccessibleSelectionFromContext; + GetAccessibleSelectionFromContextFP GetAccessibleSelectionFromContext; + GetAccessibleSelectionCountFromContextFP GetAccessibleSelectionCountFromContext; + IsAccessibleChildSelectedFromContextFP IsAccessibleChildSelectedFromContext; + RemoveAccessibleSelectionFromContextFP RemoveAccessibleSelectionFromContext; + SelectAllAccessibleSelectionFromContextFP SelectAllAccessibleSelectionFromContext; + + setTextContentsFP setTextContents; + getParentWithRoleFP getParentWithRole; + getTopLevelObjectFP getTopLevelObject; + getParentWithRoleElseRootFP getParentWithRoleElseRoot; + getObjectDepthFP getObjectDepth; + getActiveDescendentFP getActiveDescendent; + + getVirtualAccessibleNameFP getVirtualAccessibleName; + requestFocusFP requestFocus; + selectTextRangeFP selectTextRange; + getTextAttributesInRangeFP getTextAttributesInRange; + getVisibleChildrenCountFP getVisibleChildrenCount; + getVisibleChildrenFP getVisibleChildren; + setCaretPositionFP setCaretPosition; + getCaretLocationFP getCaretLocation; + + getEventsWaitingFP getEventsWaiting; + + } AccessBridgeFPs; + + + /** + * Initialize the world + */ + BOOL initializeAccessBridge(); + BOOL shutdownAccessBridge(); + + /** + * Window routines + */ + BOOL IsJavaWindow(HWND window); + + // Returns the virtual machine ID and AccessibleContext for a top-level window + BOOL GetAccessibleContextFromHWND(HWND target, long *vmID, AccessibleContext *ac); + + // Returns the HWND from the AccessibleContext of a top-level window + HWND getHWNDFromAccessibleContext(long vmID, AccessibleContext ac); + + + /** + * Event handling routines + */ + void SetJavaShutdown(AccessBridge_JavaShutdownFP fp); + void SetFocusGained(AccessBridge_FocusGainedFP fp); + void SetFocusLost(AccessBridge_FocusLostFP fp); + + void SetCaretUpdate(AccessBridge_CaretUpdateFP fp); + + void SetMouseClicked(AccessBridge_MouseClickedFP fp); + void SetMouseEntered(AccessBridge_MouseEnteredFP fp); + void SetMouseExited(AccessBridge_MouseExitedFP fp); + void SetMousePressed(AccessBridge_MousePressedFP fp); + void SetMouseReleased(AccessBridge_MouseReleasedFP fp); + + void SetMenuCanceled(AccessBridge_MenuCanceledFP fp); + void SetMenuDeselected(AccessBridge_MenuDeselectedFP fp); + void SetMenuSelected(AccessBridge_MenuSelectedFP fp); + void SetPopupMenuCanceled(AccessBridge_PopupMenuCanceledFP fp); + void SetPopupMenuWillBecomeInvisible(AccessBridge_PopupMenuWillBecomeInvisibleFP fp); + void SetPopupMenuWillBecomeVisible(AccessBridge_PopupMenuWillBecomeVisibleFP fp); + + void SetPropertyNameChange(AccessBridge_PropertyNameChangeFP fp); + void SetPropertyDescriptionChange(AccessBridge_PropertyDescriptionChangeFP fp); + void SetPropertyStateChange(AccessBridge_PropertyStateChangeFP fp); + void SetPropertyValueChange(AccessBridge_PropertyValueChangeFP fp); + void SetPropertySelectionChange(AccessBridge_PropertySelectionChangeFP fp); + void SetPropertyTextChange(AccessBridge_PropertyTextChangeFP fp); + void SetPropertyCaretChange(AccessBridge_PropertyCaretChangeFP fp); + void SetPropertyVisibleDataChange(AccessBridge_PropertyVisibleDataChangeFP fp); + void SetPropertyChildChange(AccessBridge_PropertyChildChangeFP fp); + void SetPropertyActiveDescendentChange(AccessBridge_PropertyActiveDescendentChangeFP fp); + + void SetPropertyTableModelChange(AccessBridge_PropertyTableModelChangeFP fp); + + + /** + * General routines + */ + void ReleaseJavaObject(long vmID, Java_Object object); + BOOL GetVersionInfo(long vmID, AccessBridgeVersionInfo *info); + HWND GetHWNDFromAccessibleContext(long vmID, JOBJECT64 accesibleContext); + + /** + * Accessible Context routines + */ + BOOL GetAccessibleContextAt(long vmID, AccessibleContext acParent, + jint x, jint y, AccessibleContext *ac); + BOOL GetAccessibleContextWithFocus(HWND window, long *vmID, AccessibleContext *ac); + BOOL GetAccessibleContextInfo(long vmID, AccessibleContext ac, AccessibleContextInfo *info); + AccessibleContext GetAccessibleChildFromContext(long vmID, AccessibleContext ac, jint index); + AccessibleContext GetAccessibleParentFromContext(long vmID, AccessibleContext ac); + + /** + * Accessible Text routines + */ + BOOL GetAccessibleTextInfo(long vmID, AccessibleText at, AccessibleTextInfo *textInfo, jint x, jint y); + BOOL GetAccessibleTextItems(long vmID, AccessibleText at, AccessibleTextItemsInfo *textItems, jint index); + BOOL GetAccessibleTextSelectionInfo(long vmID, AccessibleText at, AccessibleTextSelectionInfo *textSelection); + BOOL GetAccessibleTextAttributes(long vmID, AccessibleText at, jint index, AccessibleTextAttributesInfo *attributes); + BOOL GetAccessibleTextRect(long vmID, AccessibleText at, AccessibleTextRectInfo *rectInfo, jint index); + BOOL GetAccessibleTextLineBounds(long vmID, AccessibleText at, jint index, jint *startIndex, jint *endIndex); + BOOL GetAccessibleTextRange(long vmID, AccessibleText at, jint start, jint end, wchar_t *text, short len); + + /* begin AccessibleTable routines */ + BOOL getAccessibleTableInfo(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + + BOOL getAccessibleTableCellInfo(long vmID, AccessibleTable accessibleTable, jint row, jint column, + AccessibleTableCellInfo *tableCellInfo); + + BOOL getAccessibleTableRowHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + BOOL getAccessibleTableColumnHeader(long vmID, AccessibleContext acParent, AccessibleTableInfo *tableInfo); + + AccessibleContext getAccessibleTableRowDescription(long vmID, AccessibleContext acParent, jint row); + AccessibleContext getAccessibleTableColumnDescription(long vmID, AccessibleContext acParent, jint column); + + jint getAccessibleTableRowSelectionCount(long vmID, AccessibleTable table); + BOOL isAccessibleTableRowSelected(long vmID, AccessibleTable table, jint row); + BOOL getAccessibleTableRowSelections(long vmID, AccessibleTable table, jint count, jint *selections); + + jint getAccessibleTableColumnSelectionCount(long vmID, AccessibleTable table); + BOOL isAccessibleTableColumnSelected(long vmID, AccessibleTable table, jint column); + BOOL getAccessibleTableColumnSelections(long vmID, AccessibleTable table, jint count, jint *selections); + + jint getAccessibleTableRow(long vmID, AccessibleTable table, jint index); + jint getAccessibleTableColumn(long vmID, AccessibleTable table, jint index); + jint getAccessibleTableIndex(long vmID, AccessibleTable table, jint row, jint column); + /* end AccessibleTable */ + + /* ----- AccessibleRelationSet routines */ + BOOL getAccessibleRelationSet(long vmID, AccessibleContext accessibleContext, + AccessibleRelationSetInfo *relationSetInfo); + + /* ----- AccessibleHypertext routines */ + + /* + * Returns hypertext information associated with a component. + */ + BOOL getAccessibleHypertext(long vmID, AccessibleContext accessibleContext, + AccessibleHypertextInfo *hypertextInfo); + + /* + * Requests that a hyperlink be activated. + */ + BOOL activateAccessibleHyperlink(long vmID, AccessibleContext accessibleContext, + AccessibleHyperlink accessibleHyperlink); + + /* + * Returns the number of hyperlinks in a component + * Maps to AccessibleHypertext.getLinkCount. + * Returns -1 on error. + */ + jint getAccessibleHyperlinkCount(const long vmID, + const AccessibleHypertext hypertext); + + /* + * This method is used to iterate through the hyperlinks in a component. It + * returns hypertext information for a component starting at hyperlink index + * nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will + * be returned for each call to this method. + * Returns FALSE on error. + */ + BOOL getAccessibleHypertextExt(const long vmID, + const AccessibleContext accessibleContext, + const jint nStartIndex, + /* OUT */ AccessibleHypertextInfo *hypertextInfo); + + /* + * Returns the index into an array of hyperlinks that is associated with + * a character index in document; maps to AccessibleHypertext.getLinkIndex + * Returns -1 on error. + */ + jint getAccessibleHypertextLinkIndex(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex); + + /* + * Returns the nth hyperlink in a document + * Maps to AccessibleHypertext.getLink. + * Returns FALSE on error + */ + BOOL getAccessibleHyperlink(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex, + /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo); + + /* Accessible KeyBindings, Icons and Actions */ + + /* + * Returns a list of key bindings associated with a component. + */ + BOOL getAccessibleKeyBindings(long vmID, AccessibleContext accessibleContext, + AccessibleKeyBindings *keyBindings); + + /* + * Returns a list of icons associate with a component. + */ + BOOL getAccessibleIcons(long vmID, AccessibleContext accessibleContext, + AccessibleIcons *icons); + + /* + * Returns a list of actions that a component can perform. + */ + BOOL getAccessibleActions(long vmID, AccessibleContext accessibleContext, + AccessibleActions *actions); + + /* + * Request that a list of AccessibleActions be performed by a component. + * Returns TRUE if all actions are performed. Returns FALSE + * when the first requested action fails in which case "failure" + * contains the index of the action that failed. + */ + BOOL doAccessibleActions(long vmID, AccessibleContext accessibleContext, + AccessibleActionsToDo *actionsToDo, jint *failure); + + + + /* Additional utility methods */ + + /* + * Returns whether two object references refer to the same object. + */ + BOOL IsSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2); + + /** + * Sets editable text contents. The AccessibleContext must implement AccessibleEditableText and + * be editable. The maximum text length that can be set is MAX_STRING_SIZE - 1. + * Returns whether successful + */ + BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text); + + /** + * Returns the Accessible Context with the specified role that is the + * ancestor of a given object. The role is one of the role strings + * defined in AccessBridgePackages.h + * If there is no ancestor object that has the specified role, + * returns (AccessibleContext)0. + */ + AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext, + const wchar_t *role); + + /** + * Returns the Accessible Context with the specified role that is the + * ancestor of a given object. The role is one of the role strings + * defined in AccessBridgePackages.h. If an object with the specified + * role does not exist, returns the top level object for the Java Window. + * Returns (AccessibleContext)0 on error. + */ + AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext, + const wchar_t *role); + + /** + * Returns the Accessible Context for the top level object in + * a Java Window. This is same Accessible Context that is obtained + * from GetAccessibleContextFromHWND for that window. Returns + * (AccessibleContext)0 on error. + */ + AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext); + + /** + * Returns how deep in the object hierarchy a given object is. + * The top most object in the object hierarchy has an object depth of 0. + * Returns -1 on error. + */ + int getObjectDepth (const long vmID, const AccessibleContext accessibleContext); + + /** + * Returns the Accessible Context of the current ActiveDescendent of an object. + * This method assumes the ActiveDescendent is the component that is currently + * selected in a container object. + * Returns (AccessibleContext)0 on error or if there is no selection. + */ + AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext); + + /** + /** + * Accessible Value routines + */ + BOOL GetCurrentAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len); + BOOL GetMaximumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len); + BOOL GetMinimumAccessibleValueFromContext(long vmID, AccessibleValue av, wchar_t *value, short len); + + /** + * Accessible Selection routines + */ + void AddAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i); + void ClearAccessibleSelectionFromContext(long vmID, AccessibleSelection as); + JOBJECT64 GetAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i); + int GetAccessibleSelectionCountFromContext(long vmID, AccessibleSelection as); + BOOL IsAccessibleChildSelectedFromContext(long vmID, AccessibleSelection as, int i); + void RemoveAccessibleSelectionFromContext(long vmID, AccessibleSelection as, int i); + void SelectAllAccessibleSelectionFromContext(long vmID, AccessibleSelection as); + + /** + * Additional methods for Teton + */ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + BOOL getVirtualAccessibleName(const long vmID, const AccessibleContext accessibleContext, + wchar_t *name, int len); + + /** + * Request focus for a component. Returns whether successful. + * + * Bug ID 4944757 - requestFocus method needed + */ + BOOL requestFocus(const long vmID, const AccessibleContext accessibleContext); + + /** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful. + * + * Bug ID 4944758 - selectTextRange method needed + */ + BOOL selectTextRange(const long vmID, const AccessibleContext accessibleContext, const int startIndex, + const int endIndex); + + /** + * Get text attributes between two indices. The attribute list includes the text at the + * start index and the text at the end index. Returns whether successful; + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + BOOL getTextAttributesInRange(const long vmID, const AccessibleContext accessibleContext, + const int startIndex, const int endIndex, + AccessibleTextAttributesInfo *attributes, short *len); + + /** + * Returns the number of visible children of a component. Returns -1 on error. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + int getVisibleChildrenCount(const long vmID, const AccessibleContext accessibleContext); + + /** + * Gets the visible children of an AccessibleContext. Returns whether successful. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + BOOL getVisibleChildren(const long vmID, const AccessibleContext accessibleContext, + const int startIndex, + VisibleChildrenInfo *visibleChildrenInfo); + + /** + * Set the caret to a text position. Returns whether successful. + * + * Bug ID 4944770 - setCaretPosition method needed + */ + BOOL setCaretPosition(const long vmID, const AccessibleContext accessibleContext, + const int position); + + /** + * Gets the text caret location + */ + BOOL getCaretLocation(long vmID, AccessibleContext ac, + AccessibleTextRectInfo *rectInfo, jint index); + + /** + * Gets the number of events waiting to fire + */ + int getEventsWaiting(); + +#ifdef __cplusplus +} +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/include/bridge/AccessBridgePackages.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/include/bridge/AccessBridgePackages.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,2215 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * Header file for packages of paramaters passed between Java Accessibility + * and native Assistive Technologies + */ + +#ifndef __AccessBridgePackages_H__ +#define __AccessBridgePackages_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef ACCESSBRIDGE_ARCH_LEGACY +typedef jobject JOBJECT64; +typedef HWND ABHWND64; +#define ABHandleToLong +#define ABLongToHandle +#else +typedef jlong JOBJECT64; +typedef long ABHWND64; +#define ABHandleToLong HandleToLong +#define ABLongToHandle LongToHandle +#endif + +#define MAX_BUFFER_SIZE 10240 +#define MAX_STRING_SIZE 1024 +#define SHORT_STRING_SIZE 256 + + // object types + typedef JOBJECT64 AccessibleContext; + typedef JOBJECT64 AccessibleText; + typedef JOBJECT64 AccessibleValue; + typedef JOBJECT64 AccessibleSelection; + typedef JOBJECT64 Java_Object; + typedef JOBJECT64 PropertyChangeEvent; + typedef JOBJECT64 FocusEvent; + typedef JOBJECT64 CaretEvent; + typedef JOBJECT64 MouseEvent; + typedef JOBJECT64 MenuEvent; + typedef JOBJECT64 AccessibleTable; + typedef JOBJECT64 AccessibleHyperlink; + typedef JOBJECT64 AccessibleHypertext; + + /** + ****************************************************** + * Java event types + ****************************************************** + */ + +#define cPropertyChangeEvent (jlong) 1 // 1 +#define cFocusGainedEvent (jlong) 2 // 2 +#define cFocusLostEvent (jlong) 4 // 4 +#define cCaretUpdateEvent (jlong) 8 // 8 +#define cMouseClickedEvent (jlong) 16 // 10 +#define cMouseEnteredEvent (jlong) 32 // 20 +#define cMouseExitedEvent (jlong) 64 // 40 +#define cMousePressedEvent (jlong) 128 // 80 +#define cMouseReleasedEvent (jlong) 256 // 100 +#define cMenuCanceledEvent (jlong) 512 // 200 +#define cMenuDeselectedEvent (jlong) 1024 // 400 +#define cMenuSelectedEvent (jlong) 2048 // 800 +#define cPopupMenuCanceledEvent (jlong) 4096 // 1000 +#define cPopupMenuWillBecomeInvisibleEvent (jlong) 8192 // 2000 +#define cPopupMenuWillBecomeVisibleEvent (jlong) 16384 // 4000 +#define cJavaShutdownEvent (jlong) 32768 // 8000 + + /** + ****************************************************** + * Accessible Roles + * Defines all AccessibleRoles in Local.US + ****************************************************** + */ + + /** + * Object is used to alert the user about something. + */ +#define ACCESSIBLE_ALERT L"alert" + + /** + * The header for a column of data. + */ +#define ACCESSIBLE_COLUMN_HEADER L"column header" + + /** + * Object that can be drawn into and is used to trap + * events. + * see ACCESSIBLE_FRAME + * see ACCESSIBLE_GLASS_PANE + * see ACCESSIBLE_LAYERED_PANE + */ +#define ACCESSIBLE_CANVAS L"canvas" + + /** + * A list of choices the user can select from. Also optionally + * allows the user to enter a choice of their own. + */ +#define ACCESSIBLE_COMBO_BOX L"combo box" + + /** + * An iconified internal frame in a DESKTOP_PANE. + * see ACCESSIBLE_DESKTOP_PANE + * see ACCESSIBLE_INTERNAL_FRAME + */ +#define ACCESSIBLE_DESKTOP_ICON L"desktop icon" + + /** + * A frame-like object that is clipped by a desktop pane. The + * desktop pane, internal frame, and desktop icon objects are + * often used to create multiple document interfaces within an + * application. + * see ACCESSIBLE_DESKTOP_ICON + * see ACCESSIBLE_DESKTOP_PANE + * see ACCESSIBLE_FRAME + */ +#define ACCESSIBLE_INTERNAL_FRAME L"internal frame" + + /** + * A pane that supports internal frames and + * iconified versions of those internal frames. + * see ACCESSIBLE_DESKTOP_ICON + * see ACCESSIBLE_INTERNAL_FRAME + */ +#define ACCESSIBLE_DESKTOP_PANE L"desktop pane" + + /** + * A specialized pane whose primary use is inside a DIALOG + * see ACCESSIBLE_DIALOG + */ +#define ACCESSIBLE_OPTION_PANE L"option pane" + + /** + * A top level window with no title or border. + * see ACCESSIBLE_FRAME + * see ACCESSIBLE_DIALOG + */ +#define ACCESSIBLE_WINDOW L"window" + + /** + * A top level window with a title bar, border, menu bar, etc. It is + * often used as the primary window for an application. + * see ACCESSIBLE_DIALOG + * see ACCESSIBLE_CANVAS + * see ACCESSIBLE_WINDOW + */ +#define ACCESSIBLE_FRAME L"frame" + + /** + * A top level window with title bar and a border. A dialog is similar + * to a frame, but it has fewer properties and is often used as a + * secondary window for an application. + * see ACCESSIBLE_FRAME + * see ACCESSIBLE_WINDOW + */ +#define ACCESSIBLE_DIALOG L"dialog" + + /** + * A specialized dialog that lets the user choose a color. + */ +#define ACCESSIBLE_COLOR_CHOOSER L"color chooser" + + + /** + * A pane that allows the user to navigate through + * and select the contents of a directory. May be used + * by a file chooser. + * see ACCESSIBLE_FILE_CHOOSER + */ +#define ACCESSIBLE_DIRECTORY_PANE L"directory pane" + + /** + * A specialized dialog that displays the files in the directory + * and lets the user select a file, browse a different directory, + * or specify a filename. May use the directory pane to show the + * contents of a directory. + * see ACCESSIBLE_DIRECTORY_PANE + */ +#define ACCESSIBLE_FILE_CHOOSER L"file chooser" + + /** + * An object that fills up space in a user interface. It is often + * used in interfaces to tweak the spacing between components, + * but serves no other purpose. + */ +#define ACCESSIBLE_FILLER L"filler" + + /** + * A hypertext anchor + */ +#define ACCESSIBLE_HYPERLINK L"hyperlink" + + /** + * A small fixed size picture, typically used to decorate components. + */ +#define ACCESSIBLE_ICON L"icon" + + /** + * An object used to present an icon or short string in an interface. + */ +#define ACCESSIBLE_LABEL L"label" + + /** + * A specialized pane that has a glass pane and a layered pane as its + * children. + * see ACCESSIBLE_GLASS_PANE + * see ACCESSIBLE_LAYERED_PANE + */ +#define ACCESSIBLE_ROOT_PANE L"root pane" + + /** + * A pane that is guaranteed to be painted on top + * of all panes beneath it. + * see ACCESSIBLE_ROOT_PANE + * see ACCESSIBLE_CANVAS + */ +#define ACCESSIBLE_GLASS_PANE L"glass pane" + + /** + * A specialized pane that allows its children to be drawn in layers, + * providing a form of stacking order. This is usually the pane that + * holds the menu bar as well as the pane that contains most of the + * visual components in a window. + * see ACCESSIBLE_GLASS_PANE + * see ACCESSIBLE_ROOT_PANE + */ +#define ACCESSIBLE_LAYERED_PANE L"layered pane" + + /** + * An object that presents a list of objects to the user and allows the + * user to select one or more of them. A list is usually contained + * within a scroll pane. + * see ACCESSIBLE_SCROLL_PANE + * see ACCESSIBLE_LIST_ITEM + */ +#define ACCESSIBLE_LIST L"list" + + /** + * An object that presents an element in a list. A list is usually + * contained within a scroll pane. + * see ACCESSIBLE_SCROLL_PANE + * see ACCESSIBLE_LIST + */ +#define ACCESSIBLE_LIST_ITEM L"list item" + + /** + * An object usually drawn at the top of the primary dialog box of + * an application that contains a list of menus the user can choose + * from. For example, a menu bar might contain menus for "File," + * "Edit," and "Help." + * see ACCESSIBLE_MENU + * see ACCESSIBLE_POPUP_MENU + * see ACCESSIBLE_LAYERED_PANE + */ +#define ACCESSIBLE_MENU_BAR L"menu bar" + + /** + * A temporary window that is usually used to offer the user a + * list of choices, and then hides when the user selects one of + * those choices. + * see ACCESSIBLE_MENU + * see ACCESSIBLE_MENU_ITEM + */ +#define ACCESSIBLE_POPUP_MENU L"popup menu" + + /** + * An object usually found inside a menu bar that contains a list + * of actions the user can choose from. A menu can have any object + * as its children, but most often they are menu items, other menus, + * or rudimentary objects such as radio buttons, check boxes, or + * separators. For example, an application may have an "Edit" menu + * that contains menu items for "Cut" and "Paste." + * see ACCESSIBLE_MENU_BAR + * see ACCESSIBLE_MENU_ITEM + * see ACCESSIBLE_SEPARATOR + * see ACCESSIBLE_RADIO_BUTTON + * see ACCESSIBLE_CHECK_BOX + * see ACCESSIBLE_POPUP_MENU + */ +#define ACCESSIBLE_MENU L"menu" + + /** + * An object usually contained in a menu that presents an action + * the user can choose. For example, the "Cut" menu item in an + * "Edit" menu would be an action the user can select to cut the + * selected area of text in a document. + * see ACCESSIBLE_MENU_BAR + * see ACCESSIBLE_SEPARATOR + * see ACCESSIBLE_POPUP_MENU + */ +#define ACCESSIBLE_MENU_ITEM L"menu item" + + /** + * An object usually contained in a menu to provide a visual + * and logical separation of the contents in a menu. For example, + * the "File" menu of an application might contain menu items for + * "Open," "Close," and "Exit," and will place a separator between + * "Close" and "Exit" menu items. + * see ACCESSIBLE_MENU + * see ACCESSIBLE_MENU_ITEM + */ +#define ACCESSIBLE_SEPARATOR L"separator" + + /** + * An object that presents a series of panels (or page tabs), one at a + * time, through some mechanism provided by the object. The most common + * mechanism is a list of tabs at the top of the panel. The children of + * a page tab list are all page tabs. + * see ACCESSIBLE_PAGE_TAB + */ +#define ACCESSIBLE_PAGE_TAB_LIST L"page tab list" + + /** + * An object that is a child of a page tab list. Its sole child is + * the panel that is to be presented to the user when the user + * selects the page tab from the list of tabs in the page tab list. + * see ACCESSIBLE_PAGE_TAB_LIST + */ +#define ACCESSIBLE_PAGE_TAB L"page tab" + + /** + * A generic container that is often used to group objects. + */ +#define ACCESSIBLE_PANEL L"panel" + + /** + * An object used to indicate how much of a task has been completed. + */ +#define ACCESSIBLE_PROGRESS_BAR L"progress bar" + + /** + * A text object used for passwords, or other places where the + * text contents is not shown visibly to the user + */ +#define ACCESSIBLE_PASSWORD_TEXT L"password text" + + /** + * An object the user can manipulate to tell the application to do + * something. + * see ACCESSIBLE_CHECK_BOX + * see ACCESSIBLE_TOGGLE_BUTTON + * see ACCESSIBLE_RADIO_BUTTON + */ +#define ACCESSIBLE_PUSH_BUTTON L"push button" + + /** + * A specialized push button that can be checked or unchecked, but + * does not provide a separate indicator for the current state. + * see ACCESSIBLE_PUSH_BUTTON + * see ACCESSIBLE_CHECK_BOX + * see ACCESSIBLE_RADIO_BUTTON + */ +#define ACCESSIBLE_TOGGLE_BUTTON L"toggle button" + + /** + * A choice that can be checked or unchecked and provides a + * separate indicator for the current state. + * see ACCESSIBLE_PUSH_BUTTON + * see ACCESSIBLE_TOGGLE_BUTTON + * see ACCESSIBLE_RADIO_BUTTON + */ +#define ACCESSIBLE_CHECK_BOX L"check box" + + /** + * A specialized check box that will cause other radio buttons in the + * same group to become unchecked when this one is checked. + * see ACCESSIBLE_PUSH_BUTTON + * see ACCESSIBLE_TOGGLE_BUTTON + * see ACCESSIBLE_CHECK_BOX + */ +#define ACCESSIBLE_RADIO_BUTTON L"radio button" + + /** + * The header for a row of data. + */ +#define ACCESSIBLE_ROW_HEADER L"row header" + + /** + * An object that allows a user to incrementally view a large amount + * of information. Its children can include scroll bars and a viewport. + * see ACCESSIBLE_SCROLL_BAR + * see ACCESSIBLE_VIEWPORT + */ +#define ACCESSIBLE_SCROLL_PANE L"scroll pane" + + /** + * An object usually used to allow a user to incrementally view a + * large amount of data. Usually used only by a scroll pane. + * see ACCESSIBLE_SCROLL_PANE + */ +#define ACCESSIBLE_SCROLL_BAR L"scroll bar" + + /** + * An object usually used in a scroll pane. It represents the portion + * of the entire data that the user can see. As the user manipulates + * the scroll bars, the contents of the viewport can change. + * see ACCESSIBLE_SCROLL_PANE + */ +#define ACCESSIBLE_VIEWPORT L"viewport" + + /** + * An object that allows the user to select from a bounded range. For + * example, a slider might be used to select a number between 0 and 100. + */ +#define ACCESSIBLE_SLIDER L"slider" + + /** + * A specialized panel that presents two other panels at the same time. + * Between the two panels is a divider the user can manipulate to make + * one panel larger and the other panel smaller. + */ +#define ACCESSIBLE_SPLIT_PANE L"split pane" + + /** + * An object used to present information in terms of rows and columns. + * An example might include a spreadsheet application. + */ +#define ACCESSIBLE_TABLE L"table" + + /** + * An object that presents text to the user. The text is usually + * editable by the user as opposed to a label. + * see ACCESSIBLE_LABEL + */ +#define ACCESSIBLE_TEXT L"text" + + /** + * An object used to present hierarchical information to the user. + * The individual nodes in the tree can be collapsed and expanded + * to provide selective disclosure of the tree's contents. + */ +#define ACCESSIBLE_TREE L"tree" + + /** + * A bar or palette usually composed of push buttons or toggle buttons. + * It is often used to provide the most frequently used functions for an + * application. + */ +#define ACCESSIBLE_TOOL_BAR L"tool bar" + + /** + * An object that provides information about another object. The + * accessibleDescription property of the tool tip is often displayed + * to the user in a small L"help bubble" when the user causes the + * mouse to hover over the object associated with the tool tip. + */ +#define ACCESSIBLE_TOOL_TIP L"tool tip" + + /** + * An AWT component, but nothing else is known about it. + * see ACCESSIBLE_SWING_COMPONENT + * see ACCESSIBLE_UNKNOWN + */ +#define ACCESSIBLE_AWT_COMPONENT L"awt component" + + /** + * A Swing component, but nothing else is known about it. + * see ACCESSIBLE_AWT_COMPONENT + * see ACCESSIBLE_UNKNOWN + */ +#define ACCESSIBLE_SWING_COMPONENT L"swing component" + + /** + * The object contains some Accessible information, but its role is + * not known. + * see ACCESSIBLE_AWT_COMPONENT + * see ACCESSIBLE_SWING_COMPONENT + */ +#define ACCESSIBLE_UNKNOWN L"unknown" + + /** + * A STATUS_BAR is an simple component that can contain + * multiple labels of status information to the user. + */ +#define ACCESSIBLE_STATUS_BAR L"status bar" + + /** + * A DATE_EDITOR is a component that allows users to edit + * java.util.Date and java.util.Time objects + */ +#define ACCESSIBLE_DATE_EDITOR L"date editor" + + /** + * A SPIN_BOX is a simple spinner component and its main use + * is for simple numbers. + */ +#define ACCESSIBLE_SPIN_BOX L"spin box" + + /** + * A FONT_CHOOSER is a component that lets the user pick various + * attributes for fonts. + */ +#define ACCESSIBLE_FONT_CHOOSER L"font chooser" + + /** + * A GROUP_BOX is a simple container that contains a border + * around it and contains components inside it. + */ +#define ACCESSIBLE_GROUP_BOX L"group box" + + /** + * A text header + */ +#define ACCESSIBLE_HEADER L"header" + + /** + * A text footer + */ +#define ACCESSIBLE_FOOTER L"footer" + + /** + * A text paragraph + */ +#define ACCESSIBLE_PARAGRAPH L"paragraph" + + /** + * A ruler is an object used to measure distance + */ +#define ACCESSIBLE_RULER L"ruler" + + /** + * A role indicating the object acts as a formula for + * calculating a value. An example is a formula in + * a spreadsheet cell. + */ +#define ACCESSIBLE_EDITBAR L"editbar" + + /** + * A role indicating the object monitors the progress + * of some operation. + */ +#define PROGRESS_MONITOR L"progress monitor" + + + /** + ****************************************************** + * Accessibility event types + ****************************************************** + */ + +#define cPropertyNameChangeEvent (jlong) 1 // 1 +#define cPropertyDescriptionChangeEvent (jlong) 2 // 2 +#define cPropertyStateChangeEvent (jlong) 4 // 4 +#define cPropertyValueChangeEvent (jlong) 8 // 8 +#define cPropertySelectionChangeEvent (jlong) 16 // 10 +#define cPropertyTextChangeEvent (jlong) 32 // 20 +#define cPropertyCaretChangeEvent (jlong) 64 // 40 +#define cPropertyVisibleDataChangeEvent (jlong) 128 // 80 +#define cPropertyChildChangeEvent (jlong) 256 // 100 +#define cPropertyActiveDescendentChangeEvent (jlong) 512 // 200 +#define cPropertyTableModelChangeEvent (jlong) 1024 // 400 + + /** + ****************************************************** + * optional AccessibleContext interfaces + * + * This version of the bridge reuses the accessibleValue + * field in the AccessibleContextInfo struct to represent + * additional optional interfaces that are supported by + * the Java AccessibleContext. This is backwardly compatable + * because the old accessibleValue was set to the BOOL + * value TRUE (i.e., 1) if the AccessibleValue interface is + * supported. + ****************************************************** + */ + +#define cAccessibleValueInterface (jlong) 1 // 1 << 1 (TRUE) +#define cAccessibleActionInterface (jlong) 2 // 1 << 2 +#define cAccessibleComponentInterface (jlong) 4 // 1 << 3 +#define cAccessibleSelectionInterface (jlong) 8 // 1 << 4 +#define cAccessibleTableInterface (jlong) 16 // 1 << 5 +#define cAccessibleTextInterface (jlong) 32 // 1 << 6 +#define cAccessibleHypertextInterface (jlong) 64 // 1 << 7 + + + /** + ****************************************************** + * Accessibility information bundles + ****************************************************** + */ + + typedef struct AccessBridgeVersionInfoTag { + wchar_t VMversion[SHORT_STRING_SIZE]; // output of "java -version" + wchar_t bridgeJavaClassVersion[SHORT_STRING_SIZE]; // version of the AccessBridge.class + wchar_t bridgeJavaDLLVersion[SHORT_STRING_SIZE]; // version of JavaAccessBridge.dll + wchar_t bridgeWinDLLVersion[SHORT_STRING_SIZE]; // version of WindowsAccessBridge.dll + } AccessBridgeVersionInfo; + + + typedef struct AccessibleContextInfoTag { + wchar_t name[MAX_STRING_SIZE]; // the AccessibleName of the object + wchar_t description[MAX_STRING_SIZE]; // the AccessibleDescription of the object + + wchar_t role[SHORT_STRING_SIZE]; // localized AccesibleRole string + wchar_t role_en_US[SHORT_STRING_SIZE]; // AccesibleRole string in the en_US locale + wchar_t states[SHORT_STRING_SIZE]; // localized AccesibleStateSet string (comma separated) + wchar_t states_en_US[SHORT_STRING_SIZE]; // AccesibleStateSet string in the en_US locale (comma separated) + + jint indexInParent; // index of object in parent + jint childrenCount; // # of children, if any + + jint x; // screen coords in pixels + jint y; // " + jint width; // pixel width of object + jint height; // pixel height of object + + BOOL accessibleComponent; // flags for various additional + BOOL accessibleAction; // Java Accessibility interfaces + BOOL accessibleSelection; // FALSE if this object doesn't + BOOL accessibleText; // implement the additional interface + // in question + + // BOOL accessibleValue; // old BOOL indicating whether AccessibleValue is supported + BOOL accessibleInterfaces; // new bitfield containing additional interface flags + + } AccessibleContextInfo; + + + + // AccessibleText packages + typedef struct AccessibleTextInfoTag { + jint charCount; // # of characters in this text object + jint caretIndex; // index of caret + jint indexAtPoint; // index at the passsed in point + } AccessibleTextInfo; + + typedef struct AccessibleTextItemsInfoTag { + wchar_t letter; + wchar_t word[SHORT_STRING_SIZE]; + wchar_t sentence[MAX_STRING_SIZE]; + } AccessibleTextItemsInfo; + + typedef struct AccessibleTextSelectionInfoTag { + jint selectionStartIndex; + jint selectionEndIndex; + wchar_t selectedText[MAX_STRING_SIZE]; + } AccessibleTextSelectionInfo; + + typedef struct AccessibleTextRectInfoTag { + jint x; // bounding rect of char at index + jint y; // " + jint width; // " + jint height; // " + } AccessibleTextRectInfo; + + // standard attributes for text; note: tabstops are not supported + typedef struct AccessibleTextAttributesInfoTag { + BOOL bold; + BOOL italic; + BOOL underline; + BOOL strikethrough; + BOOL superscript; + BOOL subscript; + + wchar_t backgroundColor[SHORT_STRING_SIZE]; + wchar_t foregroundColor[SHORT_STRING_SIZE]; + wchar_t fontFamily[SHORT_STRING_SIZE]; + jint fontSize; + + jint alignment; + jint bidiLevel; + + jfloat firstLineIndent; + jfloat leftIndent; + jfloat rightIndent; + jfloat lineSpacing; + jfloat spaceAbove; + jfloat spaceBelow; + + wchar_t fullAttributesString[MAX_STRING_SIZE]; + } AccessibleTextAttributesInfo; + + /** + ****************************************************** + * IPC management typedefs + ****************************************************** + */ + +#define cMemoryMappedNameSize 255 + + /** + * sent by the WindowsDLL -> the memory-mapped file is setup + * + */ + typedef struct MemoryMappedFileCreatedPackageTag { +// HWND bridgeWindow; // redundant, but easier to get to here... + ABHWND64 bridgeWindow; // redundant, but easier to get to here... + char filename[cMemoryMappedNameSize]; + } MemoryMappedFileCreatedPackage; + + + + + /** + * sent when a new JavaVM attaches to the Bridge + * + */ + typedef struct JavaVMCreatedPackageTag { + ABHWND64 bridgeWindow; + long vmID; + } JavaVMCreatedPackage; + + /** + * sent when a JavaVM detatches from the Bridge + * + */ + typedef struct JavaVMDestroyedPackageTag { + ABHWND64 bridgeWindow; + } JavaVMDestroyedPackage; + + /** + * sent when a new AT attaches to the Bridge + * + */ + typedef struct WindowsATCreatedPackageTag { + ABHWND64 bridgeWindow; + } WindowsATCreatedPackage; + + /** + * sent when an AT detatches from the Bridge + * + */ + typedef struct WindowsATDestroyedPackageTag { + ABHWND64 bridgeWindow; + } WindowsATDestroyedPackage; + + + /** + * sent by JVM Bridges in response to a WindowsATCreate + * message; saying "howdy, welcome to the neighborhood" + * + */ + typedef struct JavaVMPresentNotificationPackageTag { + ABHWND64 bridgeWindow; + long vmID; + } JavaVMPresentNotificationPackage; + + /** + * sent by AT Bridges in response to a JavaVMCreate + * message; saying "howdy, welcome to the neighborhood" + * + */ + typedef struct WindowsATPresentNotificationPackageTag { + ABHWND64 bridgeWindow; + } WindowsATPresentNotificationPackage; + + + /** + ****************************************************** + * Core packages + ****************************************************** + */ + + typedef struct ReleaseJavaObjectPackageTag { + long vmID; + JOBJECT64 object; + } ReleaseJavaObjectPackage; + + typedef struct GetAccessBridgeVersionPackageTag { + long vmID; // can't get VM info w/out a VM! + AccessBridgeVersionInfo rVersionInfo; + } GetAccessBridgeVersionPackage; + + typedef struct IsSameObjectPackageTag { + long vmID; + JOBJECT64 obj1; + JOBJECT64 obj2; + jboolean rResult; + } IsSameObjectPackage; + + /** + ****************************************************** + * Windows packages + ****************************************************** + */ + + typedef struct IsJavaWindowPackageTag { + jint window; + jboolean rResult; + } IsJavaWindowPackage; + + typedef struct GetAccessibleContextFromHWNDPackageTag { + jint window; + long rVMID; + JOBJECT64 rAccessibleContext; + } GetAccessibleContextFromHWNDPackage; + + typedef struct GetHWNDFromAccessibleContextPackageTag { + JOBJECT64 accessibleContext; + ABHWND64 rHWND; + } GetHWNDFromAccessibleContextPackage; + + /** +****************************************************** +* AccessibleContext packages +****************************************************** +*/ + + typedef struct GetAccessibleContextAtPackageTag { + jint x; + jint y; + long vmID; + JOBJECT64 AccessibleContext; // look within this AC + JOBJECT64 rAccessibleContext; + } GetAccessibleContextAtPackage; + + typedef struct GetAccessibleContextWithFocusPackageTag { + long rVMID; + JOBJECT64 rAccessibleContext; + } GetAccessibleContextWithFocusPackage; + + typedef struct GetAccessibleContextInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + AccessibleContextInfo rAccessibleContextInfo; + } GetAccessibleContextInfoPackage; + + typedef struct GetAccessibleChildFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint childIndex; + JOBJECT64 rAccessibleContext; + } GetAccessibleChildFromContextPackage; + + typedef struct GetAccessibleParentFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + JOBJECT64 rAccessibleContext; + } GetAccessibleParentFromContextPackage; + + /** +****************************************************** +* AccessibleTable packages +****************************************************** +*/ + +#define MAX_TABLE_SELECTIONS 64 + + // table information + typedef struct AccessibleTableInfoTag { + JOBJECT64 caption; // AccesibleContext + JOBJECT64 summary; // AccessibleContext + jint rowCount; + jint columnCount; + JOBJECT64 accessibleContext; + JOBJECT64 accessibleTable; + } AccessibleTableInfo; + + typedef struct GetAccessibleTableInfoPackageTag { + long vmID; + JOBJECT64 accessibleContext; + AccessibleTableInfo rTableInfo; + } GetAccessibleTableInfoPackage; + + // table cell information + typedef struct AccessibleTableCellInfoTag { + JOBJECT64 accessibleContext; + jint index; + jint row; + jint column; + jint rowExtent; + jint columnExtent; + jboolean isSelected; + } AccessibleTableCellInfo; + + typedef struct GetAccessibleTableCellInfoPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint row; + jint column; + AccessibleTableCellInfo rTableCellInfo; + } GetAccessibleTableCellInfoPackage; + + typedef struct GetAccessibleTableRowHeaderPackageTag { + long vmID; + JOBJECT64 accessibleContext; + AccessibleTableInfo rTableInfo; + } GetAccessibleTableRowHeaderPackage; + + typedef struct GetAccessibleTableColumnHeaderPackageTag { + long vmID; + JOBJECT64 accessibleContext; + AccessibleTableInfo rTableInfo; + } GetAccessibleTableColumnHeaderPackage; + + typedef struct GetAccessibleTableRowDescriptionPackageTag { + long vmID; + JOBJECT64 accessibleContext; + jint row; + JOBJECT64 rAccessibleContext; + } GetAccessibleTableRowDescriptionPackage; + + typedef struct GetAccessibleTableColumnDescriptionPackageTag { + long vmID; + JOBJECT64 accessibleContext; + jint column; + JOBJECT64 rAccessibleContext; + } GetAccessibleTableColumnDescriptionPackage; + + typedef struct GetAccessibleTableRowSelectionCountPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint rCount; + } GetAccessibleTableRowSelectionCountPackage; + + typedef struct IsAccessibleTableRowSelectedPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint row; + jboolean rResult; + } IsAccessibleTableRowSelectedPackage; + + typedef struct GetAccessibleTableRowSelectionsPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint count; + jint rSelections[MAX_TABLE_SELECTIONS]; + } GetAccessibleTableRowSelectionsPackage; + + typedef struct GetAccessibleTableColumnSelectionCountPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint rCount; + } GetAccessibleTableColumnSelectionCountPackage; + + typedef struct IsAccessibleTableColumnSelectedPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint column; + jboolean rResult; + } IsAccessibleTableColumnSelectedPackage; + + typedef struct GetAccessibleTableColumnSelectionsPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint count; + jint rSelections[MAX_TABLE_SELECTIONS]; + } GetAccessibleTableColumnSelectionsPackage; + + + typedef struct GetAccessibleTableRowPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint index; + jint rRow; + } GetAccessibleTableRowPackage; + + typedef struct GetAccessibleTableColumnPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint index; + jint rColumn; + } GetAccessibleTableColumnPackage; + + typedef struct GetAccessibleTableIndexPackageTag { + long vmID; + JOBJECT64 accessibleTable; + jint row; + jint column; + jint rIndex; + } GetAccessibleTableIndexPackage; + + + /** + ****************************************************** + * AccessibleRelationSet packages + ****************************************************** + */ + +#define MAX_RELATION_TARGETS 25 +#define MAX_RELATIONS 5 + + typedef struct AccessibleRelationInfoTag { + wchar_t key[SHORT_STRING_SIZE]; + jint targetCount; + JOBJECT64 targets[MAX_RELATION_TARGETS]; // AccessibleContexts + } AccessibleRelationInfo; + + typedef struct AccessibleRelationSetInfoTag { + jint relationCount; + AccessibleRelationInfo relations[MAX_RELATIONS]; + } AccessibleRelationSetInfo; + + typedef struct GetAccessibleRelationSetPackageTag { + long vmID; + JOBJECT64 accessibleContext; + AccessibleRelationSetInfo rAccessibleRelationSetInfo; + } GetAccessibleRelationSetPackage; + + /** + ****************************************************** + * AccessibleHypertext packagess + ****************************************************** + */ + +#define MAX_HYPERLINKS 64 // maximum number of hyperlinks returned + + // hyperlink information + typedef struct AccessibleHyperlinkInfoTag { + wchar_t text[SHORT_STRING_SIZE]; // the hyperlink text + jint startIndex; //index in the hypertext document where the link begins + jint endIndex; //index in the hypertext document where the link ends + JOBJECT64 accessibleHyperlink; // AccessibleHyperlink object + } AccessibleHyperlinkInfo; + + // hypertext information + typedef struct AccessibleHypertextInfoTag { + jint linkCount; // number of hyperlinks + AccessibleHyperlinkInfo links[MAX_HYPERLINKS]; // the hyperlinks + JOBJECT64 accessibleHypertext; // AccessibleHypertext object + } AccessibleHypertextInfo; + + // struct for sending a message to get the hypertext for an AccessibleContext + typedef struct GetAccessibleHypertextPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext with hypertext + AccessibleHypertextInfo rAccessibleHypertextInfo; // returned hypertext + } GetAccessibleHypertextPackage; + + // struct for sending an message to activate a hyperlink + typedef struct ActivateAccessibleHyperlinkPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext containing the link + JOBJECT64 accessibleHyperlink; // the link to activate + BOOL rResult; // hyperlink activation return value + } ActivateAccessibleHyperlinkPackage; + + // struct for sending a message to get the number of hyperlinks in a component + typedef struct GetAccessibleHyperlinkCountPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext containing AccessibleHypertext + jint rLinkCount; // link count return value + } GetAccessibleHyperlinkCountPackage; + + // struct for sending a message to get the hypertext for an AccessibleContext + // starting at a specified index in the document + typedef struct GetAccessibleHypertextExtPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext with hypertext + jint startIndex; // start index in document + AccessibleHypertextInfo rAccessibleHypertextInfo; // returned hypertext + BOOL rSuccess; // whether call succeeded + } GetAccessibleHypertextExtPackage; + + // struct for sending a message to get the nth hyperlink in a document; + // maps to AccessibleHypertext.getLink + typedef struct GetAccessibleHyperlinkPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 hypertext; // AccessibleHypertext + jint linkIndex; // hyperlink index + AccessibleHyperlinkInfo rAccessibleHyperlinkInfo; // returned hyperlink + } GetAccessibleHyperlinkPackage; + + // struct for sending a message to get the index into an array + // of hyperlinks that is associated with a character index in a + // document; maps to AccessibleHypertext.getLinkIndex + typedef struct GetAccessibleHypertextLinkIndexPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 hypertext; // AccessibleHypertext + jint charIndex; // character index in document + jint rLinkIndex; // returned hyperlink index + } GetAccessibleHypertextLinkIndexPackage; + + /** + ****************************************************** + * Accessible Key Bindings packages + ****************************************************** + */ + +#define MAX_KEY_BINDINGS 10 + + // keyboard character modifiers +#define ACCESSIBLE_SHIFT_KEYSTROKE 1 +#define ACCESSIBLE_CONTROL_KEYSTROKE 2 +#define ACCESSIBLE_META_KEYSTROKE 4 +#define ACCESSIBLE_ALT_KEYSTROKE 8 +#define ACCESSIBLE_ALT_GRAPH_KEYSTROKE 16 +#define ACCESSIBLE_BUTTON1_KEYSTROKE 32 +#define ACCESSIBLE_BUTTON2_KEYSTROKE 64 +#define ACCESSIBLE_BUTTON3_KEYSTROKE 128 +#define ACCESSIBLE_FKEY_KEYSTROKE 256 // F key pressed, character contains 1-24 +#define ACCESSIBLE_CONTROLCODE_KEYSTROKE 512 // Control code key pressed, character contains control code. + +// The supported control code keys are: +#define ACCESSIBLE_VK_BACK_SPACE 8 +#define ACCESSIBLE_VK_DELETE 127 +#define ACCESSIBLE_VK_DOWN 40 +#define ACCESSIBLE_VK_END 35 +#define ACCESSIBLE_VK_HOME 36 +#define ACCESSIBLE_VK_INSERT 155 +#define ACCESSIBLE_VK_KP_DOWN 225 +#define ACCESSIBLE_VK_KP_LEFT 226 +#define ACCESSIBLE_VK_KP_RIGHT 227 +#define ACCESSIBLE_VK_KP_UP 224 +#define ACCESSIBLE_VK_LEFT 37 +#define ACCESSIBLE_VK_PAGE_DOWN 34 +#define ACCESSIBLE_VK_PAGE_UP 33 +#define ACCESSIBLE_VK_RIGHT 39 +#define ACCESSIBLE_VK_UP 38 + + // a key binding associates with a component + typedef struct AccessibleKeyBindingInfoTag { + jchar character; // the key character + jint modifiers; // the key modifiers + } AccessibleKeyBindingInfo; + + // all of the key bindings associated with a component + typedef struct AccessibleKeyBindingsTag { + int keyBindingsCount; // number of key bindings + AccessibleKeyBindingInfo keyBindingInfo[MAX_KEY_BINDINGS]; + } AccessibleKeyBindings; + + // struct to get the key bindings associated with a component + typedef struct GetAccessibleKeyBindingsPackageTag { + long vmID; // the virtual machine id + JOBJECT64 accessibleContext; // the component + AccessibleKeyBindings rAccessibleKeyBindings; // the key bindings + } GetAccessibleKeyBindingsPackage; + + /** +****************************************************** +* AccessibleIcon packages +****************************************************** +*/ +#define MAX_ICON_INFO 8 + + // an icon assocated with a component + typedef struct AccessibleIconInfoTag { + wchar_t description[SHORT_STRING_SIZE]; // icon description + jint height; // icon height + jint width; // icon width + } AccessibleIconInfo; + + // all of the icons associated with a component + typedef struct AccessibleIconsTag { + jint iconsCount; // number of icons + AccessibleIconInfo iconInfo[MAX_ICON_INFO]; // the icons + } AccessibleIcons; + + // struct to get the icons associated with a component + typedef struct GetAccessibleIconsPackageTag { + long vmID; // the virtual machine id + JOBJECT64 accessibleContext; // the component + AccessibleIcons rAccessibleIcons; // the icons + } GetAccessibleIconsPackage; + + + /** +****************************************************** +* AccessibleAction packages +****************************************************** +*/ +#define MAX_ACTION_INFO 256 +#define MAX_ACTIONS_TO_DO 32 + + // an action assocated with a component + typedef struct AccessibleActionInfoTag { + wchar_t name[SHORT_STRING_SIZE]; // action name + } AccessibleActionInfo; + + // all of the actions associated with a component + typedef struct AccessibleActionsTag { + jint actionsCount; // number of actions + AccessibleActionInfo actionInfo[MAX_ACTION_INFO]; // the action information + } AccessibleActions; + + // struct for requesting the actions associated with a component + typedef struct GetAccessibleActionsPackageTag { + long vmID; + JOBJECT64 accessibleContext; // the component + AccessibleActions rAccessibleActions; // the actions + } GetAccessibleActionsPackage; + + // list of AccessibleActions to do + typedef struct AccessibleActionsToDoTag { + jint actionsCount; // number of actions to do + AccessibleActionInfo actions[MAX_ACTIONS_TO_DO];// the accessible actions to do + } AccessibleActionsToDo; + + // struct for sending an message to do one or more actions + typedef struct DoAccessibleActionsPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // component to do the action + AccessibleActionsToDo actionsToDo; // the accessible actions to do + BOOL rResult; // action return value + jint failure; // index of action that failed if rResult is FALSE + } DoAccessibleActionsPackage; + + /** +****************************************************** +* AccessibleText packages +****************************************************** +*/ + + typedef struct GetAccessibleTextInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint x; + jint y; + AccessibleTextInfo rTextInfo; + } GetAccessibleTextInfoPackage; + + typedef struct GetAccessibleTextItemsPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + AccessibleTextItemsInfo rTextItemsInfo; + } GetAccessibleTextItemsPackage; + + typedef struct GetAccessibleTextSelectionInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + AccessibleTextSelectionInfo rTextSelectionItemsInfo; + } GetAccessibleTextSelectionInfoPackage; + + typedef struct GetAccessibleTextAttributeInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + AccessibleTextAttributesInfo rAttributeInfo; + } GetAccessibleTextAttributeInfoPackage; + + typedef struct GetAccessibleTextRectInfoPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + AccessibleTextRectInfo rTextRectInfo; + } GetAccessibleTextRectInfoPackage; + + typedef struct GetCaretLocationPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + AccessibleTextRectInfo rTextRectInfo; + } GetCaretLocationPackage; + + typedef struct GetAccessibleTextLineBoundsPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + jint rLineStart; + jint rLineEnd; + } GetAccessibleTextLineBoundsPackage; + + typedef struct GetAccessibleTextRangePackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint start; + jint end; + wchar_t rText[MAX_BUFFER_SIZE]; + } GetAccessibleTextRangePackage; + + /** +****************************************************** +* +* Utility method packages +****************************************************** +*/ + + typedef struct SetTextContentsPackageTag { + long vmID; + JOBJECT64 accessibleContext; // the text field + wchar_t text[MAX_STRING_SIZE]; // the text + BOOL rResult; + } SetTextContentsPackage; + + typedef struct GetParentWithRolePackageTag { + long vmID; + JOBJECT64 accessibleContext; + wchar_t role[SHORT_STRING_SIZE]; // one of Accessible Roles above + JOBJECT64 rAccessibleContext; + } GetParentWithRolePackage; + + typedef struct GetTopLevelObjectPackageTag { + long vmID; + JOBJECT64 accessibleContext; + JOBJECT64 rAccessibleContext; + } GetTopLevelObjectPackage; + + typedef struct GetParentWithRoleElseRootPackageTag { + long vmID; + JOBJECT64 accessibleContext; + wchar_t role[SHORT_STRING_SIZE]; // one of Accessible Roles above + JOBJECT64 rAccessibleContext; + } GetParentWithRoleElseRootPackage; + + typedef struct GetObjectDepthPackageTag { + long vmID; + JOBJECT64 accessibleContext; + jint rResult; + } GetObjectDepthPackage; + + typedef struct GetActiveDescendentPackageTag { + long vmID; + JOBJECT64 accessibleContext; + JOBJECT64 rAccessibleContext; + } GetActiveDescendentPackage; + + /** +****************************************************** +* AccessibleValue packages +****************************************************** +*/ + + typedef struct GetCurrentAccessibleValueFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + wchar_t rValue[SHORT_STRING_SIZE]; + } GetCurrentAccessibleValueFromContextPackage; + + typedef struct GetMaximumAccessibleValueFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + wchar_t rValue[SHORT_STRING_SIZE]; + } GetMaximumAccessibleValueFromContextPackage; + + typedef struct GetMinimumAccessibleValueFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + wchar_t rValue[SHORT_STRING_SIZE]; + } GetMinimumAccessibleValueFromContextPackage; + + + /** +****************************************************** +* AccessibleSelection packages +****************************************************** +*/ + + typedef struct AddAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + } AddAccessibleSelectionFromContextPackage; + + typedef struct ClearAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + } ClearAccessibleSelectionFromContextPackage; + + typedef struct GetAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + JOBJECT64 rAccessibleContext; + } GetAccessibleSelectionFromContextPackage; + + typedef struct GetAccessibleSelectionCountFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint rCount; + } GetAccessibleSelectionCountFromContextPackage; + + typedef struct IsAccessibleChildSelectedFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + jboolean rResult; + } IsAccessibleChildSelectedFromContextPackage; + + typedef struct RemoveAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + jint index; + } RemoveAccessibleSelectionFromContextPackage; + + typedef struct SelectAllAccessibleSelectionFromContextPackageTag { + long vmID; + JOBJECT64 AccessibleContext; + } SelectAllAccessibleSelectionFromContextPackage; + + + /** +****************************************************** +* Java Event Notification Registration packages +****************************************************** +*/ + + typedef struct AddJavaEventNotificationPackageTag { + jlong type; + //HWND DLLwindow; + ABHWND64 DLLwindow; + } AddJavaEventNotificationPackage; + + typedef struct RemoveJavaEventNotificationPackageTag { + jlong type; + //HWND DLLwindow; + ABHWND64 DLLwindow; + } RemoveJavaEventNotificationPackage; + + + /** +****************************************************** +* Accessibility Event Notification Registration packages +****************************************************** +*/ + + typedef struct AddAccessibilityEventNotificationPackageTag { + jlong type; + //HWND DLLwindow; + ABHWND64 DLLwindow; + } AddAccessibilityEventNotificationPackage; + + typedef struct RemoveAccessibilityEventNotificationPackageTag { + jlong type; + //HWND DLLwindow; + ABHWND64 DLLwindow; + } RemoveAccessibilityEventNotificationPackage; + + + /** +****************************************************** +* Accessibility Property Change Event packages +****************************************************** +*/ + + typedef struct PropertyCaretChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + jint oldPosition; + jint newPosition; + } PropertyCaretChangePackage; + + typedef struct PropertyDescriptionChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldDescription[SHORT_STRING_SIZE]; + wchar_t newDescription[SHORT_STRING_SIZE]; + } PropertyDescriptionChangePackage; + + typedef struct PropertyNameChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldName[SHORT_STRING_SIZE]; + wchar_t newName[SHORT_STRING_SIZE]; + } PropertyNameChangePackage; + + typedef struct PropertySelectionChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PropertySelectionChangePackage; + + typedef struct PropertyStateChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldState[SHORT_STRING_SIZE]; + wchar_t newState[SHORT_STRING_SIZE]; + } PropertyStateChangePackage; + + typedef struct PropertyTextChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PropertyTextChangePackage; + + typedef struct PropertyValueChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldValue[SHORT_STRING_SIZE]; + wchar_t newValue[SHORT_STRING_SIZE]; + } PropertyValueChangePackage; + + typedef struct PropertyVisibleDataChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PropertyVisibleDataChangePackage; + + typedef struct PropertyChildChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + JOBJECT64 oldChildAccessibleContext; + JOBJECT64 newChildAccessibleContext; + } PropertyChildChangePackage; + + typedef struct PropertyActiveDescendentChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + JOBJECT64 oldActiveDescendentAccessibleContext; + JOBJECT64 newActiveDescendentAccessibleContext; + } PropertyActiveDescendentChangePackage; + + + // String format for newValue is: + // "type" one of "INSERT", "UPDATE" or "DELETE" + // "firstRow" + // "lastRow" + // "firstColumn" + // "lastColumn" + // + // oldValue is currently unused + // + typedef struct PropertyTableModelChangePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + wchar_t oldValue[SHORT_STRING_SIZE]; + wchar_t newValue[SHORT_STRING_SIZE]; + } PropertyTableModelChangePackage; + + + /** +****************************************************** +* Property Change Event packages +****************************************************** +*/ + + /* + typedef struct PropertyChangePackageTag { + long vmID; + jobject Event; + jobject AccessibleContextSource; + char propertyName[SHORT_STRING_SIZE]; + char oldValue[SHORT_STRING_SIZE]; // PropertyChangeEvent().getOldValue().toString() + char newValue[SHORT_STRING_SIZE]; // PropertyChangeEvent().getNewValue().toString() + } PropertyChangePackage; + */ + + /* + * Java shutdown event package + */ + typedef struct JavaShutdownPackageTag { + long vmID; + } JavaShutdownPackage; + + + /** +****************************************************** +* Focus Event packages +****************************************************** +*/ + + typedef struct FocusGainedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } FocusGainedPackage; + + typedef struct FocusLostPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } FocusLostPackage; + + + /** +****************************************************** +* Caret Event packages +****************************************************** +*/ + + typedef struct CaretUpdatePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } CaretUpdatePackage; + + + /** +****************************************************** +* Mouse Event packages +****************************************************** +*/ + + typedef struct MouseClickedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MouseClickedPackage; + + typedef struct MouseEnteredPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MouseEnteredPackage; + + typedef struct MouseExitedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MouseExitedPackage; + + typedef struct MousePressedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MousePressedPackage; + + typedef struct MouseReleasedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MouseReleasedPackage; + + + /** +****************************************************** +* Menu/PopupMenu Event packages +****************************************************** +*/ + + typedef struct MenuCanceledPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MenuCanceledPackage; + + typedef struct MenuDeselectedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MenuDeselectedPackage; + + typedef struct MenuSelectedPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } MenuSelectedPackage; + + + typedef struct PopupMenuCanceledPackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PopupMenuCanceledPackage; + + typedef struct PopupMenuWillBecomeInvisiblePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PopupMenuWillBecomeInvisiblePackage; + + typedef struct PopupMenuWillBecomeVisiblePackageTag { + long vmID; + JOBJECT64 Event; + JOBJECT64 AccessibleContextSource; + } PopupMenuWillBecomeVisiblePackage; + + /** +****************************************************** +* Additional methods for Teton +****************************************************** +*/ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + typedef struct GetVirtualAccessibleNamePackageTag { + long vmID; + AccessibleContext accessibleContext; + wchar_t rName[MAX_STRING_SIZE]; + int len; + } GetVirtualAccessibleNamePackage; + + /** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ + typedef struct RequestFocusPackageTag { + long vmID; + AccessibleContext accessibleContext; + } RequestFocusPackage; + + /** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ + typedef struct SelectTextRangePackageTag { + long vmID; + AccessibleContext accessibleContext; + jint startIndex; + jint endIndex; + } SelectTextRangePackage; + + /** + * Gets the number of contiguous characters with the same attributes. + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + typedef struct GetTextAttributesInRangePackageTag { + long vmID; + AccessibleContext accessibleContext; + jint startIndex; // start index (inclusive) + jint endIndex; // end index (inclusive) + AccessibleTextAttributesInfo attributes; // character attributes to match + short rLength; // number of contiguous characters with matching attributes + } GetTextAttributesInRangePackage; + +#define MAX_VISIBLE_CHILDREN 256 + + // visible children information + typedef struct VisibleChildenInfoTag { + int returnedChildrenCount; // number of children returned + AccessibleContext children[MAX_VISIBLE_CHILDREN]; // the visible children + } VisibleChildrenInfo; + + // struct for sending a message to get the number of visible children + typedef struct GetVisibleChildrenCountPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext of parent component + jint rChildrenCount; // visible children count return value + } GetVisibleChildrenCountPackage; + + // struct for sending a message to get the hypertext for an AccessibleContext + // starting at a specified index in the document + typedef struct GetVisibleChildrenPackageTag { + long vmID; // the virtual machine ID + JOBJECT64 accessibleContext; // AccessibleContext of parent component + jint startIndex; // start index for retrieving children + VisibleChildrenInfo rVisibleChildrenInfo; // returned info + BOOL rSuccess; // whether call succeeded + } GetVisibleChildrenPackage; + + /** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ + typedef struct SetCaretPositionPackageTag { + long vmID; + AccessibleContext accessibleContext; + jint position; + } SetCaretPositionPackage; + + + /** + ****************************************************** + * Wrapping up all of the packages + ****************************************************** + */ + + /** + * What is the type of this package + */ + typedef enum PackageType { + + cMemoryMappedFileCreatedPackage = 0x11000, + + // many of these will go away... + cJavaVMCreatedPackage = 0x10000, + cJavaVMDestroyedPackage, + cWindowsATCreatedPackage, + cWindowsATDestroyedPackage, + cJavaVMPresentNotificationPackage, + cWindowsATPresentNotificationPackage, + + cReleaseJavaObjectPackage = 1, + cGetAccessBridgeVersionPackage = 2, + + cGetAccessibleContextFromHWNDPackage = 0x10, + cIsJavaWindowPackage, + cGetHWNDFromAccessibleContextPackage, + + cGetAccessibleContextAtPackage = 0x100, + cGetAccessibleContextWithFocusPackage, + cGetAccessibleContextInfoPackage, + cGetAccessibleChildFromContextPackage, + cGetAccessibleParentFromContextPackage, + cIsSameObjectPackage, + + cGetAccessibleTextInfoPackage = 0x200, + cGetAccessibleTextItemsPackage, + cGetAccessibleTextSelectionInfoPackage, + cGetAccessibleTextAttributeInfoPackage, + cGetAccessibleTextRectInfoPackage, + cGetAccessibleTextLineBoundsPackage, + cGetAccessibleTextRangePackage, + + cGetCurrentAccessibleValueFromContextPackage = 0x300, + cGetMaximumAccessibleValueFromContextPackage, + cGetMinimumAccessibleValueFromContextPackage, + + cAddAccessibleSelectionFromContextPackage = 0x400, + cClearAccessibleSelectionFromContextPackage, + cGetAccessibleSelectionFromContextPackage, + cGetAccessibleSelectionCountFromContextPackage, + cIsAccessibleChildSelectedFromContextPackage, + cRemoveAccessibleSelectionFromContextPackage, + cSelectAllAccessibleSelectionFromContextPackage, + + cAddJavaEventNotificationPackage = 0x900, + cRemoveJavaEventNotificationPackage, + cAddAccessibilityEventNotificationPackage, + cRemoveAccessibilityEventNotificationPackage, + + cPropertyChangePackage = 0x1000, + + cJavaShutdownPackage = 0x1010, + cFocusGainedPackage, + cFocusLostPackage, + + cCaretUpdatePackage = 0x1020, + + cMouseClickedPackage = 0x1030, + cMouseEnteredPackage, + cMouseExitedPackage, + cMousePressedPackage, + cMouseReleasedPackage, + + cMenuCanceledPackage = 0x1040, + cMenuDeselectedPackage, + cMenuSelectedPackage, + cPopupMenuCanceledPackage, + cPopupMenuWillBecomeInvisiblePackage, + cPopupMenuWillBecomeVisiblePackage, + + cPropertyCaretChangePackage = 0x1100, + cPropertyDescriptionChangePackage, + cPropertyNameChangePackage, + cPropertySelectionChangePackage, + cPropertyStateChangePackage, + cPropertyTextChangePackage, + cPropertyValueChangePackage, + cPropertyVisibleDataChangePackage, + cPropertyChildChangePackage, + cPropertyActiveDescendentChangePackage, + + + // AccessibleTable + cGetAccessibleTableInfoPackage = 0x1200, + cGetAccessibleTableCellInfoPackage, + + cGetAccessibleTableRowHeaderPackage, + cGetAccessibleTableColumnHeaderPackage, + + cGetAccessibleTableRowDescriptionPackage, + cGetAccessibleTableColumnDescriptionPackage, + + cGetAccessibleTableRowSelectionCountPackage, + cIsAccessibleTableRowSelectedPackage, + cGetAccessibleTableRowSelectionsPackage, + + cGetAccessibleTableColumnSelectionCountPackage, + cIsAccessibleTableColumnSelectedPackage, + cGetAccessibleTableColumnSelectionsPackage, + + cGetAccessibleTableRowPackage, + cGetAccessibleTableColumnPackage, + cGetAccessibleTableIndexPackage, + + cPropertyTableModelChangePackage, + + + // AccessibleRelationSet + cGetAccessibleRelationSetPackage = 0x1300, + + // AccessibleHypertext + cGetAccessibleHypertextPackage = 0x1400, + cActivateAccessibleHyperlinkPackage, + cGetAccessibleHyperlinkCountPackage, + cGetAccessibleHypertextExtPackage, + cGetAccessibleHypertextLinkIndexPackage, + cGetAccessibleHyperlinkPackage, + + // Accessible KeyBinding, Icon and Action + cGetAccessibleKeyBindingsPackage = 0x1500, + cGetAccessibleIconsPackage, + cGetAccessibleActionsPackage, + cDoAccessibleActionsPackage, + + // Utility methods + cSetTextContentsPackage = 0x1600, + cGetParentWithRolePackage, + cGetTopLevelObjectPackage, + cGetParentWithRoleElseRootPackage, + cGetObjectDepthPackage, + cGetActiveDescendentPackage, + + // Additional methods for Teton + cGetVirtualAccessibleNamePackage = 0x1700, + cRequestFocusPackage, + cSelectTextRangePackage, + cGetTextAttributesInRangePackage, + cGetSameTextAttributesInRangePackage, + cGetVisibleChildrenCountPackage, + cGetVisibleChildrenPackage, + cSetCaretPositionPackage, + cGetCaretLocationPackage + + + } PackageType; + + + /** + * Union of all package contents + */ + typedef union AllPackagesTag { + + // Initial Rendezvous packages + MemoryMappedFileCreatedPackage memoryMappedFileCreatedPackage; + + JavaVMCreatedPackage javaVMCreatedPackage; + JavaVMDestroyedPackage javaVMDestroyedPackage; + WindowsATCreatedPackage windowsATCreatedPackage; + WindowsATDestroyedPackage windowsATDestroyedPackage; + JavaVMPresentNotificationPackage javaVMPresentNotificationPackage; + WindowsATPresentNotificationPackage windowsATPresentNotificationPackage; + + // Core packages + ReleaseJavaObjectPackage releaseJavaObject; + GetAccessBridgeVersionPackage getAccessBridgeVersion; + + // Window packages + GetAccessibleContextFromHWNDPackage getAccessibleContextFromHWND; + GetHWNDFromAccessibleContextPackage getHWNDFromAccessibleContext; + + // AccessibleContext packages + GetAccessibleContextAtPackage getAccessibleContextAt; + GetAccessibleContextWithFocusPackage getAccessibleContextWithFocus; + GetAccessibleContextInfoPackage getAccessibleContextInfo; + GetAccessibleChildFromContextPackage getAccessibleChildFromContext; + GetAccessibleParentFromContextPackage getAccessibleParentFromContext; + + // AccessibleText packages + GetAccessibleTextInfoPackage getAccessibleTextInfo; + GetAccessibleTextItemsPackage getAccessibleTextItems; + GetAccessibleTextSelectionInfoPackage getAccessibleTextSelectionInfo; + GetAccessibleTextAttributeInfoPackage getAccessibleTextAttributeInfo; + GetAccessibleTextRectInfoPackage getAccessibleTextRectInfo; + GetAccessibleTextLineBoundsPackage getAccessibleTextLineBounds; + GetAccessibleTextRangePackage getAccessibleTextRange; + + // AccessibleValue packages + GetCurrentAccessibleValueFromContextPackage getCurrentAccessibleValueFromContext; + GetMaximumAccessibleValueFromContextPackage getMaximumAccessibleValueFromContext; + GetMinimumAccessibleValueFromContextPackage getMinimumAccessibleValueFromContext; + + // AccessibleSelection packages + AddAccessibleSelectionFromContextPackage addAccessibleSelectionFromContext; + ClearAccessibleSelectionFromContextPackage clearAccessibleSelectionFromContext; + GetAccessibleSelectionFromContextPackage getAccessibleSelectionFromContext; + GetAccessibleSelectionCountFromContextPackage getAccessibleSelectionCountFromContext; + IsAccessibleChildSelectedFromContextPackage isAccessibleChildSelectedFromContext; + RemoveAccessibleSelectionFromContextPackage removeAccessibleSelectionFromContext; + SelectAllAccessibleSelectionFromContextPackage selectAllAccessibleSelectionFromContext; + + // Event Notification Registration packages + AddJavaEventNotificationPackage addJavaEventNotification; + RemoveJavaEventNotificationPackage removeJavaEventNotification; + AddAccessibilityEventNotificationPackage addAccessibilityEventNotification; + RemoveAccessibilityEventNotificationPackage removeAccessibilityEventNotification; + + // Event contents packages + // PropertyChangePackage propertyChange; + PropertyCaretChangePackage propertyCaretChangePackage; + PropertyDescriptionChangePackage propertyDescriptionChangePackage; + PropertyNameChangePackage propertyNameChangePackage; + PropertySelectionChangePackage propertySelectionChangePackage; + PropertyStateChangePackage propertyStateChangePackage; + PropertyTextChangePackage propertyTextChangePackage; + PropertyValueChangePackage propertyValueChangePackage; + PropertyVisibleDataChangePackage propertyVisibleDataChangePackage; + PropertyChildChangePackage propertyChildChangePackage; + PropertyActiveDescendentChangePackage propertyActiveDescendentChangePackage; + + PropertyTableModelChangePackage propertyTableModelChangePackage; + + JavaShutdownPackage JavaShutdown; + FocusGainedPackage focusGained; + FocusLostPackage focusLost; + + CaretUpdatePackage caretUpdate; + + MouseClickedPackage mouseClicked; + MouseEnteredPackage mouseEntered; + MouseExitedPackage mouseExited; + MousePressedPackage mousePressed; + MouseReleasedPackage mouseReleased; + + MenuCanceledPackage menuCanceled; + MenuDeselectedPackage menuDeselected; + MenuSelectedPackage menuSelected; + PopupMenuCanceledPackage popupMenuCanceled; + PopupMenuWillBecomeInvisiblePackage popupMenuWillBecomeInvisible; + PopupMenuWillBecomeVisiblePackage popupMenuWillBecomeVisible; + + // AccessibleRelationSet + GetAccessibleRelationSetPackage getAccessibleRelationSet; + + // AccessibleHypertext + GetAccessibleHypertextPackage _getAccessibleHypertext; + ActivateAccessibleHyperlinkPackage _activateAccessibleHyperlink; + GetAccessibleHyperlinkCountPackage _getAccessibleHyperlinkCount; + GetAccessibleHypertextExtPackage _getAccessibleHypertextExt; + GetAccessibleHypertextLinkIndexPackage _getAccessibleHypertextLinkIndex; + GetAccessibleHyperlinkPackage _getAccessibleHyperlink; + + // Accessible KeyBinding, Icon and Action + GetAccessibleKeyBindingsPackage getAccessibleKeyBindings; + GetAccessibleIconsPackage getAccessibleIcons; + GetAccessibleActionsPackage getAccessibleActions; + DoAccessibleActionsPackage doAccessibleActions; + + // utility methods + SetTextContentsPackage _setTextContents; + GetParentWithRolePackage _getParentWithRole; + GetTopLevelObjectPackage _getTopLevelObject; + GetParentWithRoleElseRootPackage _getParentWithRoleElseRoot; + GetObjectDepthPackage _getObjectDepth; + GetActiveDescendentPackage _getActiveDescendent; + + // Additional methods for Teton + GetVirtualAccessibleNamePackage _getVirtualAccessibleName; + RequestFocusPackage _requestFocus; + SelectTextRangePackage _selectTextRange; + GetTextAttributesInRangePackage _getTextAttributesInRange; + GetVisibleChildrenCountPackage _getVisibleChildrenCount; + GetVisibleChildrenPackage _getVisibleChildren; + SetCaretPositionPackage _setCaretPosition; + + } AllPackages; + + + /** + * Union of all Java-initiated package contents + */ + typedef union JavaInitiatedPackagesTag { + + // Initial Rendezvous packages + JavaVMCreatedPackage javaVMCreatedPackage; + JavaVMDestroyedPackage javaVMDestroyedPackage; + JavaVMPresentNotificationPackage javaVMPresentNotificationPackage; + + // Event contents packages + PropertyCaretChangePackage propertyCaretChangePackage; + PropertyDescriptionChangePackage propertyDescriptionChangePackage; + PropertyNameChangePackage propertyNameChangePackage; + PropertySelectionChangePackage propertySelectionChangePackage; + PropertyStateChangePackage propertyStateChangePackage; + PropertyTextChangePackage propertyTextChangePackage; + PropertyValueChangePackage propertyValueChangePackage; + PropertyVisibleDataChangePackage propertyVisibleDataChangePackage; + PropertyChildChangePackage propertyChildChangePackage; + PropertyActiveDescendentChangePackage propertyActiveDescendentChangePackage; + + PropertyTableModelChangePackage propertyTableModelChangePackage; + + JavaShutdownPackage JavaShutdown; + FocusGainedPackage focusGained; + FocusLostPackage focusLost; + + CaretUpdatePackage caretUpdate; + + MouseClickedPackage mouseClicked; + MouseEnteredPackage mouseEntered; + MouseExitedPackage mouseExited; + MousePressedPackage mousePressed; + MouseReleasedPackage mouseReleased; + + MenuCanceledPackage menuCanceled; + MenuDeselectedPackage menuDeselected; + MenuSelectedPackage menuSelected; + PopupMenuCanceledPackage popupMenuCanceled; + PopupMenuWillBecomeInvisiblePackage popupMenuWillBecomeInvisible; + PopupMenuWillBecomeVisiblePackage popupMenuWillBecomeVisible; + + } JavaInitiatedPackages; + + + /** + * Union of all Windows-initiated package contents + */ + typedef union WindowsInitiatedPackagesTag { + + // Initial Rendezvous packages + MemoryMappedFileCreatedPackage memoryMappedFileCreatedPackage; + + WindowsATCreatedPackage windowsATCreatedPackage; + WindowsATDestroyedPackage windowsATDestroyedPackage; + WindowsATPresentNotificationPackage windowsATPresentNotificationPackage; + + // Core packages + ReleaseJavaObjectPackage releaseJavaObject; + GetAccessBridgeVersionPackage getAccessBridgeVersion; + + // Window packages + GetAccessibleContextFromHWNDPackage getAccessibleContextFromHWND; + GetHWNDFromAccessibleContextPackage getHWNDFromAccessibleContext; + + // AccessibleContext packages + GetAccessibleContextAtPackage getAccessibleContextAt; + GetAccessibleContextWithFocusPackage getAccessibleContextWithFocus; + GetAccessibleContextInfoPackage getAccessibleContextInfo; + GetAccessibleChildFromContextPackage getAccessibleChildFromContext; + GetAccessibleParentFromContextPackage getAccessibleParentFromContext; + + // AccessibleText packages + GetAccessibleTextInfoPackage getAccessibleTextInfo; + GetAccessibleTextItemsPackage getAccessibleTextItems; + GetAccessibleTextSelectionInfoPackage getAccessibleTextSelectionInfo; + GetAccessibleTextAttributeInfoPackage getAccessibleTextAttributeInfo; + GetAccessibleTextRectInfoPackage getAccessibleTextRectInfo; + GetAccessibleTextLineBoundsPackage getAccessibleTextLineBounds; + GetAccessibleTextRangePackage getAccessibleTextRange; + + // AccessibleValue packages + GetCurrentAccessibleValueFromContextPackage getCurrentAccessibleValueFromContext; + GetMaximumAccessibleValueFromContextPackage getMaximumAccessibleValueFromContext; + GetMinimumAccessibleValueFromContextPackage getMinimumAccessibleValueFromContext; + + // AccessibleSelection packages + AddAccessibleSelectionFromContextPackage addAccessibleSelectionFromContext; + ClearAccessibleSelectionFromContextPackage clearAccessibleSelectionFromContext; + GetAccessibleSelectionFromContextPackage getAccessibleSelectionFromContext; + GetAccessibleSelectionCountFromContextPackage getAccessibleSelectionCountFromContext; + IsAccessibleChildSelectedFromContextPackage isAccessibleChildSelectedFromContext; + RemoveAccessibleSelectionFromContextPackage removeAccessibleSelectionFromContext; + SelectAllAccessibleSelectionFromContextPackage selectAllAccessibleSelectionFromContext; + + // Event Notification Registration packages + AddJavaEventNotificationPackage addJavaEventNotification; + RemoveJavaEventNotificationPackage removeJavaEventNotification; + AddAccessibilityEventNotificationPackage addAccessibilityEventNotification; + RemoveAccessibilityEventNotificationPackage removeAccessibilityEventNotification; + + // AccessibleTable + GetAccessibleTableInfoPackage _getAccessibleTableInfo; + GetAccessibleTableCellInfoPackage _getAccessibleTableCellInfo; + + GetAccessibleTableRowHeaderPackage _getAccessibleTableRowHeader; + GetAccessibleTableColumnHeaderPackage _getAccessibleTableColumnHeader; + + GetAccessibleTableRowDescriptionPackage _getAccessibleTableRowDescription; + GetAccessibleTableColumnDescriptionPackage _getAccessibleTableColumnDescription; + + GetAccessibleTableRowSelectionCountPackage _getAccessibleTableRowSelectionCount; + IsAccessibleTableRowSelectedPackage _isAccessibleTableRowSelected; + GetAccessibleTableRowSelectionsPackage _getAccessibleTableRowSelections; + + GetAccessibleTableColumnSelectionCountPackage _getAccessibleTableColumnSelectionCount; + IsAccessibleTableColumnSelectedPackage _isAccessibleTableColumnSelected; + GetAccessibleTableColumnSelectionsPackage _getAccessibleTableColumnSelections; + + GetAccessibleTableRowPackage _getAccessibleTableRow; + GetAccessibleTableColumnPackage _getAccessibleTableColumn; + GetAccessibleTableIndexPackage _getAccessibleTableIndex; + + // AccessibleRelationSet + GetAccessibleRelationSetPackage _getAccessibleRelationSet; + + // Accessible KeyBindings, Icons and Actions + GetAccessibleKeyBindingsPackage _getAccessibleKeyBindings; + GetAccessibleIconsPackage _getAccessibleIcons; + GetAccessibleActionsPackage _getAccessibleActions; + DoAccessibleActionsPackage _doAccessibleActions; + + + IsSameObjectPackage _isSameObject; + + // utility methods + SetTextContentsPackage _setTextContents; + GetParentWithRolePackage _getParentWithRole; + GetTopLevelObjectPackage _getTopLevelObject; + GetParentWithRoleElseRootPackage _getParentWithRoleElseRoot; + GetObjectDepthPackage _getObjectDepth; + GetActiveDescendentPackage _getActiveDescendent; + + // Additional methods for Teton + GetVirtualAccessibleNamePackage _getVirtualAccessibleName; + RequestFocusPackage _requestFocus; + SelectTextRangePackage _selectTextRange; + GetTextAttributesInRangePackage _getTextAttributesInRange; + GetVisibleChildrenCountPackage _getVisibleChildrenCount; + GetVisibleChildrenPackage _getVisibleChildren; + SetCaretPositionPackage _setCaretPosition; + + + } WindowsInitiatedPackages; + + +#ifdef __cplusplus +} +#endif + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/jabswitch/jabswitch.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/jabswitch/jabswitch.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,475 @@ +/* + * Copyright (c) 2012, 2015, 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. + */ + +#include +#include +#include +#include +#include +#include + +// This is the default buffer size used for RegQueryValue values. +#define DEFAULT_ALLOC MAX_PATH +// only allocate a buffer as big as MAX_ALLOC for RegQueryValue values. +#define MAX_ALLOC 262144 + +static LPCTSTR ACCESSIBILITY_USER_KEY = + _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility"); +static LPCTSTR ACCESSIBILITY_SYSTEM_KEY = + _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\Session"); +static LPCTSTR ACCESSIBILITY_CONFIG = + _T("Configuration"); +static LPCTSTR STR_ACCESSBRIDGE = + _T("oracle_javaaccessbridge"); + +// Note: There are senarios where more than one extension can be specified on the +// asssistive_technologies= +// line but this code only deals with the case of +// assistive_technologies=com.sun.java.accessibility.AccessBridge +// assuming that if additional extensions are desired the user knows how edit the file. + +FILE* origFile; +FILE* tempFile; + +bool isXP() +{ + static bool isXPFlag = false; + OSVERSIONINFO osvi; + + // Initialize the OSVERSIONINFO structure. + ZeroMemory( &osvi, sizeof( osvi ) ); + osvi.dwOSVersionInfoSize = sizeof( osvi ); + + GetVersionEx( &osvi ); + + if ( osvi.dwMajorVersion == 5 ) // For Windows XP and Windows 2000 + isXPFlag = true; + + return isXPFlag ; +} + +void enableJAB() { + // Copy lines from orig to temp modifying the line containing + // assistive_technologies= + // There are various scenarios: + // 1) If the line exists exactly as + // #assistive_technologies=com.sun.java.accessibility.AccessBridge + // replace it with + // assistive_technologies=com.sun.java.accessibility.AccessBridge + // 2) else if the line exists exactly as + // assistive_technologies=com.sun.java.accessibility.AccessBridge + // use it as is + // 3) else if a line containing "assistive_technologies" exits + // a) if it's already commented out, us it as is (jab will be enabled in step 4) + // b) else if it's not commented out, comment it out and add a new line with + // assistive_technologies=com.sun.java.accessibility.AccessBridge + // 4) If the line doesn't exist (or case 3a), add + // assistive_technologies=com.sun.java.accessibility.AccessBridge + // Do the same for screen_magnifier_present= + char line[512]; + char commentLine[512] = "#"; + char jabLine[] = "assistive_technologies=com.sun.java.accessibility.AccessBridge\n"; + char magLine[] = "screen_magnifier_present=true\n"; + bool foundJabLine = false; + bool foundMagLine = false; + while (!feof(origFile)) { + if (fgets(line, 512, origFile) != NULL) { + if (_stricmp(line, "#assistive_technologies=com.sun.java.accessibility.AccessBridge\n") == 0) { + fputs(jabLine, tempFile); + foundJabLine = true; + } else if (_stricmp(line, jabLine) == 0) { + fputs(line, tempFile); + foundJabLine = true; + } else if (strstr(line, "assistive_technologies") != NULL) { + char* context; + char* firstNonSpaceChar = strtok_s(line, " ", &context); + if (*firstNonSpaceChar == '#') { + fputs(line, tempFile); + } else { + strcat_s(commentLine, line); + fputs(commentLine, tempFile); + fputs(jabLine, tempFile); + foundJabLine = true; + } + } else if (_stricmp(line, "#screen_magnifier_present=true\n") == 0) { + fputs(magLine, tempFile); + foundMagLine = true; + } else if (_stricmp(line, magLine) == 0) { + fputs(line, tempFile); + foundMagLine = true; + } else if (strstr(line, "screen_magnifier_present") != NULL) { + char* context; + char* firstNonSpaceChar = strtok_s(line, " ", &context); + if (*firstNonSpaceChar == '#') { + fputs(line, tempFile); + } else { + strcat_s(commentLine, line); + fputs(commentLine, tempFile); + fputs(magLine, tempFile); + foundMagLine = true; + } + } else { + fputs(line, tempFile); + } + } + } + if (!foundJabLine) { + fputs(jabLine, tempFile); + } + if (!foundMagLine) { + fputs(magLine, tempFile); + } +} + +void disableJAB() { + // Copy lines from orig to temp modifying the line containing + // assistive_technologies= + // There are various scenarios: + // 1) If the uncommented line exists, comment it out + // 2) If the line exists but is preceeded by a #, nothing to do + // 3) If the line doesn't exist, nothing to do + // Do the same for screen_magnifier_present= + char line[512]; + char commentLine[512]; + while (!feof(origFile)) { + if (fgets(line, 512, origFile) != NULL) { + if (strstr(line, "assistive_technologies") != NULL) { + char* context; + char* firstNonSpaceChar = strtok_s(line, " ", &context); + if (*firstNonSpaceChar != '#') { + strcpy_s(commentLine, "#"); + strcat_s(commentLine, line); + fputs(commentLine, tempFile); + } else { + fputs(line, tempFile); + } + } else if (strstr(line, "screen_magnifier_present") != NULL) { + char* context; + char* firstNonSpaceChar = strtok_s(line, " ", &context); + if (*firstNonSpaceChar != '#') { + strcpy_s(commentLine, "#"); + strcat_s(commentLine, line); + fputs(commentLine, tempFile); + } else { + fputs(line, tempFile); + } + } else { + fputs(line, tempFile); + } + } + } +} + +int modify(bool enable) { + errno_t error = 0; + char path[512]; + char tempPath[512]; + // Get the path for %USERPROFILE% + char *profilePath; + size_t len; + error = _dupenv_s(&profilePath, &len, "USERPROFILE" ); + if (error) { + printf("Error fetching USERPROFILE.\n"); + perror("Error"); + return error; + } + strcpy_s(path, profilePath); + strcat_s(path, "\\.accessibility.properties"); + strcpy_s(tempPath, profilePath); + strcat_s(tempPath, "\\.acce$$ibility.properties"); + free(profilePath); + // Open the original file. If it doesn't exist and this is an enable request then create it. + error = fopen_s(&origFile, path, "r"); + if (error) { + if (enable) { + error = fopen_s(&origFile, path, "w"); + if (error) { + printf("Couldn't create file: %s\n", path); + perror("Error"); + } else { + char str[100] = "assistive_technologies=com.sun.java.accessibility.AccessBridge\n"; + strcat_s(str, "screen_magnifier_present=true\n"); + fprintf(origFile, str); + fclose(origFile); + } + } else { + // It's OK if the file isn't there for a -disable + error = 0; + } + } else { + // open a temp file + error = fopen_s(&tempFile, tempPath, "w"); + if (error) { + printf("Couldn't open temp file: %s\n", tempPath); + perror("Error"); + return error; + } + if (enable) { + enableJAB(); + } else { + disableJAB(); + } + fclose(origFile); + fclose(tempFile); + // delete the orig file and rename the temp file + if (remove(path) != 0) { + printf("Couldn't remove file: %s\n", path); + perror("Error"); + return errno; + } + if (rename(tempPath, path) != 0) { + printf("Couldn't rename %s to %s.\n", tempPath, path); + perror("Error"); + return errno; + } + } + return error; +} + +void printUsage() { + printf("\njabswitch [/enable | /disable | /version | /?]\n\n"); + printf("Description:\n"); + printf(" jabswitch enables or disables the Java Access Bridge.\n\n"); + printf("Parameters:\n"); + printf(" /enable Enable the Java Accessibility Bridge.\n"); + printf(" /disable Disable the Java Accessibility Bridge.\n"); + printf(" /version Display the version.\n"); + printf(" /? Display this usage information.\n"); + printf("\nNote:\n"); + printf(" The Java Access Bridge can also be enabled with the\n"); + printf(" Windows Ease of Access control panel (which can be\n"); + printf(" activated by pressing Windows + U). The Ease of Access\n"); + printf(" control panel has a Java Access Bridge checkbox. Please\n"); + printf(" be aware that unchecking the checkbox has no effect and\n"); + printf(" in order to disable the Java Access Bridge you must run\n"); + printf(" jabswitch.exe from the command line.\n"); +} + +void printVersion() { + TCHAR executableFileName[_MAX_PATH]; + if (!GetModuleFileName(0, executableFileName, _MAX_PATH)) { + printf("Unable to get executable file name.\n"); + return; + } + DWORD nParam; + DWORD nVersionSize = GetFileVersionInfoSize(executableFileName, &nParam); + if (!nVersionSize) { + printf("Unable to get version info size.\n"); + return; + } + char* pVersionData = new char[nVersionSize]; + if (!GetFileVersionInfo(executableFileName, 0, nVersionSize, pVersionData)) { + printf("Unable to get version info.\n"); + return; + } + LPVOID pVersionInfo; + UINT nSize; + if (!VerQueryValue(pVersionData, _T("\\"), &pVersionInfo, &nSize)) { + printf("Unable to query version value.\n"); + return; + } + VS_FIXEDFILEINFO *pVSInfo = (VS_FIXEDFILEINFO *)pVersionInfo; + char versionString[100]; + sprintf_s( versionString, "version %i.%i.%i.%i", + pVSInfo->dwProductVersionMS >> 16, + pVSInfo->dwProductVersionMS & 0xFFFF, + pVSInfo->dwProductVersionLS >> 16, + pVSInfo->dwProductVersionLS & 0xFFFF ); + char outputString[100]; + strcpy_s(outputString, "jabswitch "); + strcat_s(outputString, versionString); + strcat_s(outputString, "\njabswitch enables or disables the Java Access Bridge.\n"); + printf(outputString); +} + +int regEnable() { + HKEY hKey; + DWORD retval = -1; + LSTATUS err; + err = RegOpenKeyEx(HKEY_CURRENT_USER, ACCESSIBILITY_USER_KEY, NULL, KEY_READ|KEY_WRITE, &hKey); + if (err == ERROR_SUCCESS) { + DWORD dataType = REG_SZ; + DWORD dataLength = DEFAULT_ALLOC; + TCHAR dataBuffer[DEFAULT_ALLOC]; + TCHAR *data = dataBuffer; + bool freeData = false; + err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength); + if (err == ERROR_MORE_DATA) { + if (dataLength > 0 && dataLength < MAX_ALLOC) { + data = new TCHAR[dataLength]; + err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength); + } + } + if (err == ERROR_SUCCESS) { + err = _tcslwr_s(dataBuffer, DEFAULT_ALLOC); + if (err) { + return -1; + } + if (_tcsstr(dataBuffer, STR_ACCESSBRIDGE) != NULL) { + return 0; // This is OK, e.g. ran enable twice and the value is there. + } else { + // add oracle_javaaccessbridge to Config key for HKCU + dataLength = dataLength + (_tcslen(STR_ACCESSBRIDGE) + 1) * sizeof(TCHAR); + TCHAR *newStr = new TCHAR[dataLength]; + if (newStr != NULL) { + wsprintf(newStr, L"%s,%s", dataBuffer, STR_ACCESSBRIDGE); + RegSetValueEx(hKey, ACCESSIBILITY_CONFIG, 0, REG_SZ, (BYTE *)newStr, dataLength); + } + } + } + RegCloseKey(hKey); + } + return err; +} + +int regDeleteValue(HKEY hFamilyKey, LPCWSTR lpSubKey) +{ + HKEY hKey; + DWORD retval = -1; + LSTATUS err; + err = RegOpenKeyEx(hFamilyKey, lpSubKey, NULL, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, &hKey); + if (err != ERROR_SUCCESS) + err = RegOpenKeyEx(hFamilyKey, lpSubKey, NULL, KEY_READ|KEY_WRITE, &hKey); + + if (err == ERROR_SUCCESS) { + DWORD dataType = REG_SZ; + DWORD dataLength = DEFAULT_ALLOC; + TCHAR dataBuffer[DEFAULT_ALLOC]; + TCHAR searchBuffer[DEFAULT_ALLOC]; + TCHAR *data = dataBuffer; + bool freeData = false; + err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength); + if (err == ERROR_MORE_DATA) { + if (dataLength > 0 && dataLength < MAX_ALLOC) { + data = new TCHAR[dataLength]; + err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength); + } + } + if (err == ERROR_SUCCESS) { + err = _tcslwr_s(dataBuffer, DEFAULT_ALLOC); + if (err) { + return -1; + } + if (_tcsstr(dataBuffer, STR_ACCESSBRIDGE) == NULL) { + return 0; // This is OK, e.g. ran disable twice and the value is not there. + } else { + // remove oracle_javaaccessbridge from Config key + TCHAR *newStr = new TCHAR[dataLength]; + TCHAR *nextToken; + LPTSTR tok, beg1 = dataBuffer; + bool first = true; + _tcscpy_s(newStr, dataLength, L""); + tok = _tcstok_s(beg1, L",", &nextToken); + while (tok != NULL) { + _tcscpy_s(searchBuffer, DEFAULT_ALLOC, tok); + err = _tcslwr_s(searchBuffer, DEFAULT_ALLOC); + if (err) { + return -1; + } + if (_tcsstr(searchBuffer, STR_ACCESSBRIDGE) == NULL) { + if (!first) { + _tcscat_s(newStr, dataLength, L","); + } + first = false; + _tcscat_s(newStr, dataLength, tok); + } + tok = _tcstok_s(NULL, L",", &nextToken); + } + dataLength = (_tcslen(newStr) + 1) * sizeof(TCHAR); + RegSetValueEx(hKey, ACCESSIBILITY_CONFIG, 0, REG_SZ, (BYTE *)newStr, dataLength); + } + } + RegCloseKey(hKey); + } + return err; +} + +int regDisable() +{ + LSTATUS err; + // Update value for HKCU + err=regDeleteValue(HKEY_CURRENT_USER, ACCESSIBILITY_USER_KEY); + // Update value for HKLM for Session + TCHAR dataBuffer[DEFAULT_ALLOC]; + DWORD dwSessionId ; + ProcessIdToSessionId(GetCurrentProcessId(),&dwSessionId ) ; + if( dwSessionId >= 0 ) + { + wsprintf(dataBuffer, L"%s%d", ACCESSIBILITY_SYSTEM_KEY, dwSessionId); + err=regDeleteValue(HKEY_LOCAL_MACHINE, dataBuffer); + } + return err; +} + +void main(int argc, char* argv[]) { + bool enableWasRequested = false; + bool disableWasRequested = false; + bool badParams = true; + int error = 0; + if (argc == 2) { + if (_stricmp(argv[1], "-?") == 0 || _stricmp(argv[1], "/?") == 0) { + printUsage(); + badParams = false; + } else if (_stricmp(argv[1], "-version") == 0 || _stricmp(argv[1], "/version") == 0) { + printVersion(); + badParams = false; + } else { + if (_stricmp(argv[1], "-enable") == 0 || _stricmp(argv[1], "/enable") == 0) { + badParams = false; + enableWasRequested = true; + error = modify(true); + if (error == 0) { + if( !isXP() ) + regEnable(); + } + } else if (_stricmp(argv[1], "-disable") == 0 || _stricmp(argv[1], "/disable") == 0) { + badParams = false; + disableWasRequested = true; + error = modify(false); + if (error == 0) { + if( !isXP() ) + regDisable(); + } + } + } + } + if (badParams) { + printUsage(); + } else if (enableWasRequested || disableWasRequested) { + if (error != 0) { + printf("There was an error.\n\n"); + } + printf("The Java Access Bridge has "); + if (error != 0) { + printf("not "); + } + printf("been "); + if (enableWasRequested) { + printf("enabled.\n"); + } else { + printf("disabled.\n"); + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/jabswitch/jabswitch.manifest --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/jabswitch/jabswitch.manifest Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,10 @@ + + + + + + + + + + diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libjabsysinfo/AccessBridgeSysInfo.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libjabsysinfo/AccessBridgeSysInfo.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2014, 2015, 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. + */ + +#include +#include +#include +#include +#include + +extern "C" { + +BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) { + return TRUE; +} + +// Determine bitness of Win OS +JNIEXPORT jboolean JNICALL +Java_com_sun_java_accessibility_AccessBridge_isSysWow(JNIEnv *env, jobject callingObj) { + BOOL bIsWow64 = FALSE; + typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); + + LPFN_ISWOW64PROCESS fnIsWow64Process = + (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process"); + + if (fnIsWow64Process != NULL) { + if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64)) { + throw std::runtime_error("fnIsWow64Process() failed"); + } + } + + return bIsWow64 ? JNI_TRUE : JNI_FALSE; +} + +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeATInstance.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeATInstance.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to track key AT instance info from the JavaAccessBridge + */ + +#include "AccessBridgeDebug.h" +#include "AccessBridgeATInstance.h" +#include "AccessBridgeMessages.h" + +#include +#include + + +/** + * AccessBridgeATInstance constructor + */ +AccessBridgeATInstance::AccessBridgeATInstance(HWND ourABWindow, HWND winABWindow, + char *memoryFilename, + AccessBridgeATInstance *next) { + ourAccessBridgeWindow = ourABWindow; + winAccessBridgeWindow = winABWindow; + nextATInstance = next; + javaEventMask = 0; + accessibilityEventMask = 0; + strncpy(memoryMappedFileName, memoryFilename, cMemoryMappedNameSize); +} + +/** + * AccessBridgeATInstance descructor + */ +AccessBridgeATInstance::~AccessBridgeATInstance() { + PrintDebugString("\r\nin AccessBridgeATInstance::~AccessBridgeATInstance"); + + // if IPC memory mapped file view is valid, unmap it + if (memoryMappedView != (char *) 0) { + PrintDebugString(" unmapping memoryMappedView; view = %p", memoryMappedView); + UnmapViewOfFile(memoryMappedView); + memoryMappedView = (char *) 0; + } + // if IPC memory mapped file handle map is open, close it + if (memoryMappedFileMapHandle != (HANDLE) 0) { + PrintDebugString(" closing memoryMappedFileMapHandle; handle = %p", memoryMappedFileMapHandle); + CloseHandle(memoryMappedFileMapHandle); + memoryMappedFileMapHandle = (HANDLE) 0; + } +} + +/** + * Sets up the memory-mapped file to do IPC messaging + * 1 files is created: to handle requests for information + * initiated from Windows AT. The package is placed into + * the memory-mapped file (char *memoryMappedView), + * and then a special SendMessage() is sent. When the + * JavaDLL returns from SendMessage() processing, the + * data will be in memoryMappedView. The SendMessage() + * return value tells us if all is right with the world. + * + * The set-up proces involves creating the memory-mapped + * file, and writing a special string to it so that the + * WindowsDLL so it knows about it as well. + */ +LRESULT +AccessBridgeATInstance::initiateIPC() { + DWORD errorCode; + + PrintDebugString("\r\nin AccessBridgeATInstance::initiateIPC()"); + + // open Windows-initiated IPC filemap & map it to a ptr + + memoryMappedFileMapHandle = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE, + FALSE, memoryMappedFileName); + if (memoryMappedFileMapHandle == NULL) { + errorCode = GetLastError(); + PrintDebugString(" Failed to CreateFileMapping for %s, error: %X", memoryMappedFileName, errorCode); + return errorCode; + } else { + PrintDebugString(" CreateFileMapping worked - filename: %s", memoryMappedFileName); + } + + memoryMappedView = (char *) MapViewOfFile(memoryMappedFileMapHandle, + FILE_MAP_READ | FILE_MAP_WRITE, + 0, 0, 0); + if (memoryMappedView == NULL) { + errorCode = GetLastError(); + PrintDebugString(" Failed to MapViewOfFile for %s, error: %X", memoryMappedFileName, errorCode); + return errorCode; + } else { + PrintDebugString(" MapViewOfFile worked - view: %p", memoryMappedView); + } + + + // look for the JavaDLL's answer to see if it could read the file + if (strcmp(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_QUERY) != 0) { + PrintDebugString(" JavaVM failed to write to memory mapped file %s", + memoryMappedFileName); + return -1; + } else { + PrintDebugString(" JavaVM successfully wrote to file!"); + } + + + // write some data to the memory mapped file for WindowsDLL to verify + strcpy(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_ANSWER); + + + return 0; +} + + +typedef struct EVENT_STRUCT +{ + char *buffer; + int bufsize; + ABHWND64 winAccessBridgeWindow; + ABHWND64 ourAccessBridgeWindow; +}EVENT_STRUCT; + + +#include +#define THREAD_PROC unsigned int __stdcall +typedef unsigned int (__stdcall *THREAD_ROUTINE)(LPVOID lpThreadParameter); + +static HANDLE BeginThread(THREAD_ROUTINE thread_func,DWORD *id,DWORD param) +{ + HANDLE ret; + ret = (HANDLE) _beginthreadex(NULL,0,thread_func,(void *)param,0,(unsigned int *)id); + if(ret == INVALID_HANDLE_VALUE) + ret = NULL; + return(ret); +} + +DWORD JavaBridgeThreadId = 0; + +static THREAD_PROC JavaBridgeThread(LPVOID param1) +{ + MSG msg; + DWORD rc = 0; + while (GetMessage(&msg, // message structure + NULL, // handle of window receiving the message + 0, // lowest message to examine + 0)) // highest message to examine + { + if(msg.message == WM_USER) + { + EVENT_STRUCT *event_struct = (EVENT_STRUCT *)msg.wParam; + COPYDATASTRUCT toCopy; + toCopy.dwData = 0; // 32-bits we could use for something... + toCopy.cbData = event_struct->bufsize; + toCopy.lpData = event_struct->buffer; + + LRESULT ret = SendMessage((HWND)ABLongToHandle(event_struct->winAccessBridgeWindow), WM_COPYDATA, + (WPARAM)event_struct->ourAccessBridgeWindow, (LPARAM) &toCopy); + delete event_struct->buffer; + delete event_struct; + } + if(msg.message == (WM_USER+1)) + PostQuitMessage(0); + } + JavaBridgeThreadId = 0; + return(0); +} + +/* + * Handles one event + */ +static void do_event(char *buffer, int bufsize,HWND ourAccessBridgeWindow,HWND winAccessBridgeWindow) +{ + EVENT_STRUCT *event_struct = new EVENT_STRUCT; + event_struct->bufsize = bufsize; + event_struct->buffer = new char[bufsize]; + memcpy(event_struct->buffer,buffer,bufsize); + event_struct->ourAccessBridgeWindow = ABHandleToLong(ourAccessBridgeWindow); + event_struct->winAccessBridgeWindow = ABHandleToLong(winAccessBridgeWindow); + if(!JavaBridgeThreadId) + { + HANDLE JavaBridgeThreadHandle = BeginThread(JavaBridgeThread,&JavaBridgeThreadId,(DWORD)event_struct); + CloseHandle(JavaBridgeThreadHandle); + } + PostThreadMessage(JavaBridgeThreadId,WM_USER,(WPARAM)event_struct,0); +} + + +/** + * sendJavaEventPackage - uses SendMessage(WM_COPYDATA) to do + * IPC messaging with the Java AccessBridge DLL + * to propogate events to those ATs that want 'em + * + */ +LRESULT +AccessBridgeATInstance::sendJavaEventPackage(char *buffer, int bufsize, long eventID) { + + PrintDebugString("AccessBridgeATInstance::sendJavaEventPackage() eventID = %X", eventID); + PrintDebugString("AccessBridgeATInstance::sendJavaEventPackage() (using PostMessage) eventID = %X", eventID); + + if (eventID & javaEventMask) { + do_event(buffer,bufsize,ourAccessBridgeWindow,winAccessBridgeWindow); + return(0); + } else { + return -1; + } +} + + +/** + * uses SendMessage(WM_COPYDATA) to do + * IPC messaging with the Java AccessBridge DLL + * to propogate events to those ATs that want 'em + * + */ +LRESULT +AccessBridgeATInstance::sendAccessibilityEventPackage(char *buffer, int bufsize, long eventID) { + + PrintDebugString("AccessBridgeATInstance::sendAccessibilityEventPackage() eventID = %X", eventID); + + if (eventID & accessibilityEventMask) { + do_event(buffer,bufsize,ourAccessBridgeWindow,winAccessBridgeWindow); + return(0); + } else { + return -1; + } +} + + +/** + * findABATInstanceFromATHWND - walk through linked list from + * where we are. Return the + * AccessBridgeATInstance + * of the ABATInstance that + * matches the passed in vmID; + * no match: return 0 + */ +AccessBridgeATInstance * +AccessBridgeATInstance::findABATInstanceFromATHWND(HWND window) { + // no need to recurse really + if (winAccessBridgeWindow == window) { + return this; + } else { + AccessBridgeATInstance *current = nextATInstance; + while (current != (AccessBridgeATInstance *) 0) { + if (current->winAccessBridgeWindow == window) { + return current; + } + current = current->nextATInstance; + } + } + return (AccessBridgeATInstance *) 0; +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeATInstance.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeATInstance.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to track key AT instance info from the JavaAccessBridge + */ + +#include +#include "AccessBridgePackages.h" + +#ifndef __AccessBridgeATInstance_H__ +#define __AccessBridgeATInstance_H__ + + +/** + * The AccessBridgeATInstance class. + */ +class AccessBridgeATInstance { + friend class JavaAccessBridge; + + AccessBridgeATInstance *nextATInstance; + HWND ourAccessBridgeWindow; + HWND winAccessBridgeWindow; + long javaEventMask; + long accessibilityEventMask; + + // IPC variables + HANDLE memoryMappedFileMapHandle; // handle to file map + char *memoryMappedView; // ptr to shared memory + char memoryMappedFileName[cMemoryMappedNameSize]; + +public: + AccessBridgeATInstance(HWND ourABWindow, HWND winABWindow, + char *memoryFilename, + AccessBridgeATInstance *next); + ~AccessBridgeATInstance(); + LRESULT initiateIPC(); + LRESULT sendJavaEventPackage(char *buffer, int bufsize, long eventID); + LRESULT sendAccessibilityEventPackage(char *buffer, int bufsize, long eventID); + AccessBridgeATInstance *findABATInstanceFromATHWND(HWND window); +}; + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,4787 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to manage JNI calls into AccessBridge.java + */ + +#include "AccessBridgeJavaEntryPoints.h" +#include "AccessBridgeDebug.h" + + + +/** + * Initialize the AccessBridgeJavaEntryPoints class + * + */ +AccessBridgeJavaEntryPoints::AccessBridgeJavaEntryPoints(JNIEnv *jniEnvironment, + jobject bridgeObject) { + jniEnv = jniEnvironment; + accessBridgeObject = (jobject)bridgeObject; + PrintDebugString("AccessBridgeJavaEntryPoints(%X, %X) called", jniEnv, accessBridgeObject); +} + + +/** + * Destructor + * + */ +AccessBridgeJavaEntryPoints::~AccessBridgeJavaEntryPoints() { +} + +// ----------------------------------- + +#define FIND_CLASS(classRef, className) \ + localClassRef = jniEnv->FindClass(className); \ + if (localClassRef == (jclass) 0) { \ + PrintDebugString(" Error! FindClass(%s) failed!", className); \ + PrintDebugString(" -> jniEnv = %p", jniEnv); \ + return FALSE; \ + } \ + classRef = (jclass) jniEnv->NewGlobalRef(localClassRef); \ + jniEnv->DeleteLocalRef(localClassRef); \ + if (classRef == (jclass) 0) { \ + PrintDebugString(" Error! FindClass(%s) failed!", className); \ + PrintDebugString(" -> (ran out of RAM)"); \ + return FALSE; \ + } + + +#define FIND_METHOD(methodID, classRef, methodString, methodSignature); \ + methodID = jniEnv->GetMethodID(classRef, methodString, methodSignature); \ + if (methodID == (jmethodID) 0) { \ + PrintDebugString(" Error! GetMethodID(%s) failed!", methodString); \ + PrintDebugString(" -> jniEnv = %p; classRef = %p", jniEnv, classRef); \ + return FALSE; \ + } + +#define EXCEPTION_CHECK(situationDescription, returnVal) \ + if (exception = jniEnv->ExceptionOccurred()) { \ + PrintDebugString("\r\n *** Exception occured while doing: %s; returning %d", situationDescription, returnVal); \ + jniEnv->ExceptionDescribe(); \ + jniEnv->ExceptionClear(); \ + return (returnVal); \ + } + +#define EXCEPTION_CHECK_VOID(situationDescription) \ + if (exception = jniEnv->ExceptionOccurred()) { \ + PrintDebugString("\r\n *** Exception occured while doing: %s", situationDescription); \ + jniEnv->ExceptionDescribe(); \ + jniEnv->ExceptionClear(); \ + return; \ + } + +/** + * Make all of the getClass() & getMethod() calls + * + */ +BOOL +AccessBridgeJavaEntryPoints::BuildJavaEntryPoints() { + jclass localClassRef; + + PrintDebugString("Calling BuildJavaEntryPoints():"); + + FIND_CLASS(bridgeClass, "com/sun/java/accessibility/AccessBridge"); + + // ------- general methods + + // GetMethodID(decrementReference) + FIND_METHOD(decrementReferenceMethod, bridgeClass, + "decrementReference", + "(Ljava/lang/Object;)V"); + + // GetMethodID(getJavaVersionPropertyMethod) + FIND_METHOD(getJavaVersionPropertyMethod, bridgeClass, + "getJavaVersionProperty", + "()Ljava/lang/String;"); + + // ------- Window methods + + // GetMethodID(isJavaWindow) + FIND_METHOD(isJavaWindowMethod, bridgeClass, + "isJavaWindow", + "(I)Z"); + + // GetMethodID(getAccessibleContextFromHWND) + FIND_METHOD(getAccessibleContextFromHWNDMethod, bridgeClass, + "getContextFromNativeWindowHandle", + "(I)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getHWNDFromAccessibleContext) + FIND_METHOD(getHWNDFromAccessibleContextMethod, bridgeClass, + "getNativeWindowHandleFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleParentFromContext) + FIND_METHOD(getAccessibleParentFromContextMethod, bridgeClass, + "getAccessibleParentFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleContext;"); + + // ===== utility methods ===== */ + + // GetMethodID(setTextContents) + FIND_METHOD(setTextContentsMethod, bridgeClass, + "setTextContents", + "(Ljavax/accessibility/AccessibleContext;Ljava/lang/String;)Z"); + + // GetMethodID(getParentWithRole) + FIND_METHOD(getParentWithRoleMethod, bridgeClass, + "getParentWithRole", + "(Ljavax/accessibility/AccessibleContext;Ljava/lang/String;)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getTopLevelObject) + FIND_METHOD(getTopLevelObjectMethod, bridgeClass, + "getTopLevelObject", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getParentWithRoleElseRoot) + FIND_METHOD(getParentWithRoleElseRootMethod, bridgeClass, + "getParentWithRoleElseRoot", + "(Ljavax/accessibility/AccessibleContext;Ljava/lang/String;)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getObjectDepth) + FIND_METHOD(getObjectDepthMethod, bridgeClass, + "getObjectDepth", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getActiveDescendent) + FIND_METHOD(getActiveDescendentMethod, bridgeClass, + "getActiveDescendent", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleContext;"); + + // ------- AccessibleContext methods + + // GetMethodID(getAccessibleContextAt) + FIND_METHOD(getAccessibleContextAtMethod, bridgeClass, + "getAccessibleContextAt", + "(IILjavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getAccessibleContextWithFocus) + FIND_METHOD(getAccessibleContextWithFocusMethod, bridgeClass, + "getAccessibleContextWithFocus", + "()Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getAccessibleNameFromContext) + FIND_METHOD(getAccessibleNameFromContextMethod, bridgeClass, + "getAccessibleNameFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + // GetMethodID(getAccessibleDescriptionFromContext) + FIND_METHOD(getAccessibleDescriptionFromContextMethod, bridgeClass, + "getAccessibleDescriptionFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + // GetMethodID(getAccessibleRoleStringFromContext) + FIND_METHOD(getAccessibleRoleStringFromContextMethod, bridgeClass, + "getAccessibleRoleStringFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + // GetMethodID(getAccessibleRoleStringFromContext_en_US) + FIND_METHOD(getAccessibleRoleStringFromContext_en_USMethod, bridgeClass, + "getAccessibleRoleStringFromContext_en_US", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + // GetMethodID(getAccessibleStatesStringFromContext) + FIND_METHOD(getAccessibleStatesStringFromContextMethod, bridgeClass, + "getAccessibleStatesStringFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + // GetMethodID(getAccessibleStatesStringFromContext_en_US) + FIND_METHOD(getAccessibleStatesStringFromContext_en_USMethod, bridgeClass, + "getAccessibleStatesStringFromContext_en_US", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + // GetMethodID(getAccessibleParentFromContext) + FIND_METHOD(getAccessibleParentFromContextMethod, bridgeClass, + "getAccessibleParentFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getAccessibleIndexInParentFromContext) + FIND_METHOD(getAccessibleIndexInParentFromContextMethod, bridgeClass, + "getAccessibleIndexInParentFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleChildrenCountFromContext) + FIND_METHOD(getAccessibleChildrenCountFromContextMethod, bridgeClass, + "getAccessibleChildrenCountFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleChildFromContext) + FIND_METHOD(getAccessibleChildFromContextMethod, bridgeClass, + "getAccessibleChildFromContext", + "(Ljavax/accessibility/AccessibleContext;I)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getAccessibleBoundsOnScreenFromContext) + FIND_METHOD(getAccessibleBoundsOnScreenFromContextMethod, bridgeClass, + "getAccessibleBoundsOnScreenFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/awt/Rectangle;"); + + // GetMethodID(getAccessibleXcoordFromContext) + FIND_METHOD(getAccessibleXcoordFromContextMethod, bridgeClass, + "getAccessibleXcoordFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleYcoordFromContext) + FIND_METHOD(getAccessibleYcoordFromContextMethod, bridgeClass, + "getAccessibleYcoordFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleHeightFromContext) + FIND_METHOD(getAccessibleHeightFromContextMethod, bridgeClass, + "getAccessibleHeightFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleWidthFromContext) + FIND_METHOD(getAccessibleWidthFromContextMethod, bridgeClass, + "getAccessibleWidthFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleComponentFromContext) + FIND_METHOD(getAccessibleComponentFromContextMethod, bridgeClass, + "getAccessibleComponentFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleComponent;"); + + // GetMethodID(getAccessibleActionFromContext) + FIND_METHOD(getAccessibleActionFromContextMethod, bridgeClass, + "getAccessibleActionFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleAction;"); + + // GetMethodID(getAccessibleSelectionFromContext) + FIND_METHOD(getAccessibleSelectionFromContextMethod, bridgeClass, + "getAccessibleSelectionFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleSelection;"); + + // GetMethodID(getAccessibleTextFromContext) + FIND_METHOD(getAccessibleTextFromContextMethod, bridgeClass, + "getAccessibleTextFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleText;"); + + // GetMethodID(getAccessibleValueFromContext) + FIND_METHOD(getAccessibleValueFromContextMethod, bridgeClass, + "getAccessibleValueFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleValue;"); + + + // ------- begin AccessibleTable methods + + // GetMethodID(getAccessibleTableFromContext) + FIND_METHOD(getAccessibleTableFromContextMethod, bridgeClass, + "getAccessibleTableFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleTable;"); + + // GetMethodID(getContextFromAccessibleTable) + FIND_METHOD(getContextFromAccessibleTableMethod, bridgeClass, + "getContextFromAccessibleTable", + "(Ljavax/accessibility/AccessibleTable;)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getAccessibleTableRowHeader) + FIND_METHOD(getAccessibleTableRowHeaderMethod, bridgeClass, + "getAccessibleTableRowHeader", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleTable;"); + + + // GetMethodID(getAccessibleTableColumnHeader) + FIND_METHOD(getAccessibleTableColumnHeaderMethod, bridgeClass, + "getAccessibleTableColumnHeader", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleTable;"); + + + // GetMethodID(getAccessibleTableRowCount) + FIND_METHOD(getAccessibleTableRowCountMethod, bridgeClass, + "getAccessibleTableRowCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleTableColumnCount) + FIND_METHOD(getAccessibleTableColumnCountMethod, bridgeClass, + "getAccessibleTableColumnCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleTableCellAccessibleContext) + FIND_METHOD(getAccessibleTableCellAccessibleContextMethod, bridgeClass, + "getAccessibleTableCellAccessibleContext", + "(Ljavax/accessibility/AccessibleTable;II)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getAccessibleTableCellIndex) + FIND_METHOD(getAccessibleTableCellIndexMethod, bridgeClass, + "getAccessibleTableCellIndex", + "(Ljavax/accessibility/AccessibleTable;II)I"); + + // GetMethodID(getAccessibleTableCellRowExtent) + FIND_METHOD(getAccessibleTableCellRowExtentMethod, bridgeClass, + "getAccessibleTableCellRowExtent", + "(Ljavax/accessibility/AccessibleTable;II)I"); + + // GetMethodID(getAccessibleTableCellColumnExtent) + FIND_METHOD(getAccessibleTableCellColumnExtentMethod, bridgeClass, + "getAccessibleTableCellColumnExtent", + "(Ljavax/accessibility/AccessibleTable;II)I"); + + // GetMethodID(isAccessibleTableCellSelected) + FIND_METHOD(isAccessibleTableCellSelectedMethod, bridgeClass, + "isAccessibleTableCellSelected", + "(Ljavax/accessibility/AccessibleTable;II)Z"); + + // GetMethodID(getAccessibleTableRowHeaderRowCount) + FIND_METHOD(getAccessibleTableRowHeaderRowCountMethod, bridgeClass, + "getAccessibleTableRowHeaderRowCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleTableColumnHeaderRowCount) + FIND_METHOD(getAccessibleTableColumnHeaderRowCountMethod, bridgeClass, + "getAccessibleTableColumnHeaderRowCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleTableRowHeaderColumnCount) + FIND_METHOD(getAccessibleTableRowHeaderColumnCountMethod, bridgeClass, + "getAccessibleTableRowHeaderColumnCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleTableColumnHeaderColumnCount) + FIND_METHOD(getAccessibleTableColumnHeaderColumnCountMethod, bridgeClass, + "getAccessibleTableColumnHeaderColumnCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleTableRowDescription) + FIND_METHOD(getAccessibleTableRowDescriptionMethod, bridgeClass, + "getAccessibleTableRowDescription", + "(Ljavax/accessibility/AccessibleTable;I)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getAccessibleTableColumnDescription) + FIND_METHOD(getAccessibleTableColumnDescriptionMethod, bridgeClass, + "getAccessibleTableColumnDescription", + "(Ljavax/accessibility/AccessibleTable;I)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getAccessibleTableRowSelectionCount) + FIND_METHOD(getAccessibleTableRowSelectionCountMethod, bridgeClass, + "getAccessibleTableRowSelectionCount", + "(Ljavax/accessibility/AccessibleTable;)I"); + + // GetMethodID(isAccessibleTableRowSelected) + FIND_METHOD(isAccessibleTableRowSelectedMethod, bridgeClass, + "isAccessibleTableRowSelected", + "(Ljavax/accessibility/AccessibleTable;I)Z"); + + // GetMethodID(getAccessibleTableRowSelections) + FIND_METHOD(getAccessibleTableRowSelectionsMethod, bridgeClass, + "getAccessibleTableRowSelections", + "(Ljavax/accessibility/AccessibleTable;I)I"); + + // GetMethodID(getAccessibleTableColumnSelectionCount) + FIND_METHOD(getAccessibleTableColumnSelectionCountMethod, bridgeClass, + "getAccessibleTableColumnSelectionCount", + "(Ljavax/accessibility/AccessibleTable;)I"); + + // GetMethodID(isAccessibleTableColumnSelected) + FIND_METHOD(isAccessibleTableColumnSelectedMethod, bridgeClass, + "isAccessibleTableColumnSelected", + "(Ljavax/accessibility/AccessibleTable;I)Z"); + + // GetMethodID(getAccessibleTableColumnSelections) + FIND_METHOD(getAccessibleTableColumnSelectionsMethod, bridgeClass, + "getAccessibleTableColumnSelections", + "(Ljavax/accessibility/AccessibleTable;I)I"); + + // GetMethodID(getAccessibleTableRow) + FIND_METHOD(getAccessibleTableRowMethod, bridgeClass, + "getAccessibleTableRow", + "(Ljavax/accessibility/AccessibleTable;I)I"); + + // GetMethodID(getAccessibleTableColumn) + FIND_METHOD(getAccessibleTableColumnMethod, bridgeClass, + "getAccessibleTableColumn", + "(Ljavax/accessibility/AccessibleTable;I)I"); + + // GetMethodID(getAccessibleTableIndex) + FIND_METHOD(getAccessibleTableIndexMethod, bridgeClass, + "getAccessibleTableIndex", + "(Ljavax/accessibility/AccessibleTable;II)I"); + + /* ------- end AccessibleTable methods */ + + /* start AccessibleRelationSet methods ----- */ + + // GetMethodID(getAccessibleRelationCount) + FIND_METHOD(getAccessibleRelationCountMethod, bridgeClass, + "getAccessibleRelationCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleRelationKey) + FIND_METHOD(getAccessibleRelationKeyMethod, bridgeClass, + "getAccessibleRelationKey", + "(Ljavax/accessibility/AccessibleContext;I)Ljava/lang/String;"); + + // GetMethodID(getAccessibleRelationTargetCount) + FIND_METHOD(getAccessibleRelationTargetCountMethod, bridgeClass, + "getAccessibleRelationTargetCount", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getAccessibleRelationTarget) + FIND_METHOD(getAccessibleRelationTargetMethod, bridgeClass, + "getAccessibleRelationTarget", + "(Ljavax/accessibility/AccessibleContext;II)Ljavax/accessibility/AccessibleContext;"); + + + // ------- AccessibleHypertext methods + + // GetMethodID(getAccessibleHypertext) + FIND_METHOD(getAccessibleHypertextMethod, bridgeClass, + "getAccessibleHypertext", + "(Ljavax/accessibility/AccessibleContext;)Ljavax/accessibility/AccessibleHypertext;"); + + // GetMethodID(activateAccessibleHyperlink) + FIND_METHOD(activateAccessibleHyperlinkMethod, bridgeClass, + "activateAccessibleHyperlink", + "(Ljavax/accessibility/AccessibleContext;Ljavax/accessibility/AccessibleHyperlink;)Z"); + + // GetMethodID(getAccessibleHyperlinkCount) + FIND_METHOD(getAccessibleHyperlinkCountMethod, bridgeClass, + "getAccessibleHyperlinkCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleHyperlink) + FIND_METHOD(getAccessibleHyperlinkMethod, bridgeClass, + "getAccessibleHyperlink", + "(Ljavax/accessibility/AccessibleHypertext;I)Ljavax/accessibility/AccessibleHyperlink;"); + + // GetMethodID(getAccessibleHyperlinkText) + FIND_METHOD(getAccessibleHyperlinkTextMethod, bridgeClass, + "getAccessibleHyperlinkText", + "(Ljavax/accessibility/AccessibleHyperlink;)Ljava/lang/String;"); + + // GetMethodID(getAccessibleHyperlinkURL) + FIND_METHOD(getAccessibleHyperlinkURLMethod, bridgeClass, + "getAccessibleHyperlinkURL", + "(Ljavax/accessibility/AccessibleHyperlink;)Ljava/lang/String;"); + + // GetMethodID(getAccessibleHyperlinkStartIndex) + FIND_METHOD(getAccessibleHyperlinkStartIndexMethod, bridgeClass, + "getAccessibleHyperlinkStartIndex", + "(Ljavax/accessibility/AccessibleHyperlink;)I"); + + // GetMethodID(getAccessibleHyperlinkEndIndex) + FIND_METHOD(getAccessibleHyperlinkEndIndexMethod, bridgeClass, + "getAccessibleHyperlinkEndIndex", + "(Ljavax/accessibility/AccessibleHyperlink;)I"); + + // GetMethodID(getAccessibleHypertextLinkIndex) + FIND_METHOD(getAccessibleHypertextLinkIndexMethod, bridgeClass, + "getAccessibleHypertextLinkIndex", + "(Ljavax/accessibility/AccessibleHypertext;I)I"); + + // Accessible KeyBinding, Icon and Action ==================== + + // GetMethodID(getAccessibleKeyBindingsCount) + FIND_METHOD(getAccessibleKeyBindingsCountMethod, bridgeClass, + "getAccessibleKeyBindingsCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleKeyBindingChar) + FIND_METHOD(getAccessibleKeyBindingCharMethod, bridgeClass, + "getAccessibleKeyBindingChar", + "(Ljavax/accessibility/AccessibleContext;I)C"); + + // GetMethodID(getAccessibleKeyBindingModifiers) + FIND_METHOD(getAccessibleKeyBindingModifiersMethod, bridgeClass, + "getAccessibleKeyBindingModifiers", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getAccessibleIconsCount) + FIND_METHOD(getAccessibleIconsCountMethod, bridgeClass, + "getAccessibleIconsCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleIconDescription) + FIND_METHOD(getAccessibleIconDescriptionMethod, bridgeClass, + "getAccessibleIconDescription", + "(Ljavax/accessibility/AccessibleContext;I)Ljava/lang/String;"); + + // GetMethodID(getAccessibleIconHeight) + FIND_METHOD(getAccessibleIconHeightMethod, bridgeClass, + "getAccessibleIconHeight", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getAccessibleIconWidth) + FIND_METHOD(getAccessibleIconWidthMethod, bridgeClass, + "getAccessibleIconWidth", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getAccessibleActionsCount) + FIND_METHOD(getAccessibleActionsCountMethod, bridgeClass, + "getAccessibleActionsCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleActionName) + FIND_METHOD(getAccessibleActionNameMethod, bridgeClass, + "getAccessibleActionName", + "(Ljavax/accessibility/AccessibleContext;I)Ljava/lang/String;"); + + // GetMethodID(doAccessibleActions) + FIND_METHOD(doAccessibleActionsMethod, bridgeClass, + "doAccessibleActions", + "(Ljavax/accessibility/AccessibleContext;Ljava/lang/String;)Z"); + + // ------- AccessibleText methods + + // GetMethodID(getAccessibleCharCountFromContext) + FIND_METHOD(getAccessibleCharCountFromContextMethod, bridgeClass, + "getAccessibleCharCountFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleCaretPositionFromContext) + FIND_METHOD(getAccessibleCaretPositionFromContextMethod, bridgeClass, + "getAccessibleCaretPositionFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleIndexAtPointFromContext) + FIND_METHOD(getAccessibleIndexAtPointFromContextMethod, bridgeClass, + "getAccessibleIndexAtPointFromContext", + "(Ljavax/accessibility/AccessibleContext;II)I"); + + // GetMethodID(getAccessibleLetterAtIndexFromContext) + FIND_METHOD(getAccessibleLetterAtIndexFromContextMethod, bridgeClass, + "getAccessibleLetterAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)Ljava/lang/String;"); + + // GetMethodID(getAccessibleWordAtIndexFromContext) + FIND_METHOD(getAccessibleWordAtIndexFromContextMethod, bridgeClass, + "getAccessibleWordAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)Ljava/lang/String;"); + + // GetMethodID(getAccessibleSentenceAtIndexFromContext) + FIND_METHOD(getAccessibleSentenceAtIndexFromContextMethod, bridgeClass, + "getAccessibleSentenceAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)Ljava/lang/String;"); + + // GetMethodID(getAccessibleTextSelectionStartFromContext) + FIND_METHOD(getAccessibleTextSelectionStartFromContextMethod, bridgeClass, + "getAccessibleTextSelectionStartFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleTextSelectionEndFromContext) + FIND_METHOD(getAccessibleTextSelectionEndFromContextMethod, bridgeClass, + "getAccessibleTextSelectionEndFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getAccessibleTextSelectedTextFromContext) + FIND_METHOD(getAccessibleTextSelectedTextFromContextMethod, bridgeClass, + "getAccessibleTextSelectedTextFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + // GetMethodID(getAccessibleAttributesAtIndexFromContext) + FIND_METHOD(getAccessibleAttributesAtIndexFromContextMethod, bridgeClass, + "getAccessibleAttributesAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)Ljava/lang/String;"); + + // GetMethodID(getAccessibleAttributeSetAtIndexFromContext) + FIND_METHOD(getAccessibleAttributeSetAtIndexFromContextMethod, bridgeClass, + "getAccessibleAttributeSetAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)Ljavax/swing/text/AttributeSet;"); + + // GetMethodID(getAccessibleTextRectAtIndexFromContext) + FIND_METHOD(getAccessibleTextRectAtIndexFromContextMethod, bridgeClass, + "getAccessibleTextRectAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)Ljava/awt/Rectangle;"); + + // GetMethodID(getAccessibleXcoordTextRectAtIndexFromContext) + FIND_METHOD(getAccessibleXcoordTextRectAtIndexFromContextMethod, bridgeClass, + "getAccessibleXcoordTextRectAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getAccessibleYcoordTextRectAtIndexFromContext) + FIND_METHOD(getAccessibleYcoordTextRectAtIndexFromContextMethod, bridgeClass, + "getAccessibleYcoordTextRectAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getAccessibleHeightTextRectAtIndexFromContext) + FIND_METHOD(getAccessibleHeightTextRectAtIndexFromContextMethod, bridgeClass, + "getAccessibleHeightTextRectAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getAccessibleWidthTextRectAtIndexFromContext) + FIND_METHOD(getAccessibleWidthTextRectAtIndexFromContextMethod, bridgeClass, + "getAccessibleWidthTextRectAtIndexFromContext", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getCaretLocationX) + FIND_METHOD(getCaretLocationXMethod, bridgeClass, + "getCaretLocationX", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getCaretLocationY) + FIND_METHOD(getCaretLocationYMethod, bridgeClass, + "getCaretLocationY", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getCaretLocationHeight) + FIND_METHOD(getCaretLocationHeightMethod, bridgeClass, + "getCaretLocationHeight", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getCaretLocationWidth) + FIND_METHOD(getCaretLocationWidthMethod, bridgeClass, + "getCaretLocationWidth", + "(Ljavax/accessibility/AccessibleContext;)I"); + + + // GetMethodID(getAccessibleTextLineLeftBoundsFromContextMethod) + FIND_METHOD(getAccessibleTextLineLeftBoundsFromContextMethod, bridgeClass, + "getAccessibleTextLineLeftBoundsFromContext", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getAccessibleTextLineRightBoundsFromContextMethod) + FIND_METHOD(getAccessibleTextLineRightBoundsFromContextMethod, bridgeClass, + "getAccessibleTextLineRightBoundsFromContext", + "(Ljavax/accessibility/AccessibleContext;I)I"); + + // GetMethodID(getAccessibleTextRangeFromContextMethod) + FIND_METHOD(getAccessibleTextRangeFromContextMethod, bridgeClass, + "getAccessibleTextRangeFromContext", + "(Ljavax/accessibility/AccessibleContext;II)Ljava/lang/String;"); + + + // ------- AccessibleValue methods + + // GetMethodID(getCurrentAccessibleValueFromContext) + FIND_METHOD(getCurrentAccessibleValueFromContextMethod, bridgeClass, + "getCurrentAccessibleValueFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + // GetMethodID(getMaximumAccessibleValueFromContext) + FIND_METHOD(getMaximumAccessibleValueFromContextMethod, bridgeClass, + "getMaximumAccessibleValueFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + // GetMethodID(getMinimumAccessibleValueFromContext) + FIND_METHOD(getMinimumAccessibleValueFromContextMethod, bridgeClass, + "getMinimumAccessibleValueFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + + // ------- AccessibleSelection methods + + // GetMethodID(addAccessibleSelectionFromContext) + FIND_METHOD(addAccessibleSelectionFromContextMethod, bridgeClass, + "addAccessibleSelectionFromContext", + "(Ljavax/accessibility/AccessibleContext;I)V"); + + // GetMethodID(clearAccessibleSelectionFromContext) + FIND_METHOD(clearAccessibleSelectionFromContextMethod, bridgeClass, + "clearAccessibleSelectionFromContext", + "(Ljavax/accessibility/AccessibleContext;)V"); + + // GetMethodID(getAccessibleSelectionFromContext) + FIND_METHOD(getAccessibleSelectionContextFromContextMethod, bridgeClass, + "getAccessibleSelectionFromContext", + "(Ljavax/accessibility/AccessibleContext;I)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(getAccessibleSelectionCountFromContext) + FIND_METHOD(getAccessibleSelectionCountFromContextMethod, bridgeClass, + "getAccessibleSelectionCountFromContext", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(isAccessibleChildSelectedFromContext) + FIND_METHOD(isAccessibleChildSelectedFromContextMethod, bridgeClass, + "isAccessibleChildSelectedFromContext", + "(Ljavax/accessibility/AccessibleContext;I)Z"); + + // GetMethodID(removeAccessibleSelectionFromContext) + FIND_METHOD(removeAccessibleSelectionFromContextMethod, bridgeClass, + "removeAccessibleSelectionFromContext", + "(Ljavax/accessibility/AccessibleContext;I)V"); + + // GetMethodID(selectAllAccessibleSelectionFromContext) + FIND_METHOD(selectAllAccessibleSelectionFromContextMethod, bridgeClass, + "selectAllAccessibleSelectionFromContext", + "(Ljavax/accessibility/AccessibleContext;)V"); + + + // ------- Event Notification methods + + // GetMethodID(addJavaEventNotification) + FIND_METHOD(addJavaEventNotificationMethod, bridgeClass, + "addJavaEventNotification", "(J)V"); + + // GetMethodID(removeJavaEventNotification) + FIND_METHOD(removeJavaEventNotificationMethod, bridgeClass, + "removeJavaEventNotification", "(J)V"); + + // GetMethodID(addAccessibilityEventNotification) + FIND_METHOD(addAccessibilityEventNotificationMethod, bridgeClass, + "addAccessibilityEventNotification", "(J)V"); + + // GetMethodID(removeAccessibilityEventNotification) + FIND_METHOD(removeAccessibilityEventNotificationMethod, bridgeClass, + "removeAccessibilityEventNotification", "(J)V"); + + + // ------- AttributeSet methods + + // GetMethodID(getBoldFromAttributeSet) + FIND_METHOD(getBoldFromAttributeSetMethod, bridgeClass, + "getBoldFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)Z"); + + // GetMethodID(getItalicFromAttributeSet) + FIND_METHOD(getItalicFromAttributeSetMethod, bridgeClass, + "getItalicFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)Z"); + + // GetMethodID(getUnderlineFromAttributeSet) + FIND_METHOD(getUnderlineFromAttributeSetMethod, bridgeClass, + "getUnderlineFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)Z"); + + // GetMethodID(getStrikethroughFromAttributeSet) + FIND_METHOD(getStrikethroughFromAttributeSetMethod, bridgeClass, + "getStrikethroughFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)Z"); + + // GetMethodID(getSuperscriptFromAttributeSet) + FIND_METHOD(getSuperscriptFromAttributeSetMethod, bridgeClass, + "getSuperscriptFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)Z"); + + // GetMethodID(getSubscriptFromAttributeSet) + FIND_METHOD(getSubscriptFromAttributeSetMethod, bridgeClass, + "getSubscriptFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)Z"); + + // GetMethodID(getBackgroundColorFromAttributeSet) + FIND_METHOD(getBackgroundColorFromAttributeSetMethod, bridgeClass, + "getBackgroundColorFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)Ljava/lang/String;"); + + // GetMethodID(getForegroundColorFromAttributeSet) + FIND_METHOD(getForegroundColorFromAttributeSetMethod, bridgeClass, + "getForegroundColorFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)Ljava/lang/String;"); + + // GetMethodID(getFontFamilyFromAttributeSet) + FIND_METHOD(getFontFamilyFromAttributeSetMethod, bridgeClass, + "getFontFamilyFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)Ljava/lang/String;"); + + // GetMethodID(getFontSizeFromAttributeSet) + FIND_METHOD(getFontSizeFromAttributeSetMethod, bridgeClass, + "getFontSizeFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)I"); + + // GetMethodID(getAlignmentFromAttributeSet) + FIND_METHOD(getAlignmentFromAttributeSetMethod, bridgeClass, + "getAlignmentFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)I"); + + // GetMethodID(getBidiLevelFromAttributeSet) + FIND_METHOD(getBidiLevelFromAttributeSetMethod, bridgeClass, + "getBidiLevelFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)I"); + + // GetMethodID(getFirstLineIndentFromAttributeSet) + FIND_METHOD(getFirstLineIndentFromAttributeSetMethod, bridgeClass, + "getFirstLineIndentFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)F"); + + // GetMethodID(getLeftIndentFromAttributeSet) + FIND_METHOD(getLeftIndentFromAttributeSetMethod, bridgeClass, + "getLeftIndentFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)F"); + + // GetMethodID(getRightIndentFromAttributeSet) + FIND_METHOD(getRightIndentFromAttributeSetMethod, bridgeClass, + "getRightIndentFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)F"); + + // GetMethodID(getLineSpacingFromAttributeSet) + FIND_METHOD(getLineSpacingFromAttributeSetMethod, bridgeClass, + "getLineSpacingFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)F"); + + // GetMethodID(getSpaceAboveFromAttributeSet) + FIND_METHOD(getSpaceAboveFromAttributeSetMethod, bridgeClass, + "getSpaceAboveFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)F"); + + // GetMethodID(getSpaceBelowFromAttributeSet) + FIND_METHOD(getSpaceBelowFromAttributeSetMethod, bridgeClass, + "getSpaceBelowFromAttributeSet", "(Ljavax/swing/text/AttributeSet;)F"); + + + /** + * Additional methods for Teton + */ + + // GetMethodID(requestFocus) + FIND_METHOD(requestFocusMethod, bridgeClass, + "requestFocus", + "(Ljavax/accessibility/AccessibleContext;)Z"); + + // GetMethodID(selectTextRange) + FIND_METHOD(selectTextRangeMethod, bridgeClass, + "selectTextRange", + "(Ljavax/accessibility/AccessibleContext;II)Z"); + + // GetMethodID(getVisibleChildrenCount) + FIND_METHOD(getVisibleChildrenCountMethod, bridgeClass, + "getVisibleChildrenCount", + "(Ljavax/accessibility/AccessibleContext;)I"); + + // GetMethodID(getVisibleChild) + FIND_METHOD(getVisibleChildMethod, bridgeClass, + "getVisibleChild", + "(Ljavax/accessibility/AccessibleContext;I)Ljavax/accessibility/AccessibleContext;"); + + // GetMethodID(setCaretPosition) + FIND_METHOD(setCaretPositionMethod, bridgeClass, + "setCaretPosition", + "(Ljavax/accessibility/AccessibleContext;I)Z"); + + // GetMethodID(getVirtualAccessibleNameFromContextMethod) Ben Key + FIND_METHOD(getVirtualAccessibleNameFromContextMethod, bridgeClass, + "getVirtualAccessibleNameFromContext", + "(Ljavax/accessibility/AccessibleContext;)Ljava/lang/String;"); + + return TRUE; +} + +// Note for the following code which makes JNI upcalls... +// +// Problem, bug DB 16818166, JBS DB JDK-8015400 +// AccessibleContext is a JOBJECT64 which is a jobject (32 bit pointer) +// for a Legacy (XP) build and a jlong (64 bits) for a -32 or -64 build. +// For the -32 build the lower 32 bits needs to be extracted into a jobject. +// Otherwise, if AccessibleContext is used directly what happens is that +// the JNI code consumes the lower 32 of its 64 bits and that is not a +// problem, but then when the JNI code consumes the next 32 bits for the +// reference to the role String it gets the higher 0x00000000 bits from +// the 64 bit JOBJECT64 AccessibleContext variable and thus a null reference +// is passed as the String reference. +// +// Solution: +// Cast the JOBJECT64 to a jobject. For a 64 bit compile this is basically +// a noop, i.e. JOBJECT64 is a 64 bit jlong and a jobject is a 64 bit reference. +// For a 32 bit compile the cast drops the high order 32 bits, i.e. JOBJECT64 +// is a 64 bit jlong and jobject is a 32 bit reference. For a Legacy build +// JOBJECT64 is a jobject so this is also basically a noop. The casts are +// done in the methods in JavaAccessBridge::processPackage. + +// ----------------------------------- + +/** + * isJavaWindow - returns whether the HWND is a Java window or not + * + */ +BOOL +AccessBridgeJavaEntryPoints::isJavaWindow(jint window) { + jthrowable exception; + BOOL returnVal; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::isJavaWindow(%X):", window); + + if (isJavaWindowMethod != (jmethodID) 0) { + returnVal = (BOOL) jniEnv->CallBooleanMethod(accessBridgeObject, isJavaWindowMethod, window); + EXCEPTION_CHECK("Getting isJavaWindow - call to CallBooleanMethod()", FALSE); + return returnVal; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or isJavaWindowMethod == 0"); + return FALSE; + } +} + +// ----------------------------------- + +/** + * isSameObject - returns whether two object reference refer to the same object + * + */ +BOOL +AccessBridgeJavaEntryPoints::isSameObject(jobject obj1, jobject obj2) { + jthrowable exception; + BOOL returnVal; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::isSameObject(%p %p):", obj1, obj2); + + returnVal = (BOOL) jniEnv->IsSameObject((jobject)obj1, (jobject)obj2); + EXCEPTION_CHECK("Calling IsSameObject", FALSE); + + PrintDebugString("\r\n isSameObject returning %d", returnVal); + return returnVal; +} + +// ----------------------------------- + +/** + * getAccessibleContextFromHWND - returns the AccessibleContext, if any, for an HWND + * + */ +jobject +AccessBridgeJavaEntryPoints::getAccessibleContextFromHWND(jint window) { + jobject returnedAccessibleContext; + jobject globalRef; + jthrowable exception; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::getAccessibleContextFromHWND(%X):", window); + + if (getAccessibleContextFromHWNDMethod != (jmethodID) 0) { + returnedAccessibleContext = + (jobject)jniEnv->CallObjectMethod(accessBridgeObject, getAccessibleContextFromHWNDMethod, + window); + EXCEPTION_CHECK("Getting AccessibleContextFromHWND - call to CallObjectMethod()", (jobject) 0); + globalRef = (jobject)jniEnv->NewGlobalRef((jobject)returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleContextFromHWND - call to CallObjectMethod()", (jobject) 0); + return globalRef; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or getAccessibleContextFromHWNDMethod == 0"); + return (jobject) 0; + } +} + +// ----------------------------------- + +/** + * getHWNDFromAccessibleContext - returns the HWND for an AccessibleContext, if any + * returns (HWND)0 on error. + */ +HWND +AccessBridgeJavaEntryPoints::getHWNDFromAccessibleContext(jobject accessibleContext) { + jthrowable exception; + HWND rHWND; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::getHWNDFromAccessibleContext(%X):", + accessibleContext); + + if (getHWNDFromAccessibleContextMethod != (jmethodID) 0) { + rHWND = (HWND)jniEnv->CallIntMethod(accessBridgeObject, getHWNDFromAccessibleContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting HWNDFromAccessibleContext - call to CallIntMethod()", (HWND)0); + PrintDebugString("\r\n rHWND = %X", rHWND); + return rHWND; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or getHWNDFromAccessibleContextMethod == 0"); + return (HWND)0; + } +} + + +/* ====== Utility methods ===== */ + +/** + * Sets a text field to the specified string. Returns whether successful; + */ +BOOL +AccessBridgeJavaEntryPoints::setTextContents(const jobject accessibleContext, const wchar_t *text) { + jthrowable exception; + BOOL result = FALSE; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::setTextContents(%p, %ls):", + accessibleContext, text); + + if (setTextContentsMethod != (jmethodID) 0) { + + // create a Java String for the text + jstring textString = jniEnv->NewString(text, (jsize)wcslen(text)); + if (textString == 0) { + PrintDebugString("\r NewString failed"); + return FALSE; + } + + result = (BOOL)jniEnv->CallBooleanMethod(accessBridgeObject, + setTextContentsMethod, + accessibleContext, textString); + EXCEPTION_CHECK("setTextContents - call to CallBooleanMethod()", FALSE); + PrintDebugString("\r\n result = %d", result); + return result; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or setTextContentsMethod == 0"); + return result; + } +} + +/** + * Returns the Accessible Context of a Page Tab object that is the + * ancestor of a given object. If the object is a Page Tab object + * or a Page Tab ancestor object was found, returns the object + * AccessibleContext. + * If there is no ancestor object that has an Accessible Role of Page Tab, + * returns (AccessibleContext)0. + */ +jobject +AccessBridgeJavaEntryPoints::getParentWithRole(const jobject accessibleContext, const wchar_t *role) { + jthrowable exception; + jobject rAccessibleContext; + + PrintDebugString("In AccessBridgeJavaEntryPoints::getParentWithRole(%p):", + accessibleContext); + + if (getParentWithRoleMethod != (jmethodID) 0) { + // create a Java String for the role + jstring roleName = jniEnv->NewString(role, (jsize)wcslen(role)); + if (roleName == 0) { + PrintDebugString(" NewString failed"); + return FALSE; + } + + rAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, + getParentWithRoleMethod, + accessibleContext, roleName); + EXCEPTION_CHECK("Getting ParentWithRole - call to CallObjectMethod()", (AccessibleContext)0); + PrintDebugString(" rAccessibleContext = %p", rAccessibleContext); + jobject globalRef = jniEnv->NewGlobalRef(rAccessibleContext); + EXCEPTION_CHECK("Getting ParentWithRole - call to NewGlobalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + rAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or getParentWithRoleMethod == 0"); + return 0; + } +} + +/** + * Returns the Accessible Context for the top level object in + * a Java Window. This is same Accessible Context that is obtained + * from GetAccessibleContextFromHWND for that window. Returns + * (AccessibleContext)0 on error. + */ +jobject +AccessBridgeJavaEntryPoints::getTopLevelObject(const jobject accessibleContext) { + jthrowable exception; + jobject rAccessibleContext; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::getTopLevelObject(%p):", + accessibleContext); + + if (getTopLevelObjectMethod != (jmethodID) 0) { + rAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, + getTopLevelObjectMethod, + accessibleContext); + EXCEPTION_CHECK("Getting TopLevelObject - call to CallObjectMethod()", FALSE); + PrintDebugString("\r\n rAccessibleContext = %p", rAccessibleContext); + jobject globalRef = jniEnv->NewGlobalRef(rAccessibleContext); + EXCEPTION_CHECK("Getting TopLevelObject - call to NewGlobalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + rAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or getTopLevelObjectMethod == 0"); + return 0; + } +} + +/** + * If there is an Ancestor object that has an Accessible Role of + * Internal Frame, returns the Accessible Context of the Internal + * Frame object. Otherwise, returns the top level object for that + * Java Window. Returns (AccessibleContext)0 on error. + */ +jobject +AccessBridgeJavaEntryPoints::getParentWithRoleElseRoot(const jobject accessibleContext, const wchar_t *role) { + jthrowable exception; + jobject rAccessibleContext; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::getParentWithRoleElseRoot(%p):", + accessibleContext); + + if (getParentWithRoleElseRootMethod != (jmethodID) 0) { + + // create a Java String for the role + jstring roleName = jniEnv->NewString(role, (jsize)wcslen(role)); + if (roleName == 0) { + PrintDebugString("\r NewString failed"); + return FALSE; + } + + rAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, + getParentWithRoleElseRootMethod, + accessibleContext, roleName); + EXCEPTION_CHECK("Getting ParentWithRoleElseRoot - call to CallObjectMethod()", (AccessibleContext)0); + PrintDebugString(" rAccessibleContext = %p", rAccessibleContext); + jobject globalRef = jniEnv->NewGlobalRef(rAccessibleContext); + EXCEPTION_CHECK("Getting ParentWithRoleElseRoot - call to NewGlobalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + rAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or getParentWithRoleElseRootMethod == 0"); + return 0; + } +} + +/** + * Returns how deep in the object hierarchy a given object is. + * The top most object in the object hierarchy has an object depth of 0. + * Returns -1 on error. + */ +jint +AccessBridgeJavaEntryPoints::getObjectDepth(const jobject accessibleContext) { + jthrowable exception; + jint rResult; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::getObjectDepth(%p):", + accessibleContext); + + if (getObjectDepthMethod != (jmethodID) 0) { + rResult = jniEnv->CallIntMethod(accessBridgeObject, + getObjectDepthMethod, + accessibleContext); + EXCEPTION_CHECK("Getting ObjectDepth - call to CallIntMethod()", -1); + PrintDebugString("\r\n rResult = %d", rResult); + return rResult; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or getObjectDepthMethod == 0"); + return -1; + } +} + + + +/** + * Returns the Accessible Context of the current ActiveDescendent of an object. + * Returns 0 on error. + */ +jobject +AccessBridgeJavaEntryPoints::getActiveDescendent(const jobject accessibleContext) { + jthrowable exception; + jobject rAccessibleContext; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::getActiveDescendent(%p):", + accessibleContext); + + if (getActiveDescendentMethod != (jmethodID) 0) { + rAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, + getActiveDescendentMethod, + accessibleContext); + EXCEPTION_CHECK("Getting ActiveDescendent - call to CallObjectMethod()", (AccessibleContext)0); + PrintDebugString("\r\n rAccessibleContext = %p", rAccessibleContext); + jobject globalRef = jniEnv->NewGlobalRef(rAccessibleContext); + EXCEPTION_CHECK("Getting ActiveDescendant - call to NewGlobalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + rAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or getActiveDescendentMethod == 0"); + return (AccessibleContext)0; + } +} + +/** + * Additional methods for Teton + */ + +/** + * Returns an AccessibleName for a component using an algorithm optimized + * for the JAWS screen reader by Ben Key (Freedom Scientific). This method + * is only intended for JAWS. All other uses are entirely optional. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ +BOOL +AccessBridgeJavaEntryPoints::getVirtualAccessibleName ( + IN const jobject object, + OUT wchar_t * name, + IN const int nameSize) +{ + /* + + + Parameter validation + + + */ + if ((name == 0) || (nameSize == 0)) + { + return FALSE; + } + ::memset (name, 0, nameSize * sizeof (wchar_t)); + if (0 == object) + { + return FALSE; + } + + jstring js = NULL; + const wchar_t * stringBytes = NULL; + jthrowable exception = NULL; + jsize length = 0; + PrintDebugString("\r\n getVirtualAccessibleName called."); + if (getVirtualAccessibleNameFromContextMethod != (jmethodID) 0) + { + js = (jstring) jniEnv->CallObjectMethod ( + accessBridgeObject, + getVirtualAccessibleNameFromContextMethod, + object); + EXCEPTION_CHECK("Getting AccessibleName - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) + { + stringBytes = (const wchar_t *) jniEnv->GetStringChars (js, 0); + EXCEPTION_CHECK("Getting AccessibleName - call to GetStringChars()", FALSE); + wcsncpy(name, stringBytes, nameSize - 1); + length = jniEnv->GetStringLength(js); + EXCEPTION_CHECK("Getting AccessibleName - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleName - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod ( + accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleName - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Name = %ls", name); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleName - call to DeleteLocalRef()", FALSE); + } + else + { + PrintDebugString(" Accessible Name is null."); + } + } + else + { + PrintDebugString("\r\n Error! either jniEnv == 0 or getVirtualAccessibleNameFromContextMethod == 0"); + return FALSE; + } + if ( 0 != name [0] ) + { + return TRUE; + } + return FALSE; +} + + +/** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ +BOOL +AccessBridgeJavaEntryPoints::requestFocus(const jobject accessibleContext) { + + jthrowable exception; + BOOL result = FALSE; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::requestFocus(%p):", + accessibleContext); + + if (requestFocusMethod != (jmethodID) 0) { + result = (BOOL)jniEnv->CallBooleanMethod(accessBridgeObject, + requestFocusMethod, + accessibleContext); + EXCEPTION_CHECK("requestFocus - call to CallBooleanMethod()", FALSE); + PrintDebugString("\r\n result = %d", result); + return result; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or requestFocusMethod == 0"); + return result; + } +} + +/** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ +BOOL +AccessBridgeJavaEntryPoints::selectTextRange(const jobject accessibleContext, int startIndex, int endIndex) { + + jthrowable exception; + BOOL result = FALSE; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::selectTextRange(%p start = %d end = %d):", + accessibleContext, startIndex, endIndex); + + if (selectTextRangeMethod != (jmethodID) 0) { + result = (BOOL)jniEnv->CallBooleanMethod(accessBridgeObject, + selectTextRangeMethod, + accessibleContext, + startIndex, endIndex); + EXCEPTION_CHECK("selectTextRange - call to CallBooleanMethod()", FALSE); + PrintDebugString("\r\n result = %d", result); + return result; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or selectTextRangeMethod == 0"); + return result; + } +} + +/* + * Returns whether two text attributes are the same. + */ +static BOOL CompareAccessibleTextAttributesInfo(AccessibleTextAttributesInfo *one, + AccessibleTextAttributesInfo *two) { + return(one->bold == two->bold + && one->italic == two->italic + && one->underline == two->underline + && one->strikethrough == two->strikethrough + && one->superscript == two->superscript + && one->subscript == two->subscript + && one->fontSize == two->fontSize + && one->alignment == two->alignment + && one->bidiLevel == two->bidiLevel + && one->firstLineIndent == two->firstLineIndent + && one->leftIndent == two->leftIndent + && one->rightIndent == two->rightIndent + && one->lineSpacing == two->lineSpacing + && one->spaceAbove == two->spaceAbove + && one->spaceBelow == two->spaceBelow + && !wcscmp(one->backgroundColor,two->backgroundColor) + && !wcscmp(one->foregroundColor,two->foregroundColor) + && !wcscmp(one->fullAttributesString,two->fullAttributesString)); +} + +/** + * Get text attributes between two indices. + * + * Only one AccessibleTextAttributesInfo structure is passed - which + * contains the attributes for the first character, the function then goes + * through the following characters in the range specified and stops when the + * attributes are different from the first, it then returns in the passed + * parameter len the number of characters with the attributes returned. In most + * situations this will be all the characters, and if not the calling program + * can easily get the attributes for the next characters with different + * attributes + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + +/* NEW FASTER CODE!!*/ +BOOL +AccessBridgeJavaEntryPoints::getTextAttributesInRange(const jobject accessibleContext, + int startIndex, int endIndex, + AccessibleTextAttributesInfo *attributes, short *len) { + + jstring js; + const wchar_t *stringBytes; + jthrowable exception; + jsize length; + BOOL result = FALSE; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::getTextAttributesInRange(%p start = %d end = %d):", + accessibleContext, startIndex, endIndex); + + *len = 0; + result = getAccessibleTextAttributes((jobject)accessibleContext, startIndex, attributes); + if (result != TRUE) { + return FALSE; + } + (*len)++; + + for (jint i = startIndex+1; i <= endIndex; i++) { + + AccessibleTextAttributesInfo test_attributes = *attributes; + // Get the full test_attributes string at i + if (getAccessibleAttributesAtIndexFromContextMethod != (jmethodID) 0) { + PrintDebugString(" Getting full test_attributes string from Context..."); + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleAttributesAtIndexFromContextMethod, + accessibleContext, i); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to CallObjectMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to GetStringChars()", FALSE); + wcsncpy(test_attributes.fullAttributesString, stringBytes, (sizeof(test_attributes.fullAttributesString) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + test_attributes.fullAttributesString[length < (sizeof(test_attributes.fullAttributesString) / sizeof(wchar_t)) ? + length : (sizeof(test_attributes.fullAttributesString) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Text attributes = %ls", test_attributes.fullAttributesString); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible Text attributes is null."); + test_attributes.fullAttributesString[0] = (wchar_t) 0; + return FALSE; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleAttributesAtIndexFromContextMethod == 0"); + return FALSE; + } + + if(wcscmp(attributes->fullAttributesString,test_attributes.fullAttributesString)) + break; + if (result != TRUE) { + return FALSE; + } + (*len)++; + } + return TRUE; +} + +/* + * Returns the number of visible children of a component + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ +int +AccessBridgeJavaEntryPoints::getVisibleChildrenCount(const jobject accessibleContext) { + + jthrowable exception; + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getVisibleChildrenCount(%p)", + accessibleContext); + + // get the visible children count + int numChildren = jniEnv->CallIntMethod(accessBridgeObject, getVisibleChildrenCountMethod, + accessibleContext); + EXCEPTION_CHECK("##### Getting visible children count - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### visible children count = %d", numChildren); + + return numChildren; +} + + +/* + * This method is used to iterate through the visible children of a component. It + * returns visible children information for a component starting at nStartIndex. + * No more than MAX_VISIBLE_CHILDREN VisibleChildrenInfo objects will + * be returned for each call to this method. Returns FALSE on error. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ +BOOL AccessBridgeJavaEntryPoints::getVisibleChildren(const jobject accessibleContext, + const int nStartIndex, + /* OUT */ VisibleChildrenInfo *visibleChildrenInfo) { + + jthrowable exception; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getVisibleChildren(%p, startIndex = %d)", + accessibleContext, nStartIndex); + + // get the visible children count + int numChildren = jniEnv->CallIntMethod(accessBridgeObject, getVisibleChildrenCountMethod, + accessibleContext); + EXCEPTION_CHECK("##### Getting visible children count - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### visible children count = %d", numChildren); + + if (nStartIndex >= numChildren) { + return FALSE; + } + + // get the visible children + int bufIndex = 0; + for (int i = nStartIndex; (i < numChildren) && (i < nStartIndex + MAX_VISIBLE_CHILDREN); i++) { + PrintDebugString(" getting visible child %d ...", i); + + // get the visible child at index i + jobject ac = jniEnv->CallObjectMethod(accessBridgeObject, getVisibleChildMethod, + accessibleContext, i); + EXCEPTION_CHECK("##### getVisibleChildMethod - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(ac); + EXCEPTION_CHECK("##### getVisibleChildMethod - call to NewGlobalRef()", FALSE); + visibleChildrenInfo->children[bufIndex] = (JOBJECT64)globalRef; + PrintDebugString(" ##### visible child = %p", globalRef); + + bufIndex++; + } + visibleChildrenInfo->returnedChildrenCount = bufIndex; + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getVisibleChildren succeeded"); + return TRUE; +} + +/** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ +BOOL +AccessBridgeJavaEntryPoints::setCaretPosition(const jobject accessibleContext, int position) { + + jthrowable exception; + BOOL result = FALSE; + + PrintDebugString("\r\nIn AccessBridgeJavaEntryPoints::setCaretPostion(%p position = %d):", + accessibleContext, position); + + if (setCaretPositionMethod != (jmethodID) 0) { + result = (BOOL)jniEnv->CallBooleanMethod(accessBridgeObject, + setCaretPositionMethod, + accessibleContext, position); + EXCEPTION_CHECK("setCaretPostion - call to CallBooleanMethod()", FALSE); + PrintDebugString("\r\n result = %d", result); + return result; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or setCaretPositionMethod == 0"); + return result; + } +} + + +// ----------------------------------- + +/** + * getVersionInfo - returns the version string of the java.version property + * and the AccessBridge.java version + * + */ +BOOL +AccessBridgeJavaEntryPoints::getVersionInfo(AccessBridgeVersionInfo *info) { + jstring js; + const wchar_t *stringBytes; + jthrowable exception; + jsize length; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getVersionInfo():"); + + if (getJavaVersionPropertyMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getJavaVersionPropertyMethod); + EXCEPTION_CHECK("Getting JavaVersionProperty - call to CallObjectMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + length = jniEnv->GetStringLength(js); + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + if (stringBytes == NULL) { + if (!jniEnv->ExceptionCheck()) { + PrintDebugString("\r\n *** Exception when getting JavaVersionProperty - call to GetStringChars"); + jniEnv->ExceptionDescribe(); + jniEnv->ExceptionClear(); + } + return FALSE; + } + wcsncpy(info->bridgeJavaDLLVersion, + stringBytes, + sizeof(info->bridgeJavaDLLVersion) / sizeof(wchar_t)); + info->bridgeJavaDLLVersion[length < (sizeof(info->bridgeJavaDLLVersion) / sizeof(wchar_t)) ? + length : (sizeof(info->bridgeJavaDLLVersion) / sizeof(wchar_t))-2] = (wchar_t) 0; + wcsncpy(info->VMversion, + stringBytes, + sizeof(info->VMversion) / sizeof(wchar_t)); + info->VMversion[length < (sizeof(info->VMversion) / sizeof(wchar_t)) ? + length : (sizeof(info->VMversion) / sizeof(wchar_t))-2] = (wchar_t) 0; + wcsncpy(info->bridgeJavaClassVersion, + stringBytes, + sizeof(info->bridgeJavaClassVersion) / sizeof(wchar_t)); + info->bridgeJavaClassVersion[length < (sizeof(info->bridgeJavaClassVersion) / sizeof(wchar_t)) ? + length : (sizeof(info->bridgeJavaClassVersion) / sizeof(wchar_t))-2] = (wchar_t) 0; + wcsncpy(info->bridgeWinDLLVersion, + stringBytes, + sizeof(info->bridgeWinDLLVersion) / sizeof(wchar_t)); + info->bridgeWinDLLVersion[length < (sizeof(info->bridgeWinDLLVersion) / sizeof(wchar_t)) ? + length : (sizeof(info->bridgeWinDLLVersion) / sizeof(wchar_t))-2] = (wchar_t) 0; + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting JavaVersionProperty - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting JavaVersionProperty - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Java version = %ls", info->VMversion); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting JavaVersionProperty - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Java version is null."); + info->VMversion[0] = (wchar_t) 0; + return FALSE; + } + } else { + PrintDebugString(" Error! either env == 0 or getJavaVersionPropertyMethod == 0"); + return FALSE; + } + + return TRUE; +} + + +/* + * Verifies the Java VM still exists and obj is an + * instance of AccessibleText + */ +BOOL AccessBridgeJavaEntryPoints::verifyAccessibleText(jobject obj) { + JavaVM *vm; + BOOL retval; + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::verifyAccessibleText"); + + if (jniEnv->GetJavaVM(&vm) != 0) { + PrintDebugString(" Error! No Java VM"); + return FALSE; + } + + if (obj == (jobject)0) { + PrintDebugString(" Error! Null jobject"); + return FALSE; + } + + // Copied from getAccessibleContextInfo + if (getAccessibleTextFromContextMethod != (jmethodID) 0) { + jobject returnedJobject = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTextFromContextMethod, + (jobject)obj); + EXCEPTION_CHECK("Getting AccessibleText - call to CallObjectMethod()", FALSE); + PrintDebugString(" AccessibleText = %p", returnedJobject); + retval = returnedJobject != (jobject) 0; + jniEnv->DeleteLocalRef(returnedJobject); + EXCEPTION_CHECK("Getting AccessibleText - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTextFromContextMethod == 0"); + return FALSE; + } + if (retval == FALSE) { + PrintDebugString(" Error! jobject is not an AccessibleText"); + } + return retval; +} + + +/********** AccessibleContext routines ***********************************/ + +/** + * getAccessibleContextAt - performs the Java method call: + * Accessible AccessBridge.getAccessibleContextAt(x, y) + * + * Note: this call explicitly goes through the AccessBridge, + * so that it can keep a reference the returned jobject for the JavaVM. + * You must explicity call INTreleaseJavaObject() when you are through using + * the Accessible returned, to let the AccessBridge know it can release the + * object, so that the can then garbage collect it. + * + */ +jobject +AccessBridgeJavaEntryPoints::getAccessibleContextAt(jint x, jint y, jobject accessibleContext) { + jobject returnedAccessibleContext; + jobject globalRef; + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleContextAt(%d, %d, %p):", + x, y, accessibleContext); + + if (getAccessibleContextAtMethod != (jmethodID) 0) { + returnedAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleContextAtMethod, + x, y, accessibleContext); + EXCEPTION_CHECK("Getting AccessibleContextAt - call to CallObjectMethod()", FALSE); + globalRef = jniEnv->NewGlobalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleContextAt - call to NewGlobalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + returnedAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleContextAtMethod == 0"); + return (jobject) 0; + } +} + +/** + * getAccessibleWithFocus - performs the Java method calls: + * Accessible Translator.getAccessible(SwingEventMonitor.getComponentWithFocus(); + * + * Note: this call explicitly goes through the AccessBridge, + * so that the AccessBridge can hide expected changes in how this functions + * between JDK 1.1.x w/AccessibilityUtility classes, and JDK 1.2, when some + * of this functionality may be built into the platform + * + */ +jobject +AccessBridgeJavaEntryPoints::getAccessibleContextWithFocus() { + jobject returnedAccessibleContext; + jobject globalRef; + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleContextWithFocus()"); + + if (getAccessibleContextWithFocusMethod != (jmethodID) 0) { + returnedAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleContextWithFocusMethod); + EXCEPTION_CHECK("Getting AccessibleContextWithFocus - call to CallObjectMethod()", FALSE); + globalRef = jniEnv->NewGlobalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleContextWithFocus - call to NewGlobalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + returnedAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString(" Error! either jniEnv == 0 or getAccessibleContextWithFocusMethod == 0"); + return (jobject) 0; + } +} + +/** + * getAccessibleContextInfo - fills a struct with a bunch of information + * contained in the Java Accessibility API + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + * + * Note: this call explicitly goes through the AccessBridge, + * so that it can keep a reference the returned jobject for the JavaVM. + * You must explicity call releaseJavaObject() when you are through using + * the AccessibleContext returned, to let the AccessBridge know it can release the + * object, so that the JavaVM can then garbage collect it. + */ +BOOL +AccessBridgeJavaEntryPoints::getAccessibleContextInfo(jobject accessibleContext, AccessibleContextInfo *info) { + jstring js; + const wchar_t *stringBytes; + jobject returnedJobject; + jthrowable exception; + jsize length; + + PrintDebugString("\r\n##### Calling AccessBridgeJavaEntryPoints::getAccessibleContextInfo(%p):", accessibleContext); + + ZeroMemory(info, sizeof(AccessibleContextInfo)); + + if (accessibleContext == (jobject) 0) { + PrintDebugString(" passed in AccessibleContext == null! (oops)"); + return (FALSE); + } + + // Get the Accessible Name + if (getAccessibleNameFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleNameFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleName - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleName - call to GetStringChars()", FALSE); + wcsncpy(info->name, stringBytes, (sizeof(info->name) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + info->name[length < (sizeof(info->name) / sizeof(wchar_t)) ? + length : (sizeof(info->name) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleName - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleName - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleName - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Name = %ls", info->name); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleName - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible Name is null."); + info->name[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleNameFromContextMethod == 0"); + return FALSE; + } + + + // Get the Accessible Description + if (getAccessibleDescriptionFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleDescriptionFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleDescription - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleName - call to GetStringChars()", FALSE); + wcsncpy(info->description, stringBytes, (sizeof(info->description) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + info->description[length < (sizeof(info->description) / sizeof(wchar_t)) ? + length : (sizeof(info->description) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleName - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleName - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleName - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Description = %ls", info->description); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleName - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible Description is null."); + info->description[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleDescriptionFromContextMethod == 0"); + return FALSE; + } + + + // Get the Accessible Role String + if (getAccessibleRoleStringFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleRoleStringFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleRole - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleRole - call to GetStringChars()", FALSE); + wcsncpy(info->role, stringBytes, (sizeof(info->role) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + info->role[length < (sizeof(info->role) / sizeof(wchar_t)) ? + length : (sizeof(info->role) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleRole - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleRole - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleRole - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Role = %ls", info->role); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleRole - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible Role is null."); + info->role[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleRoleStringFromContextMethod == 0"); + return FALSE; + } + + + // Get the Accessible Role String in the en_US locale + if (getAccessibleRoleStringFromContext_en_USMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleRoleStringFromContext_en_USMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to GetStringChars()", FALSE); + wcsncpy(info->role_en_US, stringBytes, (sizeof(info->role_en_US) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + info->role_en_US[length < (sizeof(info->role_en_US) / sizeof(wchar_t)) ? + length : (sizeof(info->role_en_US) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Role en_US = %ls", info->role_en_US); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleRole_en_US - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible Role en_US is null."); + info->role[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleRoleStringFromContext_en_USMethod == 0"); + return FALSE; + } + + // Get the Accessible States String + if (getAccessibleStatesStringFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleStatesStringFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleState - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleState - call to GetStringChars()", FALSE); + wcsncpy(info->states, stringBytes, (sizeof(info->states) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + info->states[length < (sizeof(info->states) / sizeof(wchar_t)) ? + length : (sizeof(info->states) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleState - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleState - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleState - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible States = %ls", info->states); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleState - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible States is null."); + info->states[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleStatesStringFromContextMethod == 0"); + return FALSE; + } + + // Get the Accessible States String in the en_US locale + if (getAccessibleStatesStringFromContext_en_USMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleStatesStringFromContext_en_USMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleState_en_US - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleState_en_US - call to GetStringChars()", FALSE); + wcsncpy(info->states_en_US, stringBytes, (sizeof(info->states_en_US) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + info->states_en_US[length < (sizeof(info->states_en_US) / sizeof(wchar_t)) ? + length : (sizeof(info->states_en_US) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleState_en_US - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleState_en_US - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleState_en_US - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible States en_US = %ls", info->states_en_US); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleState_en_US - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible States en_US is null."); + info->states[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleStatesStringFromContext_en_USMethod == 0"); + return FALSE; + } + + + // Get the index in Parent + if (getAccessibleIndexInParentFromContextMethod != (jmethodID) 0) { + info->indexInParent = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleIndexInParentFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleIndexInParent - call to CallIntMethod()", FALSE); + PrintDebugString(" Index in Parent = %d", info->indexInParent); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleIndexInParentFromContextMethod == 0"); + return FALSE; + } + + + PrintDebugString("*** jniEnv: %p; accessBridgeObject: %p; AccessibleContext: %p ***", + jniEnv, accessBridgeObject, accessibleContext); + + // Get the children count + if (getAccessibleChildrenCountFromContextMethod != (jmethodID) 0) { + info->childrenCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleChildrenCountFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleChildrenCount - call to CallIntMethod()", FALSE); + PrintDebugString(" Children count = %d", info->childrenCount); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleChildrenCountFromContextMethod == 0"); + return FALSE; + } + + PrintDebugString("*** jniEnv: %p; accessBridgeObject: %p; AccessibleContext: %X ***", + jniEnv, accessBridgeObject, accessibleContext); + + + // Get the x coord + if (getAccessibleXcoordFromContextMethod != (jmethodID) 0) { + info->x = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleXcoordFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleXcoord - call to CallIntMethod()", FALSE); + PrintDebugString(" X coord = %d", info->x); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleXcoordFromContextMethod == 0"); + return FALSE; + } + + PrintDebugString("*** jniEnv: %X; accessBridgeObject: %X; AccessibleContext: %p ***", + jniEnv, accessBridgeObject, accessibleContext); + + + // Get the y coord + if (getAccessibleYcoordFromContextMethod != (jmethodID) 0) { + info->y = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleYcoordFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleYcoord - call to CallIntMethod()", FALSE); + PrintDebugString(" Y coord = %d", info->y); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleYcoordFromContextMethod == 0"); + return FALSE; + } + + // Get the width + if (getAccessibleWidthFromContextMethod != (jmethodID) 0) { + info->width = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleWidthFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleWidth - call to CallIntMethod()", FALSE); + PrintDebugString(" Width = %d", info->width); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleWidthFromContextMethod == 0"); + return FALSE; + } + + // Get the height + if (getAccessibleHeightFromContextMethod != (jmethodID) 0) { + info->height = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleHeightFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleHeight - call to CallIntMethod()", FALSE); + PrintDebugString(" Height = %d", info->height); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleHeightFromContextMethod == 0"); + return FALSE; + } + + // Get the AccessibleComponent + if (getAccessibleComponentFromContextMethod != (jmethodID) 0) { + returnedJobject = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleComponentFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleComponent - call to CallObjectMethod()", FALSE); + PrintDebugString(" AccessibleComponent = %p", returnedJobject); + info->accessibleComponent = (returnedJobject != (jobject) 0 ? TRUE : FALSE); + jniEnv->DeleteLocalRef(returnedJobject); + EXCEPTION_CHECK("Getting AccessibleComponent - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleComponentFromContextMethod == 0"); + return FALSE; + } + + // Get the AccessibleAction + if (getAccessibleActionFromContextMethod != (jmethodID) 0) { + returnedJobject = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleActionFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleAction - call to CallObjectMethod()", FALSE); + PrintDebugString(" AccessibleAction = %p", returnedJobject); + info->accessibleAction = (returnedJobject != (jobject) 0 ? TRUE : FALSE); + jniEnv->DeleteLocalRef(returnedJobject); + EXCEPTION_CHECK("Getting AccessibleAction - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleActionFromContextMethod == 0"); + return FALSE; + } + + // Get the AccessibleSelection + if (getAccessibleSelectionFromContextMethod != (jmethodID) 0) { + returnedJobject = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleSelectionFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleSelection - call to CallObjectMethod()", FALSE); + PrintDebugString(" AccessibleSelection = %p", returnedJobject); + info->accessibleSelection = (returnedJobject != (jobject) 0 ? TRUE : FALSE); + jniEnv->DeleteLocalRef(returnedJobject); + EXCEPTION_CHECK("Getting AccessibleSelection - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleSelectionFromContextMethod == 0"); + return FALSE; + } + + // Get the AccessibleTable + if (getAccessibleTableFromContextMethod != (jmethodID) 0) { + PrintDebugString("##### Calling getAccessibleTableFromContextMethod ..."); + returnedJobject = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTableFromContextMethod, + accessibleContext); + PrintDebugString("##### ... Returned from getAccessibleTableFromContextMethod"); + EXCEPTION_CHECK("##### Getting AccessibleTable - call to CallObjectMethod()", FALSE); + PrintDebugString(" ##### AccessibleTable = %p", returnedJobject); + if (returnedJobject != (jobject) 0) { + info->accessibleInterfaces |= cAccessibleTableInterface; + } + jniEnv->DeleteLocalRef(returnedJobject); + EXCEPTION_CHECK("##### Getting AccessibleTable - call to DeleteLocalRef()", FALSE); + + /* + returnedJobject = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTableFromContextMethod, + AccessibleContext); + PrintDebugString("##### ... Returned from getAccessibleTableFromContextMethod"); + EXCEPTION_CHECK("##### Getting AccessibleTable - call to CallObjectMethod()", FALSE); + PrintDebugString(" ##### AccessibleTable = %X", returnedJobject); + info->accessibleTable = returnedJobject; + */ + + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableFromContextMethod == 0"); + return FALSE; + } + + // Get the AccessibleText + if (getAccessibleTextFromContextMethod != (jmethodID) 0) { + returnedJobject = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTextFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleText - call to CallObjectMethod()", FALSE); + PrintDebugString(" AccessibleText = %p", returnedJobject); + info->accessibleText = (returnedJobject != (jobject) 0 ? TRUE : FALSE); + jniEnv->DeleteLocalRef(returnedJobject); + EXCEPTION_CHECK("Getting AccessibleText - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTextFromContextMethod == 0"); + return FALSE; + } + + // Get the AccessibleValue + if (getAccessibleValueFromContextMethod != (jmethodID) 0) { + returnedJobject = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleValueFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleValue - call to CallObjectMethod()", FALSE); + PrintDebugString(" AccessibleValue = %p", returnedJobject); + if (returnedJobject != (jobject) 0) { + info->accessibleInterfaces |= cAccessibleValueInterface; + } + jniEnv->DeleteLocalRef(returnedJobject); + EXCEPTION_CHECK("Getting AccessibleValue - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleValueFromContextMethod == 0"); + return FALSE; + } + + // FIX + // get the AccessibleHypertext + if (getAccessibleHypertextMethod != (jmethodID) 0 && + getAccessibleHyperlinkCountMethod != (jmethodID) 0 && + getAccessibleHyperlinkMethod != (jmethodID) 0 && + getAccessibleHyperlinkTextMethod != (jmethodID) 0 && + getAccessibleHyperlinkStartIndexMethod != (jmethodID) 0 && + getAccessibleHyperlinkEndIndexMethod != (jmethodID) 0) { + returnedJobject = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleHypertextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleHypertext - call to CallObjectMethod()", FALSE); + PrintDebugString(" AccessibleHypertext = %p", + returnedJobject); + if (returnedJobject != (jobject) 0) { + info->accessibleInterfaces |= cAccessibleHypertextInterface; + } + jniEnv->DeleteLocalRef(returnedJobject); + EXCEPTION_CHECK("Getting AccessibleHypertext - call to DeleteLocalRef()", FALSE); + } + + // set new accessibleInterfaces flags from old BOOL values + if(info->accessibleComponent) + info->accessibleInterfaces |= cAccessibleComponentInterface; + if(info->accessibleAction) + info->accessibleInterfaces |= cAccessibleActionInterface; + if(info->accessibleSelection) + info->accessibleInterfaces |= cAccessibleSelectionInterface; + if(info->accessibleText) + info->accessibleInterfaces |= cAccessibleTextInterface; + // FIX END + + return TRUE; +} + +/** + * getAccessibleChildFromContext - performs the Java method call: + * AccessibleContext AccessBridge.getAccessibleChildContext(AccessibleContext) + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + * + * Note: this call explicitly goes through the AccessBridge, + * so that it can keep a reference the returned jobject for the JavaVM. + * You must explicity call releaseJavaObject() when you are through using + * the AccessibleContext returned, to let the AccessBridge know it can release the + * object, so that the JavaVM can then garbage collect it. + */ +jobject +AccessBridgeJavaEntryPoints::getAccessibleChildFromContext(jobject accessibleContext, jint childIndex) { + jobject returnedAccessibleContext; + jobject globalRef; + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleChildContext(%p, %d):", + accessibleContext, childIndex); + + if (getAccessibleChildFromContextMethod != (jmethodID) 0) { + returnedAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleChildFromContextMethod, + accessibleContext, childIndex); + EXCEPTION_CHECK("Getting AccessibleChild - call to CallObjectMethod()", FALSE); + globalRef = jniEnv->NewGlobalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleChild - call to NewGlobalRef()", FALSE); + jniEnv->DeleteLocalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleChild - call to DeleteLocalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + returnedAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleChildContextMethod == 0"); + return (jobject) 0; + } +} + +/** + * getAccessibleParentFromContext - returns the AccessibleContext parent + * + */ +jobject +AccessBridgeJavaEntryPoints::getAccessibleParentFromContext(jobject accessibleContext) +{ + jobject returnedAccessibleContext; + jobject globalRef; + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleParentFromContext(%p):", accessibleContext); + + if (getAccessibleParentFromContextMethod != (jmethodID) 0) { + returnedAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleParentFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleParent - call to CallObjectMethod()", FALSE); + globalRef = jniEnv->NewGlobalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleParent - call to NewGlobalRef()", FALSE); + jniEnv->DeleteLocalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleParent - call to DeleteLocalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + returnedAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleParentFromContextMethod == 0"); + return (jobject) 0; + } +} + + +/********** AccessibleTable routines **********************************/ + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTableInfo(jobject accessibleContext, + AccessibleTableInfo *tableInfo) { + + jthrowable exception; + + PrintDebugString("\r\n##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableInfo(%p):", + accessibleContext); + + // get the table row count + if (getAccessibleTableRowCountMethod != (jmethodID) 0) { + tableInfo->rowCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableRowCountMethod, + accessibleContext); + EXCEPTION_CHECK("##### Getting AccessibleTableRowCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table row count = %d", tableInfo->rowCount); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleRowCountMethod == 0"); + return FALSE; + } + + // get the table column count + if (getAccessibleTableColumnCountMethod != (jmethodID) 0) { + tableInfo->columnCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableColumnCountMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleTableColumnCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table column count = %d", tableInfo->columnCount); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableColumnCountMethod == 0"); + return FALSE; + } + + // get the AccessibleTable + if (getAccessibleTableFromContextMethod != (jmethodID) 0) { + PrintDebugString("##### Calling getAccessibleTableFromContextMethod ..."); + jobject accTable = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTableFromContextMethod, + accessibleContext); + PrintDebugString("##### ... Returned from getAccessibleTableFromContextMethod"); + EXCEPTION_CHECK("##### Getting AccessibleTable - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(accTable); + EXCEPTION_CHECK("##### Getting AccessibleTable - call to NewGlobalRef()", FALSE); + tableInfo->accessibleTable = (JOBJECT64)globalRef; + PrintDebugString(" ##### accessibleTable = %p", globalRef); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableFromContextMethod == 0"); + return FALSE; + } + + // cache the AccessibleContext + if (getContextFromAccessibleTableMethod != (jmethodID) 0) { + PrintDebugString("##### Calling getContextFromAccessibleTable Method ..."); + jobject ac = jniEnv->CallObjectMethod(accessBridgeObject, + getContextFromAccessibleTableMethod, + accessibleContext); + PrintDebugString("##### ... Returned from getContextFromAccessibleTable Method"); + EXCEPTION_CHECK("##### Getting AccessibleTable - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(ac); + EXCEPTION_CHECK("##### Getting AccessibleTable - call to NewGlobalRef()", FALSE); + tableInfo->accessibleContext = (JOBJECT64)globalRef; + PrintDebugString(" ##### accessibleContext = %p", globalRef); + } else { + PrintDebugString(" ##### Error! either env == 0 or getContextFromAccessibleTable Method == 0"); + return FALSE; + } + + // FIX - set unused elements + tableInfo->caption = NULL; + tableInfo->summary = NULL; + + PrintDebugString("##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableInfo succeeded"); + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTableCellInfo(jobject accessibleTable, jint row, jint column, + AccessibleTableCellInfo *tableCellInfo) { + + jthrowable exception; + + PrintDebugString("\r\n##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableCellInfo(%p): row=%d, column=%d", + accessibleTable, row, column); + + // FIX + ZeroMemory(tableCellInfo, sizeof(AccessibleTableCellInfo)); + tableCellInfo->row = row; + tableCellInfo->column = column; + // FIX END + + // get the table cell index + if (getAccessibleTableCellIndexMethod != (jmethodID) 0) { + tableCellInfo->index = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableCellIndexMethod, + accessibleTable, row, column); + EXCEPTION_CHECK("##### Getting AccessibleTableCellIndex - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table cell index = %d", tableCellInfo->index); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableCellIndexMethod == 0"); + return FALSE; + } + + // get the table cell row extent + if (getAccessibleTableCellRowExtentMethod != (jmethodID) 0) { + tableCellInfo->rowExtent = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableCellRowExtentMethod, + accessibleTable, row, column); + EXCEPTION_CHECK("##### Getting AccessibleTableCellRowExtentCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table cell row extent = %d", tableCellInfo->rowExtent); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableCellRowExtentMethod == 0"); + return FALSE; + } + + // get the table cell column extent + if (getAccessibleTableCellColumnExtentMethod != (jmethodID) 0) { + tableCellInfo->columnExtent = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableCellColumnExtentMethod, + accessibleTable, row, column); + EXCEPTION_CHECK("##### Getting AccessibleTableCellColumnExtentCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table cell column extent = %d", tableCellInfo->columnExtent); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableCellColumnExtentMethod == 0"); + return FALSE; + } + + // get whether the table cell is selected + if (isAccessibleTableCellSelectedMethod != (jmethodID) 0) { + tableCellInfo->isSelected = jniEnv->CallBooleanMethod(accessBridgeObject, + isAccessibleTableCellSelectedMethod, + accessibleTable, row, column); + EXCEPTION_CHECK("##### Getting isAccessibleTableCellSelected - call to CallBooleanMethod()", FALSE); + PrintDebugString(" ##### table cell isSelected = %d", tableCellInfo->isSelected); + } else { + PrintDebugString(" ##### Error! either env == 0 or isAccessibleTableCellSelectedMethod == 0"); + return FALSE; + } + + // get the table cell AccessibleContext + if (getAccessibleTableCellAccessibleContextMethod != (jmethodID) 0) { + jobject tableCellAC = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTableCellAccessibleContextMethod, + accessibleTable, row, column); + EXCEPTION_CHECK("##### Getting AccessibleTableCellAccessibleContext - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(tableCellAC); + EXCEPTION_CHECK("##### Getting AccessibleTableCellAccessibleContext - call to NewGlobalRef()", FALSE); + tableCellInfo->accessibleContext = (JOBJECT64)globalRef; + PrintDebugString(" ##### table cell AccessibleContext = %p", globalRef); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableCellAccessibleContextMethod == 0"); + return FALSE; + } + + PrintDebugString(" ##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableCellInfo succeeded"); + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTableRowHeader(jobject acParent, AccessibleTableInfo *tableInfo) { + + jthrowable exception; + + PrintDebugString("\r\n##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableRowHeader(%p):", + acParent); + + // get the header row count + if (getAccessibleTableRowHeaderRowCountMethod != (jmethodID) 0) { + tableInfo->rowCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableRowHeaderRowCountMethod, + acParent); + EXCEPTION_CHECK("##### Getting AccessibleTableRowHeaderRowCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table row count = %d", tableInfo->rowCount); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleRowHeaderRowCountMethod == 0"); + return FALSE; + } + + // get the header column count + if (getAccessibleTableRowHeaderColumnCountMethod != (jmethodID) 0) { + tableInfo->columnCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableRowHeaderColumnCountMethod, + acParent); + EXCEPTION_CHECK("Getting AccessibleTableRowHeaderColumnCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table column count = %d", tableInfo->columnCount); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableRowHeaderColumnCountMethod == 0"); + return FALSE; + } + + // get the header AccessibleTable + if (getAccessibleTableRowHeaderMethod != (jmethodID) 0) { + jobject accTable = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTableRowHeaderMethod, + acParent); + EXCEPTION_CHECK("##### Getting AccessibleTableRowHeader - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(accTable); + EXCEPTION_CHECK("##### Getting AccessibleTableRowHeader - call to NewGlobalRef()", FALSE); + tableInfo->accessibleTable = (JOBJECT64)globalRef; + PrintDebugString(" ##### row header AccessibleTable = %p", globalRef); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableRowHeaderMethod == 0"); + return FALSE; + } + + // FIX - set unused elements + tableInfo->caption = NULL; + tableInfo->summary = NULL; + tableInfo->accessibleContext = NULL; + + PrintDebugString(" ##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableRowHeader succeeded"); + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTableColumnHeader(jobject acParent, AccessibleTableInfo *tableInfo) { + jthrowable exception; + + PrintDebugString("\r\n##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableColumnHeader(%p):", + acParent); + + // get the header row count + if (getAccessibleTableColumnHeaderRowCountMethod != (jmethodID) 0) { + tableInfo->rowCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableColumnHeaderRowCountMethod, + acParent); + EXCEPTION_CHECK("##### Getting AccessibleTableColumnHeaderRowCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table row count = %d", tableInfo->rowCount); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleColumnHeaderRowCountMethod == 0"); + return FALSE; + } + + // get the header column count + if (getAccessibleTableColumnHeaderColumnCountMethod != (jmethodID) 0) { + tableInfo->columnCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableColumnHeaderColumnCountMethod, + acParent); + EXCEPTION_CHECK("Getting AccessibleTableColumnHeaderColumnCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table column count = %d", tableInfo->columnCount); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableColumnHeaderColumnCountMethod == 0"); + return FALSE; + } + // get the header AccessibleTable + if (getAccessibleTableColumnHeaderMethod != (jmethodID) 0) { + jobject accTable = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTableColumnHeaderMethod, + acParent); + EXCEPTION_CHECK("##### Getting AccessibleTableColumnHeader - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(accTable); + EXCEPTION_CHECK("##### Getting AccessibleTableColumnHeader - call to NewGlobalRef()", FALSE); + tableInfo->accessibleTable = (JOBJECT64)globalRef; + PrintDebugString(" ##### column header AccessibleTable = %p", globalRef); + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableColumnHeaderMethod == 0"); + return FALSE; + } + + // FIX - set unused elements + tableInfo->caption = NULL; + tableInfo->summary = NULL; + tableInfo->accessibleContext = NULL; + + PrintDebugString(" ##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableColumnHeader succeeded"); + return TRUE; +} + +jobject +AccessBridgeJavaEntryPoints::getAccessibleTableRowDescription(jobject acParent, jint row) { + + jobject returnedAccessibleContext; + jobject globalRef; + jthrowable exception; + + PrintDebugString("\r\n##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableRowDescription(%p):", + acParent); + + if (getAccessibleTableRowDescriptionMethod != (jmethodID) 0) { + returnedAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTableRowDescriptionMethod, + acParent, row); + EXCEPTION_CHECK("Getting AccessibleTableRowDescription - call to CallObjectMethod()", FALSE); + globalRef = jniEnv->NewGlobalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleTableRowDescription - call to NewGlobalRef()", FALSE); + jniEnv->DeleteLocalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleTableRowDescription - call to DeleteLocalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + returnedAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTableRowDescriptionMethod == 0"); + return (jobject) 0; + } +} + +jobject +AccessBridgeJavaEntryPoints::getAccessibleTableColumnDescription(jobject acParent, jint column) { + + jobject returnedAccessibleContext; + jobject globalRef; + jthrowable exception; + + PrintDebugString("\r\n##### Calling AccessBridgeJavaEntryPoints::getAccessibleTableColumnDescription(%p):", + acParent); + + if (getAccessibleTableColumnDescriptionMethod != (jmethodID) 0) { + returnedAccessibleContext = jniEnv->CallObjectMethod( + accessBridgeObject, + getAccessibleTableColumnDescriptionMethod, + acParent, column); + EXCEPTION_CHECK("Getting AccessibleTableColumnDescription - call to CallObjectMethod()", FALSE); + globalRef = jniEnv->NewGlobalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleTableColumnDescription - call to NewGlobalRef()", FALSE); + jniEnv->DeleteLocalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleTableColumnDescription - call to DeleteLocalRef()", FALSE); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + returnedAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTableColumnDescriptionMethod == 0"); + return (jobject) 0; + } +} + +jint +AccessBridgeJavaEntryPoints::getAccessibleTableRowSelectionCount(jobject accessibleTable) { + + jthrowable exception; + jint count; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleTableRowSelectionCount(%p)", + accessibleTable); + + // Get the table row selection count + if (getAccessibleTableRowSelectionCountMethod != (jmethodID) 0) { + count = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableRowSelectionCountMethod, + accessibleTable); + EXCEPTION_CHECK("##### Getting AccessibleTableRowSelectionCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table row selection count = %d", count); + return count; + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableRowSelectionCountMethod == 0"); + return 0; + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleTableRowSelectionCount failed"); + return 0; +} + +BOOL +AccessBridgeJavaEntryPoints::isAccessibleTableRowSelected(jobject accessibleTable, jint row) { + jthrowable exception; + BOOL result; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::isAccessibleTableRowSelected(%p, %d)", + accessibleTable, row); + + if (isAccessibleTableRowSelectedMethod != (jmethodID) 0) { + result = jniEnv->CallBooleanMethod(accessBridgeObject, + isAccessibleTableRowSelectedMethod, + accessibleTable, row); + EXCEPTION_CHECK("##### Getting isAccessibleTableRowSelected - call to CallBooleanMethod()", FALSE); + PrintDebugString(" ##### table row isSelected = %d", result); + return result; + } else { + PrintDebugString(" ##### Error! either env == 0 or isAccessibleTableRowSelectedMethod == 0"); + return FALSE; + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::isAccessibleTableRowSelected failed"); + return FALSE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTableRowSelections(jobject accessibleTable, jint count, + jint *selections) { + + jthrowable exception; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleTableRowSelections(%p, %d %p)", + accessibleTable, count, selections); + + if (getAccessibleTableRowSelectionsMethod == (jmethodID) 0) { + return FALSE; + } + // Get the table row selections + for (int i = 0; i < count; i++) { + + selections[i] = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableRowSelectionsMethod, + accessibleTable, + i); + EXCEPTION_CHECK("##### Getting AccessibleTableRowSelections - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table row selection[%d] = %d", i, selections[i]); + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleTableRowSelections succeeded"); + return TRUE; +} + + +jint +AccessBridgeJavaEntryPoints::getAccessibleTableColumnSelectionCount(jobject accessibleTable) { + + jthrowable exception; + jint count; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleTableColumnSelectionCount(%p)", + accessibleTable); + + // Get the table column selection count + if (getAccessibleTableColumnSelectionCountMethod != (jmethodID) 0) { + count = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableColumnSelectionCountMethod, + accessibleTable); + EXCEPTION_CHECK("##### Getting AccessibleTableColumnSelectionCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table column selection count = %d", count); + return count; + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleRowCountMethod == 0"); + return 0; + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleTableColumnSelectionCount failed"); + return 0; +} + +BOOL +AccessBridgeJavaEntryPoints::isAccessibleTableColumnSelected(jobject accessibleTable, jint column) { + jthrowable exception; + BOOL result; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::isAccessibleTableColumnSelected(%p, %d)", + accessibleTable, column); + + if (isAccessibleTableColumnSelectedMethod != (jmethodID) 0) { + result = jniEnv->CallBooleanMethod(accessBridgeObject, + isAccessibleTableColumnSelectedMethod, + accessibleTable, column); + EXCEPTION_CHECK("##### Getting isAccessibleTableColumnSelected - call to CallBooleanMethod()", FALSE); + PrintDebugString(" ##### table column isSelected = %d", result); + return result; + } else { + PrintDebugString(" ##### Error! either env == 0 or isAccessibleTableColumnSelectedMethod == 0"); + return FALSE; + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::isAccessibleTableColumnSelected failed"); + return FALSE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTableColumnSelections(jobject accessibleTable, jint count, + jint *selections) { + jthrowable exception; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleTableColumnSelections(%p, %d, %p)", + accessibleTable, count, selections); + + if (getAccessibleTableColumnSelectionsMethod == (jmethodID) 0) { + return FALSE; + } + // Get the table column selections + for (int i = 0; i < count; i++) { + + selections[i] = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableColumnSelectionsMethod, + accessibleTable, + i); + EXCEPTION_CHECK("##### Getting AccessibleTableColumnSelections - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table Column selection[%d] = %d", i, selections[i]); + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleTableColumnSelections succeeded"); + return TRUE; +} + + +jint +AccessBridgeJavaEntryPoints::getAccessibleTableRow(jobject accessibleTable, jint index) { + jthrowable exception; + jint result; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleTableRow(%p, index=%d)", + accessibleTable, index); + + if (getAccessibleTableRowMethod != (jmethodID) 0) { + result = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableRowMethod, + accessibleTable, index); + EXCEPTION_CHECK("##### Getting AccessibleTableRow - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table row = %d", result); + return result; + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableRowMethod == 0"); + return -1; + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleTableRow failed"); + return -1; +} + +jint +AccessBridgeJavaEntryPoints::getAccessibleTableColumn(jobject accessibleTable, jint index) { + jthrowable exception; + jint result; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleTableColumn(%p, index=%d)", + accessibleTable, index); + + if (getAccessibleTableColumnMethod != (jmethodID) 0) { + result = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableColumnMethod, + accessibleTable, index); + EXCEPTION_CHECK("##### Getting AccessibleTableColumn - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table column = %d", result); + return result; + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableColumnMethod == 0"); + return -1; + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleTableColumn failed"); + return -1; +} + +jint +AccessBridgeJavaEntryPoints::getAccessibleTableIndex(jobject accessibleTable, jint row, jint column) { + jthrowable exception; + jint result; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleTableIndex(%p, row=%d, col=%d)", + accessibleTable, row, column); + + if (getAccessibleTableIndexMethod != (jmethodID) 0) { + result = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTableIndexMethod, + accessibleTable, row, column); + EXCEPTION_CHECK("##### Getting getAccessibleTableIndex - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### table index = %d", result); + return result; + } else { + PrintDebugString(" ##### Error! either env == 0 or getAccessibleTableIndexMethod == 0"); + return -1; + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleTableIndex failed"); + return -1; +} + +/********** end AccessibleTable routines ******************************/ + + +/********** begin AccessibleRelationSet routines **********************/ + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleRelationSet(jobject accessibleContext, + AccessibleRelationSetInfo *relationSet) { + + jthrowable exception; + const wchar_t *stringBytes; + jsize length; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleRelationSet(%p, %p)", + accessibleContext, relationSet); + + if (getAccessibleRelationCountMethod == (jmethodID) 0 || + getAccessibleRelationKeyMethod == (jmethodID) 0 || + getAccessibleRelationTargetCountMethod == (jmethodID) 0 || + getAccessibleRelationTargetMethod == (jmethodID) 0) { + return FALSE; + } + + // Get the relations set count + relationSet->relationCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleRelationCountMethod, + accessibleContext); + EXCEPTION_CHECK("##### Getting AccessibleRelationCount - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### AccessibleRelation count = %d", relationSet->relationCount); + + + // Get the relation set + for (int i = 0; i < relationSet->relationCount && i < MAX_RELATIONS; i++) { + + jstring js = (jstring)jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleRelationKeyMethod, + accessibleContext, + i); + + EXCEPTION_CHECK("Getting AccessibleRelationKey - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleRelation key - call to GetStringChars()", FALSE); + wcsncpy(relationSet->relations[i].key, stringBytes, (sizeof(relationSet->relations[i].key ) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + relationSet->relations[i].key [length < (sizeof(relationSet->relations[i].key ) / sizeof(wchar_t)) ? + length : (sizeof(relationSet->relations[i].key ) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleRelation key - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleRelation key - call to ReleaseStringChars()", FALSE); + // jniEnv->CallVoidMethod(accessBridgeObject, + // decrementReferenceMethod, js); + //EXCEPTION_CHECK("Getting AccessibleRelation key - call to CallVoidMethod()", FALSE); + PrintDebugString("##### AccessibleRelation key = %ls", relationSet->relations[i].key ); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleRelation key - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" AccessibleRelation key is null."); + relationSet->relations[i].key [0] = (wchar_t) 0; + } + + relationSet->relations[i].targetCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleRelationTargetCountMethod, + accessibleContext, + i); + + for (int j = 0; j < relationSet->relations[i].targetCount && j < MAX_RELATION_TARGETS; j++) { + jobject target = jniEnv->CallObjectMethod(accessBridgeObject, getAccessibleRelationTargetMethod, + accessibleContext, i, j); + EXCEPTION_CHECK("Getting AccessibleRelationSet - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(target); + EXCEPTION_CHECK("Getting AccessibleRelationSet - call to NewGlobalRef()", FALSE); + relationSet->relations[i].targets[j] = (JOBJECT64)globalRef; + PrintDebugString(" relation set item: %p", globalRef); + } + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleRelationSet succeeded"); + return TRUE; +} + + +/********** end AccessibleRelationSet routines ************************/ + + +/********** begin AccessibleHypertext routines **********************/ + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleHypertext(jobject accessibleContext, + AccessibleHypertextInfo *hypertext) { + + jthrowable exception; + const wchar_t *stringBytes; + jsize length; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleHypertext(%p, %p)", + accessibleContext, hypertext); + + // get the AccessibleHypertext + jobject ht = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleHypertextMethod, + accessibleContext); + EXCEPTION_CHECK("##### Getting AccessibleHypertext - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(ht); + EXCEPTION_CHECK("##### Getting AccessibleHypertext - call to NewGlobalRef()", FALSE); + hypertext->accessibleHypertext = (JOBJECT64)globalRef; + PrintDebugString(" ##### AccessibleHypertext = %p", globalRef); + + if (hypertext->accessibleHypertext == 0) { + PrintDebugString(" ##### null AccessibleHypertext; returning FALSE"); + return false; + } + + // get the hyperlink count + hypertext->linkCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleHyperlinkCountMethod,accessibleContext); + + EXCEPTION_CHECK("##### Getting hyperlink count - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### hyperlink count = %d", hypertext->linkCount); + + + // get the hypertext links + for (int i = 0; i < hypertext->linkCount && i < MAX_HYPERLINKS; i++) { + + // get the hyperlink + jobject hl = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleHyperlinkMethod, + accessibleContext, + i); + EXCEPTION_CHECK("##### Getting AccessibleHyperlink - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(hl); + EXCEPTION_CHECK("##### Getting AccessibleHyperlink - call to NewGlobalRef()", FALSE); + hypertext->links[i].accessibleHyperlink = (JOBJECT64)globalRef; + PrintDebugString(" ##### AccessibleHyperlink = %p", globalRef); + + // get the hyperlink text + jstring js = (jstring)jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleHyperlinkTextMethod, + hypertext->links[i].accessibleHyperlink, + i); + + EXCEPTION_CHECK("Getting hyperlink text - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to GetStringChars()", FALSE); + wcsncpy(hypertext->links[i].text, stringBytes, (sizeof(hypertext->links[i].text) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + if (length >= (sizeof(hypertext->links[i].text) / sizeof(wchar_t))) { + length = (sizeof(hypertext->links[i].text) / sizeof(wchar_t)) - 2; + } + hypertext->links[i].text[length] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to ReleaseStringChars()", FALSE); + // jniEnv->CallVoidMethod(accessBridgeObject, + // decrementReferenceMethod, js); + //EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to CallVoidMethod()", FALSE); + PrintDebugString("##### AccessibleHyperlink text = %ls", hypertext->links[i].text ); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" AccessibleHyperlink text is null."); + hypertext->links[i].text[0] = (wchar_t) 0; + } + + hypertext->links[i].startIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleHyperlinkStartIndexMethod, + hypertext->links[i].accessibleHyperlink, + i); + EXCEPTION_CHECK("##### Getting hyperlink start index - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### hyperlink start index = %d", hypertext->links[i].startIndex); + + + hypertext->links[i].endIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleHyperlinkEndIndexMethod, + hypertext->links[i].accessibleHyperlink, + i); + EXCEPTION_CHECK("##### Getting hyperlink end index - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### hyperlink end index = %d", hypertext->links[i].endIndex); + + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleHypertext succeeded"); + return TRUE; +} + +/* + * Activates an AccessibleHyperlink + */ +BOOL +AccessBridgeJavaEntryPoints::activateAccessibleHyperlink(jobject accessibleContext, + jobject accessibleHyperlink) { + + jthrowable exception; + BOOL returnVal; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::activateAccessibleHyperlink(%p, %p):", + accessibleContext, accessibleHyperlink); + + if (activateAccessibleHyperlinkMethod != (jmethodID) 0) { + returnVal = (BOOL) jniEnv->CallBooleanMethod(accessBridgeObject, activateAccessibleHyperlinkMethod, + accessibleContext, accessibleHyperlink); + EXCEPTION_CHECK("activateAccessibleHyperlink - call to CallBooleanMethod()", FALSE); + return returnVal; + } else { + PrintDebugString("\r\n Error! either jniEnv == 0 or activateAccessibleHyperlinkMethod == 0"); + return FALSE; + } +} + + +/* + * This method is used to iterate through the hyperlinks in a component. It + * returns hypertext information for a component starting at hyperlink index + * nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will + * be returned for each call to this method. + * returns FALSE on error. + */ +BOOL +AccessBridgeJavaEntryPoints::getAccessibleHypertextExt(const jobject accessibleContext, + const jint nStartIndex, + /* OUT */ AccessibleHypertextInfo *hypertext) { + + jthrowable exception; + const wchar_t *stringBytes; + jsize length; + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleHypertextExt(%p, %p, startIndex = %d)", + accessibleContext, hypertext, nStartIndex); + + // get the AccessibleHypertext + jobject ht = jniEnv->CallObjectMethod(accessBridgeObject, getAccessibleHypertextMethod, + accessibleContext); + EXCEPTION_CHECK("##### Getting AccessibleHypertext - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(ht); + EXCEPTION_CHECK("##### Getting AccessibleHypertext - call to NewGlobalRef()", FALSE); + hypertext->accessibleHypertext = (JOBJECT64)globalRef; + PrintDebugString(" ##### AccessibleHypertext = %p", globalRef); + if (hypertext->accessibleHypertext == 0) { + PrintDebugString(" ##### null AccessibleHypertext; returning FALSE"); + return FALSE; + } + + // get the hyperlink count + hypertext->linkCount = jniEnv->CallIntMethod(accessBridgeObject, getAccessibleHyperlinkCountMethod, + accessibleContext); + EXCEPTION_CHECK("##### Getting hyperlink count - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### hyperlink count = %d", hypertext->linkCount); + + if (nStartIndex >= hypertext->linkCount) { + return FALSE; + } + + // get the hypertext links + // NOTE: To avoid a crash when there are more than MAX_HYPERLINKS (64) links + // in the document, test for i < MAX_HYPERLINKS in addition to + // i < hypertext->linkCount + int bufIndex = 0; + for (int i = nStartIndex; (i < hypertext->linkCount) && (i < nStartIndex + MAX_HYPERLINKS); i++) { + PrintDebugString(" getting hyperlink %d ...", i); + + // get the hyperlink + jobject hl = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleHyperlinkMethod, + hypertext->accessibleHypertext, + i); + EXCEPTION_CHECK("##### Getting AccessibleHyperlink - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(hl); + EXCEPTION_CHECK("##### Getting AccessibleHyperlink - call to NewGlobalRef()", FALSE); + hypertext->links[bufIndex].accessibleHyperlink = (JOBJECT64)globalRef; + PrintDebugString(" ##### AccessibleHyperlink = %p", globalRef); + + // get the hyperlink text + jstring js = (jstring)jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleHyperlinkTextMethod, + hypertext->links[bufIndex].accessibleHyperlink, + i); + + EXCEPTION_CHECK("Getting hyperlink text - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to GetStringChars()", FALSE); + wcsncpy(hypertext->links[bufIndex].text, stringBytes, + (sizeof(hypertext->links[bufIndex].text) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + if (length >= (sizeof(hypertext->links[bufIndex].text) / sizeof(wchar_t))) { + length = (sizeof(hypertext->links[bufIndex].text) / sizeof(wchar_t)) - 2; + } + hypertext->links[bufIndex].text[length] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to ReleaseStringChars()", FALSE); + // jniEnv->CallVoidMethod(accessBridgeObject, + // decrementReferenceMethod, js); + //EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to CallVoidMethod()", FALSE); + PrintDebugString("##### AccessibleHyperlink text = %ls", hypertext->links[bufIndex].text ); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to DeleteLocalRef()", FALSE); + + } else { + PrintDebugString(" AccessibleHyperlink text is null."); + hypertext->links[bufIndex].text[0] = (wchar_t) 0; + } + + hypertext->links[bufIndex].startIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleHyperlinkStartIndexMethod, + hypertext->links[bufIndex].accessibleHyperlink, + i); + EXCEPTION_CHECK("##### Getting hyperlink start index - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### hyperlink start index = %d", hypertext->links[bufIndex].startIndex); + + hypertext->links[bufIndex].endIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleHyperlinkEndIndexMethod, + hypertext->links[bufIndex].accessibleHyperlink, + i); + EXCEPTION_CHECK("##### Getting hyperlink end index - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### hyperlink end index = %d", hypertext->links[bufIndex].endIndex); + + bufIndex++; + } + + PrintDebugString(" ##### AccessBridgeJavaEntryPoints::getAccessibleHypertextExt succeeded"); + return TRUE; +} + +jint AccessBridgeJavaEntryPoints::getAccessibleHyperlinkCount(const jobject accessibleContext) { + + jthrowable exception; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleHyperlinkCount(%X)", + accessibleContext); + + if (getAccessibleHyperlinkCountMethod == (jmethodID)0) { + return -1; + } + + // get the hyperlink count + jint linkCount = jniEnv->CallIntMethod(accessBridgeObject, getAccessibleHyperlinkCountMethod, + accessibleContext); + EXCEPTION_CHECK("##### Getting hyperlink count - call to CallIntMethod()", -1); + PrintDebugString(" ##### hyperlink count = %d", linkCount); + + return linkCount; +} + + +jint AccessBridgeJavaEntryPoints::getAccessibleHypertextLinkIndex(const jobject hypertext, + const jint nIndex) { + + jthrowable exception; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleHypertextLinkIndex(%p, index = %d)", + hypertext, nIndex); + + if (getAccessibleHypertextLinkIndexMethod == (jmethodID)0) { + return -1; + } + + // get the hyperlink index + jint index = jniEnv->CallIntMethod(accessBridgeObject, getAccessibleHypertextLinkIndexMethod, + hypertext, nIndex); + + EXCEPTION_CHECK("##### Getting hyperlink index - call to CallIntMethod()", -1); + PrintDebugString(" ##### hyperlink index = %d", index); + + return index; +} + +BOOL AccessBridgeJavaEntryPoints::getAccessibleHyperlink(jobject hypertext, + const jint index, + /* OUT */ AccessibleHyperlinkInfo *info) { + + jthrowable exception; + const wchar_t *stringBytes; + jsize length; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleHyperlink(%p, index = %d)", + hypertext, index); + + + // get the hyperlink + jobject hl = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleHyperlinkMethod, + hypertext, + index); + EXCEPTION_CHECK("##### Getting AccessibleHyperlink - call to CallObjectMethod()", FALSE); + jobject globalRef = jniEnv->NewGlobalRef(hl); + EXCEPTION_CHECK("##### Getting AccessibleHyperlink - call to NewGlobalRef()", FALSE); + info->accessibleHyperlink = (JOBJECT64)globalRef; + PrintDebugString(" ##### AccessibleHyperlink = %p", globalRef); + + // get the hyperlink text + jstring js = (jstring)jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleHyperlinkTextMethod, + info->accessibleHyperlink, + index); + + EXCEPTION_CHECK("Getting hyperlink text - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to GetStringChars()", FALSE); + wcsncpy(info->text, stringBytes, + (sizeof(info->text) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + if (length >= (sizeof(info->text) / sizeof(wchar_t))) { + length = (sizeof(info->text) / sizeof(wchar_t)) - 2; + } + info->text[length] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to ReleaseStringChars()", FALSE); + // jniEnv->CallVoidMethod(accessBridgeObject, + // decrementReferenceMethod, js); + //EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to CallVoidMethod()", FALSE); + PrintDebugString("##### AccessibleHyperlink text = %ls", info->text ); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleHyperlink text - call to DeleteLocalRef()", FALSE); + + } else { + PrintDebugString(" AccessibleHyperlink text is null."); + info->text[0] = (wchar_t) 0; + } + + info->startIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleHyperlinkStartIndexMethod, + info->accessibleHyperlink, + index); + EXCEPTION_CHECK("##### Getting hyperlink start index - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### hyperlink start index = %d", info->startIndex); + + info->endIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleHyperlinkEndIndexMethod, + info->accessibleHyperlink, + index); + EXCEPTION_CHECK("##### Getting hyperlink end index - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### hyperlink end index = %d", info->endIndex); + + return TRUE; +} + + +/********** end AccessibleHypertext routines ************************/ + +// Accessible Keybinding methods +BOOL AccessBridgeJavaEntryPoints::getAccessibleKeyBindings(jobject accessibleContext, + AccessibleKeyBindings *keyBindings) { + + jthrowable exception; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleKeyBindings(%p, %p)", + accessibleContext, keyBindings); + + if (getAccessibleKeyBindingsCountMethod == (jmethodID) 0 || + getAccessibleKeyBindingCharMethod == (jmethodID) 0 || + getAccessibleKeyBindingModifiersMethod == (jmethodID) 0) { + return FALSE; + } + + // get the key binding count + keyBindings->keyBindingsCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleKeyBindingsCountMethod, accessibleContext); + + EXCEPTION_CHECK("##### Getting key bindings count - call to CallIntMethod()", FALSE); + + PrintDebugString(" ##### key bindings count = %d", keyBindings->keyBindingsCount); + + // get the key bindings + for (int i = 0; i < keyBindings->keyBindingsCount && i < MAX_KEY_BINDINGS; i++) { + + // get the key binding character + keyBindings->keyBindingInfo[i].character = jniEnv->CallCharMethod(accessBridgeObject, + getAccessibleKeyBindingCharMethod, + accessibleContext, + i); + EXCEPTION_CHECK("##### Getting key binding character - call to CallCharMethod()", FALSE); + PrintDebugString(" ##### key binding character = %c", keyBindings->keyBindingInfo[i].character); + PrintDebugString(" ##### key binding character in hex = %hx", keyBindings->keyBindingInfo[i].character); + + // get the key binding modifiers + keyBindings->keyBindingInfo[i].modifiers = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleKeyBindingModifiersMethod, + accessibleContext, + i); + EXCEPTION_CHECK("##### Getting key binding modifiers - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### key binding modifiers = %x", keyBindings->keyBindingInfo[i].modifiers); + } + return FALSE; +} + +// AccessibleIcon methods +BOOL AccessBridgeJavaEntryPoints::getAccessibleIcons(jobject accessibleContext, + AccessibleIcons *icons) { + + jthrowable exception; + const wchar_t *stringBytes; + jsize length; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleIcons(%p, %p)", + accessibleContext, icons); + + if (getAccessibleIconsCountMethod == (jmethodID) 0 || + getAccessibleIconDescriptionMethod == (jmethodID) 0 || + getAccessibleIconHeightMethod == (jmethodID) 0 || + getAccessibleIconWidthMethod == (jmethodID) 0) { + PrintDebugString(" ##### missing method(s) !!!"); + return FALSE; + } + + + // get the icons count + icons->iconsCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleIconsCountMethod, accessibleContext); + + EXCEPTION_CHECK("##### Getting icons count - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### icons count = %d", icons->iconsCount); + + + // get the icons + for (int i = 0; i < icons->iconsCount && i < MAX_ICON_INFO; i++) { + + // get the icon description + jstring js = (jstring)jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleIconDescriptionMethod, + accessibleContext, + i); + + EXCEPTION_CHECK("Getting icon description - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleIcon description - call to GetStringChars()", FALSE); + wcsncpy(icons->iconInfo[i].description, stringBytes, (sizeof(icons->iconInfo[i].description) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + if (length >= (sizeof(icons->iconInfo[i].description) / sizeof(wchar_t))) { + length = (sizeof(icons->iconInfo[i].description) / sizeof(wchar_t)) - 2; + } + icons->iconInfo[i].description[length] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleIcon description - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleIcon description - call to ReleaseStringChars()", FALSE); + // jniEnv->CallVoidMethod(accessBridgeObject, + // decrementReferenceMethod, js); + //EXCEPTION_CHECK("Getting AccessibleIcon description - call to CallVoidMethod()", FALSE); + PrintDebugString("##### AccessibleIcon description = %ls", icons->iconInfo[i].description ); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleIcon description - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" AccessibleIcon description is null."); + icons->iconInfo[i].description[0] = (wchar_t) 0; + } + + + // get the icon height + icons->iconInfo[i].height = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleIconHeightMethod, + accessibleContext, + i); + EXCEPTION_CHECK("##### Getting icon height - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### icon height = %d", icons->iconInfo[i].height); + + // get the icon width + icons->iconInfo[i].width = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleIconWidthMethod, + accessibleContext, + i); + EXCEPTION_CHECK("##### Getting icon width - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### icon width = %d", icons->iconInfo[i].width); + } + return FALSE; +} + +// AccessibleActionMethods +BOOL AccessBridgeJavaEntryPoints::getAccessibleActions(jobject accessibleContext, + AccessibleActions *actions) { + + jthrowable exception; + const wchar_t *stringBytes; + jsize length; + + PrintDebugString("\r\n##### AccessBridgeJavaEntryPoints::getAccessibleIcons(%p, %p)", + accessibleContext, actions); + + if (getAccessibleActionsCountMethod == (jmethodID) 0 || + getAccessibleActionNameMethod == (jmethodID) 0) { + PrintDebugString(" ##### missing method(s) !!!"); + return FALSE; + } + + + // get the icons count + actions->actionsCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleActionsCountMethod,accessibleContext); + + EXCEPTION_CHECK("##### Getting actions count - call to CallIntMethod()", FALSE); + PrintDebugString(" ##### key actions count = %d", actions->actionsCount); + + + // get the actions + for (int i = 0; i < actions->actionsCount && i < MAX_ACTION_INFO; i++) { + + // get the action name + jstring js = (jstring)jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleActionNameMethod, + accessibleContext, + i); + + EXCEPTION_CHECK("Getting Action Name - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleAction Name - call to GetStringChars()", FALSE); + wcsncpy(actions->actionInfo[i].name , stringBytes, (sizeof(actions->actionInfo[i].name ) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + if (length >= (sizeof(actions->actionInfo[i].name ) / sizeof(wchar_t))) { + length = (sizeof(actions->actionInfo[i].name ) / sizeof(wchar_t)) - 2; + } + actions->actionInfo[i].name [length] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleAction name - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleAction name - call to ReleaseStringChars()", FALSE); + // jniEnv->CallVoidMethod(accessBridgeObject, + // decrementReferenceMethod, js); + //EXCEPTION_CHECK("Getting AccessibleAction name - call to CallVoidMethod()", FALSE); + PrintDebugString("##### AccessibleAction name = %ls", actions->actionInfo[i].name ); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleAction name - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" AccessibleAction name is null."); + actions->actionInfo[i].name [0] = (wchar_t) 0; + } + } + return FALSE; +} + +BOOL AccessBridgeJavaEntryPoints::doAccessibleActions(jobject accessibleContext, + AccessibleActionsToDo *actionsToDo, + jint *failure) { + + jthrowable exception; + BOOL returnVal; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::doAccessibleActions(%p, #actions %d %s):", + accessibleContext, + actionsToDo->actionsCount, + actionsToDo->actions[0].name); + + if (doAccessibleActionsMethod == (jmethodID) 0) { + *failure = 0; + return FALSE; + } + + PrintDebugString("\r\n doing %d actions ...", actionsToDo->actionsCount); + for (int i = 0; i < actionsToDo->actionsCount && i < MAX_ACTIONS_TO_DO; i++) { + PrintDebugString("\r doing action %d: %s ...", i, actionsToDo->actions[i].name); + + // create a Java String for the action name + wchar_t *actionName = (wchar_t *)actionsToDo->actions[i].name; + jstring javaName = jniEnv->NewString(actionName, (jsize)wcslen(actionName)); + if (javaName == 0) { + PrintDebugString("\r NewString failed"); + *failure = i; + return FALSE; + } + + returnVal = (BOOL)jniEnv->CallBooleanMethod(accessBridgeObject, doAccessibleActionsMethod, + accessibleContext, javaName); + jniEnv->DeleteLocalRef(javaName); + EXCEPTION_CHECK("doAccessibleActions - call to CallBooleanMethod()", FALSE); + + if (returnVal != TRUE) { + PrintDebugString("\r Action %d failed", i); + *failure = i; + return FALSE; + } + } + *failure = -1; + return TRUE; +} + + +/********** AccessibleText routines ***********************************/ + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTextInfo(jobject accessibleContext, + AccessibleTextInfo *textInfo, + jint x, jint y) { + jthrowable exception; + + // Verify the Java VM still exists and AccessibleContext is + // an instance of AccessibleText + if (verifyAccessibleText(accessibleContext) == FALSE) { + return FALSE; + } + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleTextInfo(%p, %d, %d):", + accessibleContext, x, y); + + // Get the character count + if (getAccessibleCharCountFromContextMethod != (jmethodID) 0) { + textInfo->charCount = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleCharCountFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleCharCount - call to CallIntMethod()", FALSE); + PrintDebugString(" Char count = %d", textInfo->charCount); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleCharCountFromContextMethod == 0"); + return FALSE; + } + + // Get the index of the caret + if (getAccessibleCaretPositionFromContextMethod != (jmethodID) 0) { + textInfo->caretIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleCaretPositionFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleCaretPosition - call to CallIntMethod()", FALSE); + PrintDebugString(" Index at caret = %d", textInfo->caretIndex); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleCaretPositionFromContextMethod == 0"); + return FALSE; + } + + // Get the index at the given point + if (getAccessibleIndexAtPointFromContextMethod != (jmethodID) 0) { + textInfo->indexAtPoint = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleIndexAtPointFromContextMethod, + accessibleContext, x, y); + EXCEPTION_CHECK("Getting AccessibleIndexAtPoint - call to CallIntMethod()", FALSE); + PrintDebugString(" Index at point = %d", textInfo->indexAtPoint); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleIndexAtPointFromContextMethod == 0"); + return FALSE; + } + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTextItems(jobject accessibleContext, + AccessibleTextItemsInfo *textItems, jint index) { + jstring js; + const wchar_t *stringBytes; + jthrowable exception; + jsize length; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleTextItems(%p):", accessibleContext); + + // Verify the Java VM still exists and AccessibleContext is + // an instance of AccessibleText + if (verifyAccessibleText(accessibleContext) == FALSE) { + return FALSE; + } + + // Get the letter at index + if (getAccessibleLetterAtIndexFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleLetterAtIndexFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleLetterAtIndex - call to CallIntMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleLetterAtIndex - call to GetStringChars()", FALSE); + textItems->letter = stringBytes[0]; + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleLetterAtIndex - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleLetterAtIndex - call to CallVoidMethod()", FALSE); + PrintDebugString(" Accessible Text letter = %c", textItems->letter); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleLetterAtIndex - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible Text letter is null."); + textItems->letter = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleLetterAtIndexFromContextMethod == 0"); + return FALSE; + } + + + // Get the word at index + if (getAccessibleWordAtIndexFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleWordAtIndexFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleWordAtIndex - call to CallIntMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleWordAtIndex - call to GetStringChars()", FALSE); + wcsncpy(textItems->word, stringBytes, (sizeof(textItems->word) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + textItems->word[length < (sizeof(textItems->word) / sizeof(wchar_t)) ? + length : (sizeof(textItems->word) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleWordAtIndex - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleWordAtIndex - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleWordAtIndex - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Text word = %ls", textItems->word); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleWordAtIndex - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible Text word is null."); + textItems->word[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleWordAtIndexFromContextMethod == 0"); + return FALSE; + } + + // Get the sentence at index + if (getAccessibleSentenceAtIndexFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleSentenceAtIndexFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleSentenceAtIndex - call to CallObjectMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleSentenceAtIndex - call to GetStringChars()", FALSE); + wcsncpy(textItems->sentence, stringBytes, (sizeof(textItems->sentence) / sizeof(wchar_t))-2); + length = jniEnv->GetStringLength(js); + + if (length < sizeof(textItems->sentence) / sizeof(wchar_t)) { + textItems->sentence[length] = (wchar_t) 0; + } else { + textItems->sentence[(sizeof(textItems->sentence) / sizeof(wchar_t))-2] = (wchar_t) 0; + } + EXCEPTION_CHECK("Getting AccessibleSentenceAtIndex - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleSentenceAtIndex - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleSentenceAtIndex - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Text sentence = %ls", textItems->sentence); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleSentenceAtIndex - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible Text sentence is null."); + textItems->sentence[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleSentenceAtIndexFromContextMethod == 0"); + return FALSE; + } + + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTextSelectionInfo(jobject accessibleContext, + AccessibleTextSelectionInfo *selectionInfo) { + jstring js; + const wchar_t *stringBytes; + jthrowable exception; + jsize length; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleTextSelectionInfo(%p):", + accessibleContext); + + // Verify the Java VM still exists and AccessibleContext is + // an instance of AccessibleText + if (verifyAccessibleText(accessibleContext) == FALSE) { + return FALSE; + } + + // Get the selection start index + if (getAccessibleTextSelectionStartFromContextMethod != (jmethodID) 0) { + selectionInfo->selectionStartIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTextSelectionStartFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleTextSelectionStart - call to CallIntMethod()", FALSE); + PrintDebugString(" Selection start = %d", selectionInfo->selectionStartIndex); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTextSelectionStartFromContextMethod == 0"); + return FALSE; + } + + // Get the selection end index + if (getAccessibleTextSelectionEndFromContextMethod != (jmethodID) 0) { + selectionInfo->selectionEndIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTextSelectionEndFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleTextSelectionEnd - call to CallIntMethod()", FALSE); + PrintDebugString(" Selection end = %d", selectionInfo->selectionEndIndex); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTextSelectionEndFromContextMethod == 0"); + return FALSE; + } + + // Get the selected text + if (getAccessibleTextSelectedTextFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTextSelectedTextFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleTextSelectedText - call to CallObjectMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleTextSelectedText - call to GetStringChars()", FALSE); + wcsncpy(selectionInfo->selectedText, stringBytes, (sizeof(selectionInfo->selectedText) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + selectionInfo->selectedText[length < (sizeof(selectionInfo->selectedText) / sizeof(wchar_t)) ? + length : (sizeof(selectionInfo->selectedText) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleTextSelectedText - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleTextSelectedText - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleTextSelectedText - call to CallVoidMethod()", FALSE); + PrintDebugString(" Accessible's selected text = %s", selectionInfo->selectedText); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleTextSelectedText - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible's selected text is null."); + selectionInfo->selectedText[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTextSelectedTextFromContextMethod == 0"); + return FALSE; + } + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTextAttributes(jobject accessibleContext, jint index, AccessibleTextAttributesInfo *attributes) { + jstring js; + const wchar_t *stringBytes; + jobject AttributeSet; + jthrowable exception; + jsize length; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleTextAttributes(%p):", accessibleContext); + + // Verify the Java VM still exists and AccessibleContext is + // an instance of AccessibleText + if (verifyAccessibleText(accessibleContext) == FALSE) { + return FALSE; + } + + if (accessibleContext == (jobject) 0) { + PrintDebugString(" passed in AccessibleContext == null! (oops)"); + + attributes->bold = FALSE; + attributes->italic = FALSE; + attributes->underline = FALSE; + attributes->strikethrough = FALSE; + attributes->superscript = FALSE; + attributes->subscript = FALSE; + attributes->backgroundColor[0] = (wchar_t) 0; + attributes->foregroundColor[0] = (wchar_t) 0; + attributes->fontFamily[0] = (wchar_t) 0; + attributes->fontSize = -1; + attributes->alignment = -1; + attributes->bidiLevel = -1; + attributes->firstLineIndent = -1; + attributes->leftIndent = -1; + attributes->rightIndent = -1; + attributes->lineSpacing = -1; + attributes->spaceAbove = -1; + attributes->spaceBelow = -1; + attributes->fullAttributesString[0] = (wchar_t) 0; + + return (FALSE); + } + + // Get the AttributeSet + if (getAccessibleAttributeSetAtIndexFromContextMethod != (jmethodID) 0) { + PrintDebugString(" Getting AttributeSet at index..."); + AttributeSet = jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleAttributeSetAtIndexFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleAttributeSetAtIndex - call to CallObjectMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleAttributeSetAtIndexFromContextMethod == 0"); + return FALSE; + } + + // It is legal for the AttributeSet object to be null, in which case we return false! + if (AttributeSet == (jobject) 0) { + PrintDebugString(" AttributeSet returned at index is null (this is legal! - see AWT in J2SE 1.3"); + + attributes->bold = FALSE; + attributes->italic = FALSE; + attributes->underline = FALSE; + attributes->strikethrough = FALSE; + attributes->superscript = FALSE; + attributes->subscript = FALSE; + attributes->backgroundColor[0] = (wchar_t) 0; + attributes->foregroundColor[0] = (wchar_t) 0; + attributes->fontFamily[0] = (wchar_t) 0; + attributes->fontSize = -1; + attributes->alignment = -1; + attributes->bidiLevel = -1; + attributes->firstLineIndent = -1; + attributes->leftIndent = -1; + attributes->rightIndent = -1; + attributes->lineSpacing = -1; + attributes->spaceAbove = -1; + attributes->spaceBelow = -1; + attributes->fullAttributesString[0] = (wchar_t) 0; + + return (FALSE); + } + + // Get the bold setting + if (getBoldFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting bold from AttributeSet..."); + attributes->bold = (BOOL) jniEnv->CallBooleanMethod(accessBridgeObject, + getBoldFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting BoldFromAttributeSet - call to CallBooleanMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getBoldFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting BoldFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting BoldFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the italic setting + if (getItalicFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting italic from AttributeSet..."); + attributes->italic = (BOOL) jniEnv->CallBooleanMethod(accessBridgeObject, + getItalicFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting ItalicFromAttributeSet - call to CallBooleanMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getItalicdFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting ItalicFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting ItalicFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the underline setting + if (getUnderlineFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting underline from AttributeSet..."); + attributes->underline = (BOOL) jniEnv->CallBooleanMethod(accessBridgeObject, + getUnderlineFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting UnderlineFromAttributeSet - call to CallBooleanMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getUnderlineFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting UnderlineFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting UnderlineFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the strikethrough setting + if (getStrikethroughFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting strikethrough from AttributeSet..."); + attributes->strikethrough = (BOOL) jniEnv->CallBooleanMethod(accessBridgeObject, + getStrikethroughFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting StrikethroughFromAttributeSet - call to CallBooleanMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getStrikethroughFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting StrikethroughFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting StrikethroughFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the superscript setting + if (getSuperscriptFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting superscript from AttributeSet..."); + attributes->superscript = (BOOL) jniEnv->CallBooleanMethod(accessBridgeObject, + getSuperscriptFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting SuperscriptFromAttributeSet - call to CallBooleanMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getSuperscripteFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting SuperscriptFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting SuperscriptFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the subscript setting + if (getSubscriptFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting subscript from AttributeSet..."); + attributes->subscript = (BOOL) jniEnv->CallBooleanMethod(accessBridgeObject, + getSubscriptFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting SubscriptFromAttributeSet - call to CallBooleanMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getSubscriptFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting SubscriptFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting SubscriptFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the backgroundColor setting + if (getBackgroundColorFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting backgroundColor from AttributeSet..."); + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getBackgroundColorFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to GetStringChars()", FALSE); + wcsncpy(attributes->backgroundColor, stringBytes, (sizeof(attributes->backgroundColor) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + attributes->backgroundColor[length < (sizeof(attributes->backgroundColor) / sizeof(wchar_t)) ? + length : (sizeof(attributes->backgroundColor) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" AttributeSet's background color = %ls", attributes->backgroundColor); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" AttributeSet's background color is null."); + attributes->backgroundColor[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getBackgroundColorFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting BackgroundColorFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the foregroundColor setting + if (getForegroundColorFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting foregroundColor from AttributeSet..."); + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getForegroundColorFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to GetStringChars()", FALSE); + wcsncpy(attributes->foregroundColor, stringBytes, (sizeof(attributes->foregroundColor) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + attributes->foregroundColor[length < (sizeof(attributes->foregroundColor) / sizeof(wchar_t)) ? + length : (sizeof(attributes->foregroundColor) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" AttributeSet's foreground color = %ls", attributes->foregroundColor); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" AttributeSet's foreground color is null."); + attributes->foregroundColor[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getForegroundColorFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting ForegroundColorFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the fontFamily setting + if (getFontFamilyFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting fontFamily from AttributeSet..."); + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getFontFamilyFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to CallObjectMethod()", FALSE); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to GetStringChars()", FALSE); + wcsncpy(attributes->fontFamily, stringBytes, (sizeof(attributes->fontFamily) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + attributes->fontFamily[length < (sizeof(attributes->fontFamily) / sizeof(wchar_t)) ? + length : (sizeof(attributes->fontFamily) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" AttributeSet's fontFamily = %ls", attributes->fontFamily); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" AttributeSet's fontFamily is null."); + attributes->backgroundColor[0] = (wchar_t) 0; + } + } else { + PrintDebugString(" Error! either env == 0 or getFontFamilyFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting FontFamilyFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the font size + if (getFontSizeFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting font size from AttributeSet..."); + attributes->fontSize = jniEnv->CallIntMethod(accessBridgeObject, + getFontSizeFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting FontSizeFromAttributeSet - call to CallIntMethod()", FALSE); + PrintDebugString(" AttributeSet's font size = %d", attributes->fontSize); + } else { + PrintDebugString(" Error! either env == 0 or getAlignmentFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting FontSizeFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting FontSizeFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + + // Get the alignment setting + if (getAlignmentFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting alignment from AttributeSet..."); + attributes->alignment = jniEnv->CallIntMethod(accessBridgeObject, + getAlignmentFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting AlignmentFromAttributeSet - call to CallIntMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getAlignmentFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting AlignmentFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting AlignmentFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the bidiLevel setting + if (getBidiLevelFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting bidiLevel from AttributeSet..."); + attributes->bidiLevel = jniEnv->CallIntMethod(accessBridgeObject, + getBidiLevelFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting BidiLevelFromAttributeSet - call to CallIntMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getBidiLevelFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting BidiLevelFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting BidiLevelFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the firstLineIndent setting + if (getFirstLineIndentFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting firstLineIndent from AttributeSet..."); + attributes->firstLineIndent = (jfloat) jniEnv->CallFloatMethod(accessBridgeObject, + getFirstLineIndentFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting FirstLineIndentFromAttributeSet - call to CallIntMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getFirstLineIndentFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting FirstLineIndentFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting FirstLineIndentFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the leftIndent setting + if (getLeftIndentFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting leftIndent from AttributeSet..."); + attributes->leftIndent = (jfloat) jniEnv->CallFloatMethod(accessBridgeObject, + getLeftIndentFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting LeftIndentFromAttributeSet - call to CallIntMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getLeftIndentFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting LeftIndentFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting LeftIndentFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the rightIndent setting + if (getRightIndentFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting rightIndent from AttributeSet..."); + attributes->rightIndent = (jfloat) jniEnv->CallFloatMethod(accessBridgeObject, + getRightIndentFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting RightIndentFromAttributeSet - call to CallIntMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getRightIndentFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting RightIndentFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting RightIndentFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the lineSpacing setting + if (getLineSpacingFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting lineSpacing from AttributeSet..."); + attributes->lineSpacing = (jfloat) jniEnv->CallFloatMethod(accessBridgeObject, + getLineSpacingFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting LineSpacingFromAttributeSet - call to CallIntMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getLineSpacingFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting LineSpacingFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting LineSpacingFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the spaceAbove setting + if (getSpaceAboveFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting spaceAbove from AttributeSet..."); + attributes->spaceAbove = (jfloat) jniEnv->CallFloatMethod(accessBridgeObject, + getSpaceAboveFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting SpaceAboveFromAttributeSet - call to CallIntMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getSpaceAboveFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting SpaceAboveFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting SpaceAboveFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the spaceBelow setting + if (getSpaceBelowFromAttributeSetMethod != (jmethodID) 0) { + PrintDebugString(" Getting spaceBelow from AttributeSet..."); + attributes->spaceBelow = (jfloat) jniEnv->CallFloatMethod(accessBridgeObject, + getSpaceBelowFromAttributeSetMethod, + AttributeSet); + EXCEPTION_CHECK("Getting SpaceBelowFromAttributeSet - call to CallIntMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or getSpaceBelowFromAttributeSetMethod == 0"); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Getting SpaceBelowFromAttributeSet - call to CallVoidMethod()", FALSE); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting SpaceBelowFromAttributeSet - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Release the AttributeSet object + if (decrementReferenceMethod != (jmethodID) 0) { + PrintDebugString(" Decrementing reference to AttributeSet..."); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, AttributeSet); + EXCEPTION_CHECK("Releasing AttributeSet object - call to CallVoidMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or accessBridgeObject == 0"); + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Releasing AttributeSet object - call to DeleteLocalRef()", FALSE); + return FALSE; + } + + // Get the full attributes string at index + if (getAccessibleAttributesAtIndexFromContextMethod != (jmethodID) 0) { + PrintDebugString(" Getting full attributes string from Context..."); + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleAttributesAtIndexFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to CallObjectMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to GetStringChars()", FALSE); + wcsncpy(attributes->fullAttributesString, stringBytes, (sizeof(attributes->fullAttributesString) / sizeof(wchar_t))); + length = jniEnv->GetStringLength(js); + attributes->fullAttributesString[length < (sizeof(attributes->fullAttributesString) / sizeof(wchar_t)) ? + length : (sizeof(attributes->fullAttributesString) / sizeof(wchar_t))-2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Text attributes = %ls", attributes->fullAttributesString); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" Accessible Text attributes is null."); + attributes->fullAttributesString[0] = (wchar_t) 0; + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting AccessibleAttributesAtIndex - call to DeleteLocalRef()", FALSE); + return FALSE; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleAttributesAtIndexFromContextMethod == 0"); + jniEnv->DeleteLocalRef(AttributeSet); + return FALSE; + } + + jniEnv->DeleteLocalRef(AttributeSet); + EXCEPTION_CHECK("Getting AccessibleAttributeSetAtIndex - call to DeleteLocalRef()", FALSE); + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTextRect(jobject accessibleContext, AccessibleTextRectInfo *rectInfo, jint index) { + + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleTextRect(%p), index = %d", + accessibleContext, index); + + // Verify the Java VM still exists and AccessibleContext is + // an instance of AccessibleText + if (verifyAccessibleText(accessibleContext) == FALSE) { + return FALSE; + } + + // Get the x coord + if (getAccessibleXcoordTextRectAtIndexFromContextMethod != (jmethodID) 0) { + rectInfo->x = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleXcoordTextRectAtIndexFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleXcoordTextRect - call to CallIntMethod()", FALSE); + PrintDebugString(" X coord = %d", rectInfo->x); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleXcoordTextRectAtIndexFromContextMethod == 0"); + return FALSE; + } + + // Get the y coord + if (getAccessibleYcoordTextRectAtIndexFromContextMethod != (jmethodID) 0) { + rectInfo->y = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleYcoordTextRectAtIndexFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleYcoordTextRect - call to CallIntMethod()", FALSE); + PrintDebugString(" Y coord = %d", rectInfo->y); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleYcoordTextRectAtIndexFromContextMethod == 0"); + return FALSE; + } + + // Get the width + if (getAccessibleWidthTextRectAtIndexFromContextMethod != (jmethodID) 0) { + rectInfo->width = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleWidthTextRectAtIndexFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleWidthTextRect - call to CallIntMethod()", FALSE); + PrintDebugString(" Width = %d", rectInfo->width); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleWidthTextRectAtIndexFromContextMethod == 0"); + return FALSE; + } + + // Get the height + if (getAccessibleHeightTextRectAtIndexFromContextMethod != (jmethodID) 0) { + rectInfo->height = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleHeightTextRectAtIndexFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleHeightTextRect - call to CallIntMethod()", FALSE); + PrintDebugString(" Height = %d", rectInfo->height); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleHeightTextRectAtIndexFromContextMethod == 0"); + return FALSE; + } + + return TRUE; +} + +// ===== + +/** + * gets the bounding rectangle for the text caret + */ +BOOL +AccessBridgeJavaEntryPoints::getCaretLocation(jobject accessibleContext, AccessibleTextRectInfo *rectInfo, jint index) { + + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getCaretLocation(%p), index = %d", + accessibleContext, index); + + // Verify the Java VM still exists and AccessibleContext is + // an instance of AccessibleText + if (verifyAccessibleText(accessibleContext) == FALSE) { + return FALSE; + } + + // Get the x coord + if (getCaretLocationXMethod != (jmethodID) 0) { + rectInfo->x = jniEnv->CallIntMethod(accessBridgeObject, + getCaretLocationXMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting caret X coordinate - call to CallIntMethod()", FALSE); + PrintDebugString(" X coord = %d", rectInfo->x); + } else { + PrintDebugString(" Error! either env == 0 or getCaretLocationXMethod == 0"); + return FALSE; + } + + // Get the y coord + if (getCaretLocationYMethod != (jmethodID) 0) { + rectInfo->y = jniEnv->CallIntMethod(accessBridgeObject, + getCaretLocationYMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting caret Y coordinate - call to CallIntMethod()", FALSE); + PrintDebugString(" Y coord = %d", rectInfo->y); + } else { + PrintDebugString(" Error! either env == 0 or getCaretLocationYMethod == 0"); + return FALSE; + } + + // Get the width + if (getCaretLocationWidthMethod != (jmethodID) 0) { + rectInfo->width = jniEnv->CallIntMethod(accessBridgeObject, + getCaretLocationWidthMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting caret width - call to CallIntMethod()", FALSE); + PrintDebugString(" Width = %d", rectInfo->width); + } else { + PrintDebugString(" Error! either env == 0 or getCaretLocationWidthMethod == 0"); + return FALSE; + } + + // Get the height + if (getCaretLocationHeightMethod != (jmethodID) 0) { + rectInfo->height = jniEnv->CallIntMethod(accessBridgeObject, + getCaretLocationHeightMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting caret height - call to CallIntMethod()", FALSE); + PrintDebugString(" Height = %d", rectInfo->height); + } else { + PrintDebugString(" Error! either env == 0 or getCaretLocationHeightMethod == 0"); + return FALSE; + } + + return TRUE; +} + +// ===== + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTextLineBounds(jobject accessibleContext, jint index, jint *startIndex, jint *endIndex) { + + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleTextLineBounds(%p):", accessibleContext); + + // Verify the Java VM still exists and AccessibleContext is + // an instance of AccessibleText + if (verifyAccessibleText(accessibleContext) == FALSE) { + return FALSE; + } + + // Get the index of the left boundary of the line containing 'index' + if (getAccessibleTextLineLeftBoundsFromContextMethod != (jmethodID) 0) { + *startIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTextLineLeftBoundsFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleTextLineLeftBounds - call to CallIntMethod()", FALSE); + PrintDebugString(" startIndex = %d", *startIndex); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTextLineLeftBoundsFromContextMethod == 0"); + return FALSE; + } + + // Get the index of the right boundary of the line containing 'index' + if (getAccessibleTextLineRightBoundsFromContextMethod != (jmethodID) 0) { + *endIndex = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleTextLineRightBoundsFromContextMethod, + accessibleContext, index); + EXCEPTION_CHECK("Getting AccessibleTextLineRightBounds - call to CallIntMethod()", FALSE); + PrintDebugString(" endIndex = %d", *endIndex); + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTextLineRightBoundsFromContextMethod == 0"); + return FALSE; + } + + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getAccessibleTextRange(jobject accessibleContext, + jint start, jint end, wchar_t *text, short len) { + jstring js; + const wchar_t *stringBytes; + jthrowable exception; + jsize length; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleTextRange(%p, %d, %d, *text, %d):", accessibleContext, start, end, len); + + // Verify the Java VM still exists and AccessibleContext is + // an instance of AccessibleText + if (verifyAccessibleText(accessibleContext) == FALSE) { + return FALSE; + } + + // range is inclusive + if (end < start) { + PrintDebugString(" Error! end < start!"); + text[0] = (wchar_t) 0; + return FALSE; + } + + // Get the text range within [start, end] inclusive + if (getAccessibleTextRangeFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getAccessibleTextRangeFromContextMethod, + accessibleContext, start, end); + EXCEPTION_CHECK("Getting AccessibleTextRange - call to CallObjectMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting AccessibleTextRange - call to GetStringChars()", FALSE); + wPrintDebugString(L" Accessible Text stringBytes returned from Java = %ls", stringBytes); + wcsncpy(text, stringBytes, len); + length = jniEnv->GetStringLength(js); + PrintDebugString(" Accessible Text stringBytes length = %d", length); + text[length < len ? length : len - 2] = (wchar_t) 0; + wPrintDebugString(L" Accessible Text 'text' after null termination = %ls", text); + EXCEPTION_CHECK("Getting AccessibleTextRange - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting AccessibleTextRange - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting AccessibleTextRange - call to CallVoidMethod()", FALSE); + wPrintDebugString(L" Accessible Text range = %ls", text); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting AccessibleTextRange - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" current Accessible Text range is null."); + text[0] = (wchar_t) 0; + return FALSE; + } + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleTextRangeFromContextMethod == 0"); + return FALSE; + } + return TRUE; +} + +/********** AccessibleValue routines ***************/ + +BOOL +AccessBridgeJavaEntryPoints::getCurrentAccessibleValueFromContext(jobject accessibleContext, wchar_t *value, short len) { + jstring js; + const wchar_t *stringBytes; + jthrowable exception; + jsize length; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getCurrentAccessibleValueFromContext(%p):", accessibleContext); + + // Get the current Accessible Value + if (getCurrentAccessibleValueFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getCurrentAccessibleValueFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting CurrentAccessibleValue - call to CallObjectMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting CurrentAccessibleValue - call to GetStringChars()", FALSE); + wcsncpy(value, stringBytes, len); + length = jniEnv->GetStringLength(js); + value[length < len ? length : len - 2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting CurrentAccessibleValue - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting CurrentAccessibleValue - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting CurrentAccessibleValue - call to CallVoidMethod()", FALSE); + PrintDebugString(" current Accessible Value = %s", value); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting CurrentAccessibleValue - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" current Accessible Value is null."); + value[0] = (wchar_t) 0; + return FALSE; + } + } else { + PrintDebugString(" Error! either env == 0 or getCurrentAccessibleValueFromContextMethod == 0"); + return FALSE; + } + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getMaximumAccessibleValueFromContext(jobject accessibleContext, wchar_t *value, short len) { + jstring js; + const wchar_t *stringBytes; + jthrowable exception; + jsize length; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getMaximumAccessibleValueFromContext(%p):", accessibleContext); + + // Get the maximum Accessible Value + if (getMaximumAccessibleValueFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getMaximumAccessibleValueFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting MaximumAccessibleValue - call to CallObjectMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting MaximumAccessibleValue - call to GetStringChars()", FALSE); + wcsncpy(value, stringBytes, len); + length = jniEnv->GetStringLength(js); + value[length < len ? length : len - 2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting MaximumAccessibleValue - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting MaximumAccessibleValue - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting MaximumAccessibleValue - call to CallVoidMethod()", FALSE); + PrintDebugString(" maximum Accessible Value = %s", value); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting MaximumAccessibleValue - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" maximum Accessible Value is null."); + value[0] = (wchar_t) 0; + return FALSE; + } + } else { + PrintDebugString(" Error! either env == 0 or getMaximumAccessibleValueFromContextMethod == 0"); + return FALSE; + } + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::getMinimumAccessibleValueFromContext(jobject accessibleContext, wchar_t *value, short len) { + jstring js; + const wchar_t *stringBytes; + jthrowable exception; + jsize length; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getMinimumAccessibleValueFromContext(%p):", accessibleContext); + + // Get the mimimum Accessible Value + if (getMinimumAccessibleValueFromContextMethod != (jmethodID) 0) { + js = (jstring) jniEnv->CallObjectMethod(accessBridgeObject, + getMinimumAccessibleValueFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting MinimumAccessibleValue - call to CallObjectMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod(), js = %p", js); + if (js != (jstring) 0) { + stringBytes = (const wchar_t *) jniEnv->GetStringChars(js, 0); + EXCEPTION_CHECK("Getting MinimumAccessibleValue - call to GetStringChars()", FALSE); + wcsncpy(value, stringBytes, len); + length = jniEnv->GetStringLength(js); + value[length < len ? length : len - 2] = (wchar_t) 0; + EXCEPTION_CHECK("Getting MinimumAccessibleValue - call to GetStringLength()", FALSE); + jniEnv->ReleaseStringChars(js, stringBytes); + EXCEPTION_CHECK("Getting MinimumAccessibleValue - call to ReleaseStringChars()", FALSE); + jniEnv->CallVoidMethod(accessBridgeObject, + decrementReferenceMethod, js); + EXCEPTION_CHECK("Getting MinimumAccessibleValue - call to CallVoidMethod()", FALSE); + PrintDebugString(" mimimum Accessible Value = %s", value); + jniEnv->DeleteLocalRef(js); + EXCEPTION_CHECK("Getting MinimumAccessibleValue - call to DeleteLocalRef()", FALSE); + } else { + PrintDebugString(" mimimum Accessible Value is null."); + value[0] = (wchar_t) 0; + return FALSE; + } + } else { + PrintDebugString(" Error! either env == 0 or getMinimumAccessibleValueFromContextMethod == 0"); + return FALSE; + } + return TRUE; +} + + +/********** AccessibleSelection routines ***************/ + +void +AccessBridgeJavaEntryPoints::addAccessibleSelectionFromContext(jobject accessibleContext, int i) { + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::addAccessibleSelectionFromContext(%p):", accessibleContext); + + // Add the child to the AccessibleSelection + if (addAccessibleSelectionFromContextMethod != (jmethodID) 0) { + jniEnv->CallVoidMethod(accessBridgeObject, + addAccessibleSelectionFromContextMethod, + accessibleContext, i); + EXCEPTION_CHECK_VOID("Doing addAccessibleSelection - call to CallVoidMethod()"); + PrintDebugString(" returned from CallObjectMethod()"); + } else { + PrintDebugString(" Error! either env == 0 or addAccessibleSelectionFromContextMethod == 0"); + } +} + +void +AccessBridgeJavaEntryPoints::clearAccessibleSelectionFromContext(jobject accessibleContext) { + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::clearAccessibleSelectionFromContext(%p):", accessibleContext); + + // Clearing the Selection of the AccessibleSelection + if (clearAccessibleSelectionFromContextMethod != (jmethodID) 0) { + jniEnv->CallVoidMethod(accessBridgeObject, + clearAccessibleSelectionFromContextMethod, + accessibleContext); + EXCEPTION_CHECK_VOID("Doing clearAccessibleSelection - call to CallVoidMethod()"); + PrintDebugString(" returned from CallObjectMethod()"); + } else { + PrintDebugString(" Error! either env == 0 or clearAccessibleSelectionFromContextMethod == 0"); + } +} + +jobject +AccessBridgeJavaEntryPoints::getAccessibleSelectionFromContext(jobject accessibleContext, int i) { + jobject returnedAccessibleContext; + jobject globalRef; + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleSelectionFromContext(%p):", accessibleContext); + + if (getAccessibleSelectionContextFromContextMethod != (jmethodID) 0) { + returnedAccessibleContext = jniEnv->CallObjectMethod( + accessBridgeObject, + getAccessibleSelectionContextFromContextMethod, + accessibleContext, i); + EXCEPTION_CHECK("Getting AccessibleSelectionContext - call to CallObjectMethod()", (jobject) 0); + globalRef = jniEnv->NewGlobalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleSelectionContext - call to NewGlobalRef()", (jobject) 0); + jniEnv->DeleteLocalRef(returnedAccessibleContext); + EXCEPTION_CHECK("Getting AccessibleSelectionContext - call to DeleteLocalRef()", (jobject) 0); + PrintDebugString(" Returning - returnedAccessibleContext = %p; globalRef = %p", + returnedAccessibleContext, globalRef); + return globalRef; + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleSelectionContextFromContextMethod == 0"); + return (jobject) 0; + } +} + +int +AccessBridgeJavaEntryPoints::getAccessibleSelectionCountFromContext(jobject accessibleContext) { + int count; + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::getAccessibleSelectionCountFromContext(%p):", accessibleContext); + + // Get (& return) the # of items selected in the AccessibleSelection + if (getAccessibleSelectionCountFromContextMethod != (jmethodID) 0) { + count = jniEnv->CallIntMethod(accessBridgeObject, + getAccessibleSelectionCountFromContextMethod, + accessibleContext); + EXCEPTION_CHECK("Getting AccessibleSelectionCount - call to CallIntMethod()", -1); + PrintDebugString(" returned from CallObjectMethod()"); + return count; + } else { + PrintDebugString(" Error! either env == 0 or getAccessibleSelectionCountFromContextMethod == 0"); + return -1; + } +} + +BOOL +AccessBridgeJavaEntryPoints::isAccessibleChildSelectedFromContext(jobject accessibleContext, int i) { + jboolean result; + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::isAccessibleChildSelectedFromContext(%p):", accessibleContext); + + // Get (& return) the # of items selected in the AccessibleSelection + if (isAccessibleChildSelectedFromContextMethod != (jmethodID) 0) { + result = jniEnv->CallBooleanMethod(accessBridgeObject, + isAccessibleChildSelectedFromContextMethod, + accessibleContext, i); + EXCEPTION_CHECK("Doing isAccessibleChildSelected - call to CallBooleanMethod()", FALSE); + PrintDebugString(" returned from CallObjectMethod()"); + if (result != 0) { + return TRUE; + } + } else { + PrintDebugString(" Error! either env == 0 or isAccessibleChildSelectedFromContextMethod == 0"); + } + return FALSE; +} + + +void +AccessBridgeJavaEntryPoints::removeAccessibleSelectionFromContext(jobject accessibleContext, int i) { + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::removeAccessibleSelectionFromContext(%p):", accessibleContext); + + // Remove the i-th child from the AccessibleSelection + if (removeAccessibleSelectionFromContextMethod != (jmethodID) 0) { + jniEnv->CallVoidMethod(accessBridgeObject, + removeAccessibleSelectionFromContextMethod, + accessibleContext, i); + EXCEPTION_CHECK_VOID("Doing removeAccessibleSelection - call to CallVoidMethod()"); + PrintDebugString(" returned from CallObjectMethod()"); + } else { + PrintDebugString(" Error! either env == 0 or removeAccessibleSelectionFromContextMethod == 0"); + } +} + +void +AccessBridgeJavaEntryPoints::selectAllAccessibleSelectionFromContext(jobject accessibleContext) { + jthrowable exception; + + PrintDebugString("\r\nCalling AccessBridgeJavaEntryPoints::selectAllAccessibleSelectionFromContext(%p):", accessibleContext); + + // Select all children (if possible) of the AccessibleSelection + if (selectAllAccessibleSelectionFromContextMethod != (jmethodID) 0) { + jniEnv->CallVoidMethod(accessBridgeObject, + selectAllAccessibleSelectionFromContextMethod, + accessibleContext); + EXCEPTION_CHECK_VOID("Doing selectAllAccessibleSelection - call to CallVoidMethod()"); + PrintDebugString(" returned from CallObjectMethod()"); + } else { + PrintDebugString(" Error! either env == 0 or selectAllAccessibleSelectionFromContextMethod == 0"); + } +} + + +/********** Event Notification Registration routines ***************/ + +BOOL +AccessBridgeJavaEntryPoints::addJavaEventNotification(jlong type) { + jthrowable exception; + + PrintDebugString("\r\n in AccessBridgeJavaEntryPoints::addJavaEventNotification(%016I64X);", type); + + // Let AccessBridge know we want to add an event type + if (addJavaEventNotificationMethod != (jmethodID) 0) { + jniEnv->CallVoidMethod(accessBridgeObject, + addJavaEventNotificationMethod, type); + EXCEPTION_CHECK("Doing addJavaEventNotification - call to CallVoidMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or addJavaEventNotificationMethod == 0"); + return FALSE; + } + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::removeJavaEventNotification(jlong type) { + jthrowable exception; + + PrintDebugString("\r\n in AccessBridgeJavaEntryPoints::removeJavaEventNotification(%016I64X):", type); + + // Let AccessBridge know we want to remove an event type + if (removeJavaEventNotificationMethod != (jmethodID) 0) { + jniEnv->CallVoidMethod(accessBridgeObject, + removeJavaEventNotificationMethod, type); + EXCEPTION_CHECK("Doing removeJavaEventNotification - call to CallVoidMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or removeJavaEventNotificationMethod == 0"); + return FALSE; + } + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::addAccessibilityEventNotification(jlong type) { + jthrowable exception; + + PrintDebugString("\r\n in AccessBridgeJavaEntryPoints::addAccessibilityEventNotification(%016I64X);", type); + + // Let AccessBridge know we want to add an event type + if (addAccessibilityEventNotificationMethod != (jmethodID) 0) { + PrintDebugString("\r\n addAccessibilityEventNotification: calling void method: accessBridgeObject = %p", accessBridgeObject); + jniEnv->CallVoidMethod(accessBridgeObject, + addAccessibilityEventNotificationMethod, type); + EXCEPTION_CHECK("Doing addAccessibilityEvent - call to CallVoidMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or addAccessibilityEventNotificationMethod == 0"); + return FALSE; + } + PrintDebugString("\r\n addAccessibilityEventNotification: just returning true"); + return TRUE; +} + +BOOL +AccessBridgeJavaEntryPoints::removeAccessibilityEventNotification(jlong type) { + jthrowable exception; + + PrintDebugString("\r\n in AccessBridgeJavaEntryPoints::removeAccessibilityEventNotification(%016I64X):", type); + + // Let AccessBridge know we want to remove an event type + if (removeAccessibilityEventNotificationMethod != (jmethodID) 0) { + jniEnv->CallVoidMethod(accessBridgeObject, + removeAccessibilityEventNotificationMethod, type); + EXCEPTION_CHECK("Doing removeAccessibilityEvent - call to CallVoidMethod()", FALSE); + } else { + PrintDebugString(" Error! either env == 0 or removeAccessibilityEventNotificationMethod == 0"); + return FALSE; + } + return TRUE; +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,418 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to manage JNI calls into AccessBridge.java + */ + +#include "AccessBridgePackages.h" + +#include +#include + +#ifndef __AccessBridgeJavaEntryPoints_H__ +#define __AccessBridgeJavaEntryPoints_H__ + +class AccessBridgeJavaEntryPoints { + JNIEnv *jniEnv; + + jobject accessBridgeObject; + + jclass bridgeClass; + jclass eventHandlerClass; + + jmethodID decrementReferenceMethod; + jmethodID getJavaVersionPropertyMethod; + + jmethodID isJavaWindowMethod; + jmethodID isSameObjectMethod; + jmethodID getAccessibleContextFromHWNDMethod; + jmethodID getHWNDFromAccessibleContextMethod; + + jmethodID getAccessibleContextAtMethod; + jmethodID getAccessibleContextWithFocusMethod; + + jmethodID getAccessibleNameFromContextMethod; + jmethodID getAccessibleDescriptionFromContextMethod; + jmethodID getAccessibleRoleStringFromContextMethod; + jmethodID getAccessibleRoleStringFromContext_en_USMethod; + jmethodID getAccessibleStatesStringFromContextMethod; + jmethodID getAccessibleStatesStringFromContext_en_USMethod; + jmethodID getAccessibleParentFromContextMethod; + jmethodID getAccessibleIndexInParentFromContextMethod; + jmethodID getAccessibleChildrenCountFromContextMethod; + jmethodID getAccessibleChildFromContextMethod; + jmethodID getAccessibleBoundsOnScreenFromContextMethod; + jmethodID getAccessibleXcoordFromContextMethod; + jmethodID getAccessibleYcoordFromContextMethod; + jmethodID getAccessibleHeightFromContextMethod; + jmethodID getAccessibleWidthFromContextMethod; + + jmethodID getAccessibleComponentFromContextMethod; + jmethodID getAccessibleActionFromContextMethod; + jmethodID getAccessibleSelectionFromContextMethod; + jmethodID getAccessibleTextFromContextMethod; + jmethodID getAccessibleValueFromContextMethod; + + /* begin AccessibleTable */ + jmethodID getAccessibleTableFromContextMethod; + jmethodID getAccessibleTableRowHeaderMethod; + jmethodID getAccessibleTableColumnHeaderMethod; + jmethodID getAccessibleTableRowCountMethod; + jmethodID getAccessibleTableColumnCountMethod; + jmethodID getAccessibleTableCaptionMethod; + jmethodID getAccessibleTableSummaryMethod; + + jmethodID getContextFromAccessibleTableMethod; + jmethodID getAccessibleTableCellAccessibleContextMethod; + jmethodID getAccessibleTableCellIndexMethod; + jmethodID getAccessibleTableCellRowExtentMethod; + jmethodID getAccessibleTableCellColumnExtentMethod; + jmethodID isAccessibleTableCellSelectedMethod; + + jmethodID getAccessibleTableRowHeaderRowCountMethod; + jmethodID getAccessibleTableColumnHeaderRowCountMethod; + + jmethodID getAccessibleTableRowHeaderColumnCountMethod; + jmethodID getAccessibleTableColumnHeaderColumnCountMethod; + + jmethodID getAccessibleTableRowDescriptionMethod; + jmethodID getAccessibleTableColumnDescriptionMethod; + + jmethodID getAccessibleTableRowSelectionCountMethod; + jmethodID isAccessibleTableRowSelectedMethod; + jmethodID getAccessibleTableRowSelectionsMethod; + + jmethodID getAccessibleTableColumnSelectionCountMethod; + jmethodID isAccessibleTableColumnSelectedMethod; + jmethodID getAccessibleTableColumnSelectionsMethod; + + jmethodID getAccessibleTableRowMethod; + jmethodID getAccessibleTableColumnMethod; + jmethodID getAccessibleTableIndexMethod; + + /* end AccessibleTable */ + + /* begin AccessibleRelationSet */ + + jmethodID getAccessibleRelationSetMethod; + jmethodID getAccessibleRelationCountMethod; + jmethodID getAccessibleRelationKeyMethod; + jmethodID getAccessibleRelationTargetCountMethod; + jmethodID getAccessibleRelationTargetMethod; + + /* end AccessibleRelationSet */ + + // AccessibleHypertext methods + jmethodID getAccessibleHypertextMethod; + jmethodID getAccessibleHyperlinkCountMethod; + jmethodID getAccessibleHyperlinkTextMethod; + jmethodID getAccessibleHyperlinkURLMethod; + jmethodID getAccessibleHyperlinkStartIndexMethod; + jmethodID getAccessibleHyperlinkEndIndexMethod; + jmethodID getAccessibleHypertextLinkIndexMethod; + jmethodID getAccessibleHyperlinkMethod; + jmethodID activateAccessibleHyperlinkMethod; + + // AccessibleKeyBinding + jmethodID getAccessibleKeyBindingsCountMethod; + jmethodID getAccessibleKeyBindingCharMethod; + jmethodID getAccessibleKeyBindingModifiersMethod; + + // AccessibleIcon + jmethodID getAccessibleIconsCountMethod; + jmethodID getAccessibleIconDescriptionMethod; + jmethodID getAccessibleIconHeightMethod; + jmethodID getAccessibleIconWidthMethod; + + // AccessibleAction + jmethodID getAccessibleActionsCountMethod; + jmethodID getAccessibleActionNameMethod; + jmethodID doAccessibleActionsMethod; + + // AccessibleText + jmethodID getAccessibleCharCountFromContextMethod; + jmethodID getAccessibleCaretPositionFromContextMethod; + jmethodID getAccessibleIndexAtPointFromContextMethod; + + jmethodID getAccessibleLetterAtIndexFromContextMethod; + jmethodID getAccessibleWordAtIndexFromContextMethod; + jmethodID getAccessibleSentenceAtIndexFromContextMethod; + + jmethodID getAccessibleTextSelectionStartFromContextMethod; + jmethodID getAccessibleTextSelectionEndFromContextMethod; + jmethodID getAccessibleTextSelectedTextFromContextMethod; + jmethodID getAccessibleAttributesAtIndexFromContextMethod; + jmethodID getAccessibleAttributeSetAtIndexFromContextMethod; + jmethodID getAccessibleTextRectAtIndexFromContextMethod; + jmethodID getAccessibleXcoordTextRectAtIndexFromContextMethod; + jmethodID getAccessibleYcoordTextRectAtIndexFromContextMethod; + jmethodID getAccessibleHeightTextRectAtIndexFromContextMethod; + jmethodID getAccessibleWidthTextRectAtIndexFromContextMethod; + jmethodID getAccessibleTextLineLeftBoundsFromContextMethod; + jmethodID getAccessibleTextLineRightBoundsFromContextMethod; + jmethodID getAccessibleTextRangeFromContextMethod; + + jmethodID getCurrentAccessibleValueFromContextMethod; + jmethodID getMaximumAccessibleValueFromContextMethod; + jmethodID getMinimumAccessibleValueFromContextMethod; + + jmethodID addAccessibleSelectionFromContextMethod; + jmethodID clearAccessibleSelectionFromContextMethod; + jmethodID getAccessibleSelectionContextFromContextMethod; + jmethodID getAccessibleSelectionCountFromContextMethod; + jmethodID isAccessibleChildSelectedFromContextMethod; + jmethodID removeAccessibleSelectionFromContextMethod; + jmethodID selectAllAccessibleSelectionFromContextMethod; + + jmethodID addJavaEventNotificationMethod; + jmethodID removeJavaEventNotificationMethod; + jmethodID addAccessibilityEventNotificationMethod; + jmethodID removeAccessibilityEventNotificationMethod; + + jmethodID getBoldFromAttributeSetMethod; + jmethodID getItalicFromAttributeSetMethod; + jmethodID getUnderlineFromAttributeSetMethod; + jmethodID getStrikethroughFromAttributeSetMethod; + jmethodID getSuperscriptFromAttributeSetMethod; + jmethodID getSubscriptFromAttributeSetMethod; + jmethodID getBackgroundColorFromAttributeSetMethod; + jmethodID getForegroundColorFromAttributeSetMethod; + jmethodID getFontFamilyFromAttributeSetMethod; + jmethodID getFontSizeFromAttributeSetMethod; + jmethodID getAlignmentFromAttributeSetMethod; + jmethodID getBidiLevelFromAttributeSetMethod; + jmethodID getFirstLineIndentFromAttributeSetMethod; + jmethodID getLeftIndentFromAttributeSetMethod; + jmethodID getRightIndentFromAttributeSetMethod; + jmethodID getLineSpacingFromAttributeSetMethod; + jmethodID getSpaceAboveFromAttributeSetMethod; + jmethodID getSpaceBelowFromAttributeSetMethod; + + jmethodID setTextContentsMethod; + jmethodID getParentWithRoleMethod; + jmethodID getTopLevelObjectMethod; + jmethodID getParentWithRoleElseRootMethod; + jmethodID getObjectDepthMethod; + jmethodID getActiveDescendentMethod; + + /** + * Additional methods for Teton + */ + jmethodID getVirtualAccessibleNameFromContextMethod; // Ben Key + jmethodID requestFocusMethod; + jmethodID selectTextRangeMethod; + jmethodID getTextAttributesInRangeMethod; + jmethodID getVisibleChildrenCountMethod; + jmethodID getVisibleChildMethod; + jmethodID setCaretPositionMethod; + + jmethodID getCaretLocationMethod; + jmethodID getCaretLocationXMethod; + jmethodID getCaretLocationYMethod; + jmethodID getCaretLocationHeightMethod; + jmethodID getCaretLocationWidthMethod; + +public: + AccessBridgeJavaEntryPoints(JNIEnv *jniEnvironment, jobject bridgeObject); + ~AccessBridgeJavaEntryPoints(); + BOOL BuildJavaEntryPoints(); + + // HWND management methods + BOOL isJavaWindow(jint window); + jobject getAccessibleContextFromHWND(jint window); + HWND getHWNDFromAccessibleContext(jobject accessibleContext); + + // version methods + BOOL getVersionInfo(AccessBridgeVersionInfo *info); + + // verification methods + BOOL verifyAccessibleText(jobject obj); + + /* ===== utility methods ===== */ + BOOL isSameObject(jobject obj1, jobject obj2); + BOOL setTextContents(const jobject accessibleContext, const wchar_t *text); + jobject getParentWithRole (const jobject accessibleContext, const wchar_t *role); + jobject getTopLevelObject (const jobject accessibleContext); + jobject getParentWithRoleElseRoot (const jobject accessibleContext, const wchar_t *role); + jint getObjectDepth (const jobject accessibleContext); + jobject getActiveDescendent (const jobject accessibleContext); + + // Accessible Context methods + jobject getAccessibleContextAt(jint x, jint y, jobject AccessibleContext); + jobject getAccessibleContextWithFocus(); + BOOL getAccessibleContextInfo(jobject AccessibleContext, AccessibleContextInfo *info); + jobject getAccessibleChildFromContext(jobject AccessibleContext, jint childIndex); + jobject getAccessibleParentFromContext(jobject AccessibleContext); + + /* begin AccessibleTable methods */ + + BOOL getAccessibleTableInfo(jobject acParent, AccessibleTableInfo *tableInfo); + BOOL getAccessibleTableCellInfo(jobject accessibleTable,jint row, jint column, + AccessibleTableCellInfo *tableCellInfo); + + BOOL getAccessibleTableRowHeader(jobject acParent, AccessibleTableInfo *tableInfo); + BOOL getAccessibleTableColumnHeader(jobject acParent, AccessibleTableInfo *tableInfo); + + jobject getAccessibleTableRowDescription(jobject acParent, jint row); + jobject getAccessibleTableColumnDescription(jobject acParent, jint column); + + jint getAccessibleTableRowSelectionCount(jobject accessibleTable); + BOOL isAccessibleTableRowSelected(jobject accessibleTable, jint row); + BOOL getAccessibleTableRowSelections(jobject accessibleTable, jint count, jint *selections); + + jint getAccessibleTableColumnSelectionCount(jobject accessibleTable); + BOOL isAccessibleTableColumnSelected(jobject accessibleTable, jint column); + BOOL getAccessibleTableColumnSelections(jobject accessibleTable, jint count, jint *selections); + + jint getAccessibleTableRow(jobject accessibleTable, jint index); + jint getAccessibleTableColumn(jobject accessibleTable, jint index); + jint getAccessibleTableIndex(jobject accessibleTable, jint row, jint column); + + /* end AccessibleTable methods */ + + BOOL getAccessibleRelationSet(jobject accessibleContext, AccessibleRelationSetInfo *relationSetInfo); + + // AccessibleHypertext methods + BOOL getAccessibleHypertext(jobject accessibleContext, AccessibleHypertextInfo *hyperlink); + + BOOL activateAccessibleHyperlink(jobject accessibleContext, jobject accessibleHyperlink); + + BOOL getAccessibleHypertextExt(const jobject accessibleContext, + const jint nStartIndex, + /* OUT */ AccessibleHypertextInfo *hypertext); + jint getAccessibleHyperlinkCount(const jobject accessibleContext); + jint getAccessibleHypertextLinkIndex(const jobject accessibleContext, + const jint nIndex); + BOOL getAccessibleHyperlink(const jobject accessibleContext, + const jint nIndex, + /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo); + + // Accessible Keybinding methods + BOOL getAccessibleKeyBindings(jobject accessibleContext, AccessibleKeyBindings *keyBindings); + + // AccessibleIcon methods + BOOL getAccessibleIcons(jobject accessibleContext, AccessibleIcons *icons); + + // AccessibleActionMethods + BOOL getAccessibleActions(jobject accessibleContext, AccessibleActions *actions); + BOOL doAccessibleActions(jobject accessibleContext, AccessibleActionsToDo *actionsToDo, jint *failure); + + // Accessible Text methods + BOOL getAccessibleTextInfo(jobject AccessibleContext, AccessibleTextInfo *textInfo, jint x, jint y); + BOOL getAccessibleTextItems(jobject AccessibleContext, AccessibleTextItemsInfo *textItems, jint index); + BOOL getAccessibleTextSelectionInfo(jobject AccessibleContext, AccessibleTextSelectionInfo *selectionInfo); + BOOL getAccessibleTextAttributes(jobject AccessibleContext, jint index, AccessibleTextAttributesInfo *attributes); + BOOL getAccessibleTextRect(jobject AccessibleContext, AccessibleTextRectInfo *rectInfo, jint index); + BOOL getAccessibleCaretRect(jobject AccessibleContext, AccessibleTextRectInfo *rectInfo, jint index); + BOOL getAccessibleTextLineBounds(jobject AccessibleContext, jint index, jint *startIndex, jint *endIndex); + BOOL getAccessibleTextRange(jobject AccessibleContext, jint start, jint end, wchar_t *text, short len); + + // Accessible Value methods + BOOL getCurrentAccessibleValueFromContext(jobject AccessibleContext, wchar_t *value, short len); + BOOL getMaximumAccessibleValueFromContext(jobject AccessibleContext, wchar_t *value, short len); + BOOL getMinimumAccessibleValueFromContext(jobject AccessibleContext, wchar_t *value, short len); + + // Accessible Selection methods + void addAccessibleSelectionFromContext(jobject AccessibleContext, int i); + void clearAccessibleSelectionFromContext(jobject AccessibleContext); + jobject getAccessibleSelectionFromContext(jobject AccessibleContext, int i); + int getAccessibleSelectionCountFromContext(jobject AccessibleContext); + BOOL isAccessibleChildSelectedFromContext(jobject AccessibleContext, int i); + void removeAccessibleSelectionFromContext(jobject AccessibleContext, int i); + void selectAllAccessibleSelectionFromContext(jobject AccessibleContext); + + // Event handling methods + BOOL addJavaEventNotification(jlong type); + BOOL removeJavaEventNotification(jlong type); + BOOL addAccessibilityEventNotification(jlong type); + BOOL removeAccessibilityEventNotification(jlong type); + + /** + * Additional methods for Teton + */ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + BOOL getVirtualAccessibleName(const jobject accessibleContext, wchar_t *name, int len); + + /** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ + BOOL requestFocus(const jobject accessibleContext); + + /** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ + BOOL selectTextRange(const jobject accessibleContext, int startIndex, int endIndex); + + /** + * Get text attributes between two indices. The attribute list includes the text at the + * start index and the text at the end index. Returns whether successful; + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + BOOL getTextAttributesInRange(const jobject accessibleContext, int startIndex, int endIndex, + AccessibleTextAttributesInfo *attributes, short *len); + + /** + * Gets the number of visible children of a component. Returns -1 on error. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + int getVisibleChildrenCount(const jobject accessibleContext); + + /** + * Gets the visible children of an AccessibleContext. Returns whether successful; + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + BOOL getVisibleChildren(const jobject accessibleContext, const int startIndex, + VisibleChildrenInfo *visibleChildrenInfo); + + /** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ + BOOL setCaretPosition(const jobject accessibleContext, int position); + + /** + * Gets the bounding rectangle for the text caret + */ + BOOL getCaretLocation(jobject AccessibleContext, AccessibleTextRectInfo *rectInfo, jint index); + +}; + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/JavaAccessBridge.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/JavaAccessBridge.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,2799 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A DLL which is loaded by Java applications to handle communication + * between Java VMs purposes of Accessbility. + */ + +#include "AccessBridgeDebug.h" +#include "JavaAccessBridge.h" +#include "com_sun_java_accessibility_AccessBridge.h" // programatically generated by JNI +#include "accessBridgeResource.h" +#include "accessBridgeCallbacks.h" +#include "AccessBridgeMessages.h" + + +#include +#include + +#include +#include + +JavaAccessBridge *theJavaAccessBridge; +HWND theDialogWindow; + +// re-entrance lock for receiving memory messages +CRITICAL_SECTION receiveMemoryIPCLock; + + +// unique broadcast msg. IDs gotten dymanically +extern UINT theFromJavaHelloMsgID; +extern UINT theFromWindowsHelloMsgID; + + +// --------------------------------------------------------------------------- + +extern "C" { + /** + * DllMain - where Windows executables will load/unload us + * + */ + BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) { + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: + InitializeCriticalSection(&receiveMemoryIPCLock); + theJavaAccessBridge = new JavaAccessBridge(hinstDll); + break; + + case DLL_PROCESS_DETACH: // A Windows executable unloaded us + if (theJavaAccessBridge != (JavaAccessBridge *) 0) { + delete theJavaAccessBridge; + DeleteCriticalSection(&receiveMemoryIPCLock); + } + break; + } + return TRUE; + } + + /** + * Open a native window (and init the wrappers we'll be using) + * + */ + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_runDLL(JNIEnv *env, jobject obj) { + PrintDebugString("\r\nJavaAccessBridge.DLL runDLL() called"); + theJavaAccessBridge->javaRun(env, obj); + } + +#if 0 // SetDlgItemText has caused problems with JAWS + /** + * Append debug info to dialog + * + */ + void AppendToCallInfo(char *s) { + char buffer[4096]; + + PrintDebugString(s); + + GetDlgItemText(theDialogWindow, cCallInfo, buffer, sizeof(buffer)); + if (strlen(buffer) < (sizeof(buffer) - strlen(s))) { + strncat(buffer, s, sizeof(buffer)); + SetDlgItemText(theDialogWindow, cCallInfo, buffer); + } else { + SetDlgItemText(theDialogWindow, cCallInfo, s); + } + } +#endif + + + /** + * Our window proc + * + */ + BOOL APIENTRY AccessBridgeDialogProc (HWND hDlg, UINT message, UINT wParam, LONG lParam) { + int command; + COPYDATASTRUCT *sentToUs; + char *package; + //DEBUG_CODE(char buffer[256]); + + switch (message) { + case WM_INITDIALOG: + //DEBUG_CODE(SetDlgItemText(theDialogWindow, cStatusText, "Initializing")); + break; + + case WM_COMMAND: + command = LOWORD (wParam); + break; + + // call from Java with data for us to deliver + case WM_COPYDATA: + if (theDialogWindow == (HWND) wParam) { + //DEBUG_CODE(SetDlgItemText(theDialogWindow, cStatusText, "Got WM_COPYDATA from ourselves")); + } else { + //DEBUG_CODE(sprintf(buffer, "Got WM_COPYDATA from HWND %p", wParam)); + //DEBUG_CODE(SetDlgItemText(theDialogWindow, cStatusText, buffer)); + sentToUs = (COPYDATASTRUCT *) lParam; + package = (char *) sentToUs->lpData; + theJavaAccessBridge->processPackage(package, sentToUs->cbData); + } + break; + + // call from Java with data for us retrieve from memory mapped file and deliver + case AB_MESSAGE_WAITING: + // wParam == sourceHwnd + // lParam == buffer size in shared memory + if (theDialogWindow == (HWND) wParam) { + //DEBUG_CODE(SetDlgItemText(theDialogWindow, cStatusText, "Got AB_MESSAGE_WAITING from ourselves")); + } else { + //DEBUG_CODE(sprintf(buffer, "Got AB_MESSAGE_WAITING from HWND %p", wParam)); + //DEBUG_CODE(SetDlgItemText(theDialogWindow, cStatusText, buffer)); + LRESULT returnVal = theJavaAccessBridge->receiveMemoryPackage((HWND) wParam, lParam); + } + break; + + // a JavaAccessBridge DLL is going away + case AB_DLL_GOING_AWAY: + // wParam == sourceHwnd + //DEBUG_CODE(SetDlgItemText(theDialogWindow, cStatusText, "Got AB_DLL_GOING_AWAY message")); + theJavaAccessBridge->WindowsATDestroyed((HWND) wParam); + break; + + default: + // the Windows AT is saying "hi"! + // wParam == sourceHwnc; lParam unused + if (message == theFromWindowsHelloMsgID) { + // A new Windows AT just said "hi"; + // say "hi" back so it can mate up with us + // otherwise don't do anything (e.g. don't set up data structures yet) + theJavaAccessBridge->postHelloToWindowsDLLMsg((HWND) wParam); + } + } + return FALSE; + } + +} + + +// ----------------------------- + + +/** + * Initialize the JavaAccessBridge + * + */ +JavaAccessBridge::JavaAccessBridge(HINSTANCE hInstance) { + windowsInstance = hInstance; + ATs = (AccessBridgeATInstance *) 0; + initBroadcastMessageIDs(); // get the unique to us broadcast msg. IDs +} + +extern DWORD JavaBridgeThreadId; + +/** + * Destroy the JavaAccessBridge + * + */ +JavaAccessBridge::~JavaAccessBridge() { + // inform all other AccessBridges that we're going away + + PrintDebugString("\r\nin JavaAccessBridge::~JavaAccessBridge()"); + + // Send a shutdown message for those applications like StarOffice that do + // send a shutdown message themselves. + javaShutdown(NULL, 0); + + AccessBridgeATInstance *current = ATs; + while (current != (AccessBridgeATInstance *) 0) { + PrintDebugString(" telling %p we're going away", current->winAccessBridgeWindow); + SendMessage(current->winAccessBridgeWindow, + AB_DLL_GOING_AWAY, (WPARAM) dialogWindow, (LPARAM) 0); + current = current->nextATInstance; + } + + PrintDebugString(" finished telling ATs about our demise"); + + if(JavaBridgeThreadId) + { + PostThreadMessage(JavaBridgeThreadId,WM_USER+1,0,0); + Sleep(100); + } + + delete ATs; + + PrintDebugString(" finished deleting ATs"); + PrintDebugString("GOODBYE CRUEL WORLD..."); +} + + +void +JavaAccessBridge::javaRun(JNIEnv *env, jobject obj) { + MSG msg; + + PrintDebugString("JavaAccessBridge::javaRun(%p, %p) called", env, obj); + + if (env->GetJavaVM(&javaVM) != 0) { + return; // huh!?!?! + } + PrintDebugString(" -> javaVM = %p", javaVM); + + if (javaVM->AttachCurrentThread((void **) &windowsThreadJNIEnv, NULL) != 0) { + return; // huh!?!?! + } + PrintDebugString(" -> windowsThreadJNIEnv = %p", windowsThreadJNIEnv); + + javaThreadABObject = env->NewGlobalRef(obj); + windowsThreadABObject = windowsThreadJNIEnv->NewGlobalRef(obj); + + // initialize the Java thread AccessBridge entry points + javaThreadEntryPoints = new AccessBridgeJavaEntryPoints(env, javaThreadABObject); + if (javaThreadEntryPoints->BuildJavaEntryPoints() == FALSE) { + return; // couldn't build our entry points; let's get out of here! + } + PrintDebugString(" all Java thread entry points successfully found."); + + // initialize the Windows thread AccessBridge entry points + windowsThreadEntryPoints = new AccessBridgeJavaEntryPoints(windowsThreadJNIEnv, + windowsThreadABObject); + if (windowsThreadEntryPoints->BuildJavaEntryPoints() == FALSE) { + return; // couldn't build our entry points; let's get out of here! + } + PrintDebugString(" all Windows thread entry points successfully found."); + + + // open our window + if (initWindow() == TRUE) { + PrintDebugString(" Window created. HWND = %p", dialogWindow); + + // post a broadcast msg.; let other AccessBridge DLLs know we exist + postHelloToWindowsDLLMsg(HWND_BROADCAST); + + // do that message loop thing + while (GetMessage(&msg, NULL, 0, 0)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } else { + PrintDebugString(" FAILED TO CREATE WINDOW!!!"); + } + + javaVM->DetachCurrentThread(); +} + +/** + * Bring up our window; make a connection to the rest of the world + * + */ +BOOL +JavaAccessBridge::initWindow() { + theDialogWindow = CreateDialog(windowsInstance, + "ACCESSBRIDGESTATUSWINDOW", NULL, + (DLGPROC) AccessBridgeDialogProc); + + // If window could not be created, return "failure". + if (!theDialogWindow) + return FALSE; + + dialogWindow = theDialogWindow; + + // Make the window visible, update its client area, & return "success". + // DEBUG_CODE(ShowWindow (theDialogWindow, SW_SHOWNORMAL)); + // DEBUG_CODE(UpdateWindow (theDialogWindow)); + + return TRUE; +} + + + +// ----------------------- + + +/** + * postHelloToWindowsDLLMsg + * - PostMessage(theFromJavaHelloMsgID) to let one or + * all WindowDLLs we're here and have a vmID + * + * destHwnd is either a single hwnd or HWND_BROADCAST + * (former if a reply, latter if we're just born) + * wParam is our HWND + * lParam is our vmID + * + */ +void +JavaAccessBridge::postHelloToWindowsDLLMsg(HWND destHwnd) { + PrintDebugString("\r\nin JavaAccessBridge::postHelloToWindowsDLLMsg"); + PrintDebugString(" calling PostMessage(%p, %X, %p, %p)", + destHwnd, theFromJavaHelloMsgID, dialogWindow, javaVM); + PostMessage(destHwnd, theFromJavaHelloMsgID, (WPARAM) dialogWindow, (LPARAM) dialogWindow); +} + + +// ----------------------- + +/** + * sendPackage - uses SendMessage(WM_COPYDATA) to do IPC messaging + * with the Java AccessBridge DLL + * + */ +void +JavaAccessBridge::sendPackage(char *buffer, int bufsize, HWND destHwnd) { + COPYDATASTRUCT toCopy; + toCopy.dwData = 0; // 32-bits we could use for something... + toCopy.cbData = bufsize; + toCopy.lpData = buffer; + + SendMessage(destHwnd, WM_COPYDATA, (WPARAM) dialogWindow, (LPARAM) &toCopy); +} + + +/** + * sendJavaEventPackage - walk through ATs, sending event messages to 'em + * + */ +void +JavaAccessBridge::sendJavaEventPackage(char *buffer, int bufsize, long type) { + + PrintDebugString("JavaAccessBridge::sendJavaEventPackage(), type = %X", type); + + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + } + + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + ati->sendJavaEventPackage(buffer, bufsize, type); + ati = ati->nextATInstance; + } +} + +/** + * sendAccessibilityEventPackage - walk through ATs, sending event messages to 'em + * + */ +void +JavaAccessBridge::sendAccessibilityEventPackage(char *buffer, int bufsize, long type) { + + PrintDebugString("JavaAccessBridge::sendAccessibilityEventPackage(), type = %X", type); + + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + } + + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + ati->sendAccessibilityEventPackage(buffer, bufsize, type); + ati = ati->nextATInstance; + } +} + + + + +/** + * receiveMemoryPackage - uses Memory-Mapped files to do IPC messaging + * with the Java AccessBridge DLL, receiving the + * message from Java AccessBridge DLL by reading the + * contents of the shared memory mapped file that + * is used for Java-initiated messages + * + */ +BOOL +JavaAccessBridge::receiveMemoryPackage(HWND srcWindow, long bufsize) { + char *IPCview; + + PrintDebugString("\r\nJavaAccessBridge::receiveMemoryPackage(%p, %d)", srcWindow, bufsize); + + // look-up the appropriate IPCview based on the srcHWND of the Windows AccessBridge DLL + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR! - ATs == 0 (shouldn't happen in receiveMemoryPackage()!"); + return FALSE; + } + AccessBridgeATInstance *ati = ATs->findABATInstanceFromATHWND(srcWindow); + if (ati != (AccessBridgeATInstance *) 0) { + IPCview = (char *) ati->memoryMappedView; + + // wait for the lock if someone else has it (re-entrancy) + EnterCriticalSection(&receiveMemoryIPCLock); + { + // set byte at end of buffer to indicate to caller that we have reached this point + IPCview[bufsize] = 1; + + // process the package + processPackage(IPCview, bufsize); + } + // release re-entrance lock + LeaveCriticalSection(&receiveMemoryIPCLock); + + return TRUE; + + } else { + //DEBUG_CODE(AppendToCallInfo("ERROR receiving memory package: couldn't find srcWindow")); + PrintDebugString("ERROR receiving memory package: couldn't find srcWindow"); + return FALSE; + } +} + +/** + * processPackage - processes the output of SendMessage(WM_COPYDATA) + * to do IPC messaging with the Windows AccessBridge DLL + * + */ +LRESULT +JavaAccessBridge::processPackage(char *buffer, int bufsize) { + PrintDebugString("\r\nProcessing package sent from Windows, bufsize = %d:", bufsize); + + PackageType *type = (PackageType *) buffer; + LRESULT returnVal = 0; + PrintDebugString(" PackageType = %X:", *type); + jobject rAC; + + switch (*type) { + + + case cMemoryMappedFileCreatedPackage: + // Windows is telling us it created a memory mapped file for us to use + // in repsonding to various information querying packages (see below) + PrintDebugString(" type == cMemoryMappedFileCreatedPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(MemoryMappedFileCreatedPackage))) { + MemoryMappedFileCreatedPackage *pkg = + (MemoryMappedFileCreatedPackage *) (buffer + sizeof(PackageType)); + returnVal = MemoryMappedFileCreated((HWND)ABLongToHandle(pkg->bridgeWindow), pkg->filename); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(MemoryMappedFileCreatedPackage)); + } + break; + + // ------------ information querying packages ------------------ + + case cReleaseJavaObjectPackage: + PrintDebugString(" type == cReleaseJavaObjectPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(ReleaseJavaObjectPackage))) { + ReleaseJavaObjectPackage *pkg = + (ReleaseJavaObjectPackage *) (buffer + sizeof(PackageType)); + releaseJavaObject((jobject)pkg->object); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(ReleaseJavaObjectPackage)); + } + break; + + case cGetAccessBridgeVersionPackage: + PrintDebugString(" type == cGetAccessBridgeVersionPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessBridgeVersionPackage))) { + GetAccessBridgeVersionPackage *pkg = + (GetAccessBridgeVersionPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getVersionInfo(&(pkg->rVersionInfo)); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessBridgeVersionPackage)); + } + break; + + case cIsJavaWindowPackage: + PrintDebugString(" type == cIsJavaWindowPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(IsJavaWindowPackage))) { + IsJavaWindowPackage *pkg = + (IsJavaWindowPackage *) (buffer + sizeof(PackageType)); + pkg->rResult = + windowsThreadEntryPoints->isJavaWindow(pkg->window); + PrintDebugString(" -> returning result = %d", pkg->rResult); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(IsJavaWindowPackage)); + } + break; + + case cIsSameObjectPackage: + PrintDebugString(" type == cIsSameObjectPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(IsSameObjectPackage))) { + IsSameObjectPackage *pkg = + (IsSameObjectPackage *) (buffer + sizeof(PackageType)); + pkg->rResult = + windowsThreadEntryPoints->isSameObject((jobject)pkg->obj1, (jobject)pkg->obj2); + PrintDebugString(" -> returning result = %d", pkg->rResult); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(IsSameObjectPackage)); + } + break; + + + case cGetAccessibleContextFromHWNDPackage: + PrintDebugString(" type == cGetAccessibleContextFromHWNDPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleContextFromHWNDPackage))) { + GetAccessibleContextFromHWNDPackage *pkg = + (GetAccessibleContextFromHWNDPackage *) (buffer + sizeof(PackageType)); + rAC = windowsThreadEntryPoints->getAccessibleContextFromHWND(pkg->window); + pkg->rAccessibleContext = (JOBJECT64)rAC; + pkg->rVMID = HandleToLong(dialogWindow); + PrintDebugString(" -> returning AC = %p, vmID = %X", rAC, pkg->rVMID); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleContextFromHWNDPackage)); + } + break; + + + case cGetHWNDFromAccessibleContextPackage: + PrintDebugString(" type == cGetHWNDFromAccessibleContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetHWNDFromAccessibleContextPackage))) { + GetHWNDFromAccessibleContextPackage *pkg = + (GetHWNDFromAccessibleContextPackage *) (buffer + sizeof(PackageType)); + pkg->rHWND = + ABHandleToLong( windowsThreadEntryPoints->getHWNDFromAccessibleContext((jobject)pkg->accessibleContext) ); + PrintDebugString(" -> returning HWND = %p", pkg->rHWND); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetHWNDFromAccessibleContextPackage)); + } + break; + + + /* ===== utility methods ===== */ + + case cSetTextContentsPackage: + PrintDebugString(" type == cSetTextContentsPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(SetTextContentsPackage))) { + SetTextContentsPackage *pkg = + (SetTextContentsPackage *) (buffer + sizeof(PackageType)); + pkg->rResult = + windowsThreadEntryPoints->setTextContents((jobject)pkg->accessibleContext, pkg->text); + PrintDebugString(" -> returning result = %d", pkg->rResult); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(SetTextContentsPackage)); + } + break; + + case cGetParentWithRolePackage: + if (bufsize == (sizeof(PackageType) + sizeof(GetParentWithRolePackage))) { + GetParentWithRolePackage *pkg = + (GetParentWithRolePackage *) (buffer + sizeof(PackageType)); + rAC = windowsThreadEntryPoints->getParentWithRole((jobject)pkg->accessibleContext, pkg->role); + pkg->rAccessibleContext = (JOBJECT64)rAC; + PrintDebugString(" type == cGetParentWithRolePackage"); + PrintDebugString(" pkg->vmID: %X", pkg->vmID); + PrintDebugString(" pkg->accessibleContext: %p", (jobject)pkg->accessibleContext); + PrintDebugString(" pkg->role: %ls", pkg->role); + PrintDebugString(" -> returning rAccessibleContext = %p", rAC); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetParentWithRolePackage)); + } + break; + + case cGetTopLevelObjectPackage: + PrintDebugString(" type == cGetTopLevelObjectPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetTopLevelObjectPackage))) { + GetTopLevelObjectPackage *pkg = + (GetTopLevelObjectPackage *) (buffer + sizeof(PackageType)); + rAC = windowsThreadEntryPoints->getTopLevelObject((jobject)pkg->accessibleContext); + pkg->rAccessibleContext = (JOBJECT64)rAC; + PrintDebugString(" -> returning rAccessibleContext = %p", rAC); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetTopLevelObjectPackage)); + } + break; + + case cGetParentWithRoleElseRootPackage: + PrintDebugString(" type == cGetParentWithRoleElseRootPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetParentWithRoleElseRootPackage))) { + GetParentWithRoleElseRootPackage *pkg = + (GetParentWithRoleElseRootPackage *) (buffer + sizeof(PackageType)); + rAC = windowsThreadEntryPoints->getParentWithRoleElseRoot((jobject)pkg->accessibleContext, pkg->role); + pkg->rAccessibleContext = (JOBJECT64)rAC; + PrintDebugString(" -> returning rAccessibleContext = %p", rAC); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetParentWithRoleElseRootPackage)); + } + break; + + case cGetObjectDepthPackage: + PrintDebugString(" type == cGetObjectDepthPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetObjectDepthPackage))) { + GetObjectDepthPackage *pkg = + (GetObjectDepthPackage *) (buffer + sizeof(PackageType)); + pkg->rResult = + windowsThreadEntryPoints->getObjectDepth((jobject)pkg->accessibleContext); + PrintDebugString(" -> returning rResult = %d", pkg->rResult); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetObjectDepthPackage)); + } + break; + + case cGetActiveDescendentPackage: + PrintDebugString(" type == cGetActiveDescendentPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetActiveDescendentPackage))) { + GetActiveDescendentPackage *pkg = + (GetActiveDescendentPackage *) (buffer + sizeof(PackageType)); + rAC = windowsThreadEntryPoints->getActiveDescendent((jobject)pkg->accessibleContext); + pkg->rAccessibleContext = (JOBJECT64)rAC; + PrintDebugString(" -> returning rAccessibleContext = %p", rAC); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetActiveDescendentPackage)); + } + break; + + case cGetAccessibleContextAtPackage: + PrintDebugString(" type == cGetAccessibleContextAtPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleContextAtPackage))) { + GetAccessibleContextAtPackage *pkg = + (GetAccessibleContextAtPackage *) (buffer + sizeof(PackageType)); + pkg->rAccessibleContext = (JOBJECT64) + windowsThreadEntryPoints->getAccessibleContextAt(pkg->x, pkg->y, + (jobject)pkg->AccessibleContext); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleContextAtPackage)); + } + break; + + case cGetAccessibleContextWithFocusPackage: + PrintDebugString(" type == cGetAccessibleContextWithFocusPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleContextWithFocusPackage))) { + GetAccessibleContextWithFocusPackage *pkg = + (GetAccessibleContextWithFocusPackage *) (buffer + sizeof(PackageType)); + pkg->rAccessibleContext = (JOBJECT64) + windowsThreadEntryPoints->getAccessibleContextWithFocus(); + pkg->rVMID = HandleToLong(dialogWindow); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleContextWithFocusPackage)); + } + break; + + case cGetAccessibleContextInfoPackage: + PrintDebugString(" type == cGetAccessibleContextInfoPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleContextInfoPackage))) { + GetAccessibleContextInfoPackage *pkg = + (GetAccessibleContextInfoPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleContextInfo( + (jobject)pkg->AccessibleContext, &(pkg->rAccessibleContextInfo)); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleContextInfoPackage)); + } + break; + + case cGetAccessibleChildFromContextPackage: + PrintDebugString(" type == cGetAccessibleChildFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleChildFromContextPackage))) { + GetAccessibleChildFromContextPackage *pkg = + (GetAccessibleChildFromContextPackage *) (buffer + sizeof(PackageType)); + pkg->rAccessibleContext = (JOBJECT64)windowsThreadEntryPoints->getAccessibleChildFromContext( + (jobject)pkg->AccessibleContext, pkg->childIndex); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleChildFromContextPackage)); + } + break; + + case cGetAccessibleParentFromContextPackage: + PrintDebugString(" type == cGetAccessibleParentFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleParentFromContextPackage))) { + GetAccessibleParentFromContextPackage *pkg = + (GetAccessibleParentFromContextPackage *) (buffer + sizeof(PackageType)); + pkg->rAccessibleContext = (JOBJECT64)windowsThreadEntryPoints->getAccessibleParentFromContext( + (jobject)pkg->AccessibleContext); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleParentFromContextPackage)); + } + break; + + // ------------ begin AccessibleTable packages ------------------ + + case cGetAccessibleTableInfoPackage: + PrintDebugString(" ##### type == cGetAccessibleTableInfoPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableInfoPackage))) { + GetAccessibleTableInfoPackage *pkg = + (GetAccessibleTableInfoPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTableInfo((jobject)pkg->accessibleContext, + &(pkg->rTableInfo)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableInfoPackage)); + } + break; + + case cGetAccessibleTableCellInfoPackage: + PrintDebugString(" ##### type == cGetAccessibleTableCellInfoPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableCellInfoPackage))) { + GetAccessibleTableCellInfoPackage *pkg = + (GetAccessibleTableCellInfoPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTableCellInfo((jobject)pkg->accessibleTable, pkg->row, + pkg->column, &(pkg->rTableCellInfo)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableCellInfoPackage)); + } + break; + + case cGetAccessibleTableRowHeaderPackage: + PrintDebugString(" ##### type == cGetAccessibleTableRowHeaderPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableRowHeaderPackage))) { + GetAccessibleTableRowHeaderPackage *pkg = + (GetAccessibleTableRowHeaderPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTableRowHeader((jobject)pkg->accessibleContext, + &(pkg->rTableInfo)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableRowHeaderPackage)); + } + break; + + case cGetAccessibleTableColumnHeaderPackage: + PrintDebugString(" ##### type == cGetAccessibleTableColumnHeaderPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableColumnHeaderPackage))) { + GetAccessibleTableColumnHeaderPackage *pkg = + (GetAccessibleTableColumnHeaderPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTableColumnHeader((jobject)pkg->accessibleContext, + &(pkg->rTableInfo)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableColumnHeaderPackage)); + } + break; + + + case cGetAccessibleTableRowDescriptionPackage: + PrintDebugString(" ##### type == cGetAccessibleTableRowDescriptionPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableRowDescriptionPackage))) { + GetAccessibleTableRowDescriptionPackage *pkg = + (GetAccessibleTableRowDescriptionPackage *) (buffer + sizeof(PackageType)); + pkg->rAccessibleContext = (JOBJECT64)windowsThreadEntryPoints->getAccessibleTableRowDescription( + (jobject)pkg->accessibleContext, pkg->row); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableRowDescriptionPackage)); + } + break; + + case cGetAccessibleTableColumnDescriptionPackage: + PrintDebugString(" ##### type == cGetAccessibleTableColumnDescriptionPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableColumnDescriptionPackage))) { + GetAccessibleTableColumnDescriptionPackage *pkg = + (GetAccessibleTableColumnDescriptionPackage *) (buffer + sizeof(PackageType)); + pkg->rAccessibleContext = (JOBJECT64)windowsThreadEntryPoints->getAccessibleTableColumnDescription( + (jobject)pkg->accessibleContext, pkg->column); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableColumnDescriptionPackage)); + } + break; + + case cGetAccessibleTableColumnSelectionCountPackage: + PrintDebugString(" ##### type == cGetAccessibleTableColumnSelectionCountPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableColumnSelectionCountPackage))) { + GetAccessibleTableColumnSelectionCountPackage *pkg = + (GetAccessibleTableColumnSelectionCountPackage *) (buffer + sizeof(PackageType)); + pkg->rCount = windowsThreadEntryPoints->getAccessibleTableColumnSelectionCount( + (jobject)pkg->accessibleTable); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableColumnSelectionCountPackage)); + } + break; + + case cGetAccessibleTableRowSelectionCountPackage: + PrintDebugString(" ##### type == cGetAccessibleTableRowSelectionCountPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableRowSelectionCountPackage))) { + GetAccessibleTableRowSelectionCountPackage *pkg = + (GetAccessibleTableRowSelectionCountPackage *) (buffer + sizeof(PackageType)); + + pkg->rCount = windowsThreadEntryPoints->getAccessibleTableRowSelectionCount( + (jobject)pkg->accessibleTable); + + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableRowSelectionCountPackage)); + } + break; + + case cIsAccessibleTableRowSelectedPackage: + PrintDebugString(" ##### type == cIsAccessibleTableRowSelectedPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(IsAccessibleTableRowSelectedPackage))) { + IsAccessibleTableRowSelectedPackage *pkg = + (IsAccessibleTableRowSelectedPackage *) (buffer + sizeof(PackageType)); + pkg->rResult = windowsThreadEntryPoints->isAccessibleTableRowSelected( + (jobject)pkg->accessibleTable, pkg->row); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(IsAccessibleTableRowSelectedPackage)); + } + break; + + case cIsAccessibleTableColumnSelectedPackage: + PrintDebugString(" ##### type == cIsAccessibleTableColumnSelectedPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(IsAccessibleTableColumnSelectedPackage))) { + IsAccessibleTableColumnSelectedPackage *pkg = + (IsAccessibleTableColumnSelectedPackage *) (buffer + sizeof(PackageType)); + pkg->rResult = windowsThreadEntryPoints->isAccessibleTableColumnSelected( + (jobject)pkg->accessibleTable, pkg->column); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(IsAccessibleTableColumnSelectedPackage)); + } + break; + + case cGetAccessibleTableColumnSelectionsPackage: + PrintDebugString(" ##### type == cGetAccessibleTableColumnSelectionsPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableColumnSelectionsPackage))) { + GetAccessibleTableColumnSelectionsPackage *pkg = + (GetAccessibleTableColumnSelectionsPackage *) (buffer + sizeof(PackageType)); + PrintDebugString(" ##### cGetAccessibleTableColumnSelectionsPackage count=%d", pkg->count); + windowsThreadEntryPoints->getAccessibleTableColumnSelections( + (jobject)pkg->accessibleTable, pkg->count, pkg->rSelections); + + for (int i = 0; i < pkg->count; i++) { + PrintDebugString(" ##### cGetAccessibleTableColumnSelectionsPackage(%d)=%d", i, pkg->rSelections[i]); + } + + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableColumnSelectionsPackage)); + } + break; + + + case cGetAccessibleTableRowSelectionsPackage: + PrintDebugString(" ##### type == cGetAccessibleTableRowSelectionsPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableRowSelectionsPackage))) { + GetAccessibleTableRowSelectionsPackage *pkg = + (GetAccessibleTableRowSelectionsPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTableRowSelections( + (jobject)pkg->accessibleTable, pkg->count, pkg->rSelections); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableRowSelectionsPackage)); + } + break; + + case cGetAccessibleTableRowPackage: + PrintDebugString(" ##### type == cGetAccessibleTableRowPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableRowPackage))) { + GetAccessibleTableRowPackage *pkg = + (GetAccessibleTableRowPackage *) (buffer + sizeof(PackageType)); + pkg->rRow = windowsThreadEntryPoints->getAccessibleTableRow( + (jobject)pkg->accessibleTable, pkg->index); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableRowPackage)); + } + break; + + case cGetAccessibleTableColumnPackage: + PrintDebugString(" ##### type == cGetAccessibleTableColumnPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableColumnPackage))) { + GetAccessibleTableColumnPackage *pkg = + (GetAccessibleTableColumnPackage *) (buffer + sizeof(PackageType)); + pkg->rColumn = windowsThreadEntryPoints->getAccessibleTableColumn( + (jobject)pkg->accessibleTable, pkg->index); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableColumnPackage)); + } + break; + + case cGetAccessibleTableIndexPackage: + PrintDebugString(" ##### type == cGetAccessibleTableIndexPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTableIndexPackage))) { + GetAccessibleTableIndexPackage *pkg = + (GetAccessibleTableIndexPackage *) (buffer + sizeof(PackageType)); + pkg->rIndex = windowsThreadEntryPoints->getAccessibleTableIndex( + (jobject)pkg->accessibleTable, pkg->row, pkg->column); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTableIndexPackage)); + } + break; + + // ------------ end AccessibleTable packages ------------------ + + + // ------------ begin AccessibleRelationSet packages ------------------ + + case cGetAccessibleRelationSetPackage: + PrintDebugString(" ##### type == cGetAccessibleRelationSetPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleRelationSetPackage))) { + GetAccessibleRelationSetPackage *pkg = + (GetAccessibleRelationSetPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleRelationSet( + (jobject)pkg->accessibleContext, &(pkg->rAccessibleRelationSetInfo)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleRelationSetPackage)); + } + break; + + // ------------ end AccessibleRelationSet packages ------------------ + + // ------------ begin AccessibleHypertext packages ------------------ + + case cGetAccessibleHypertextPackage: + PrintDebugString(" ##### type == cGetAccessibleHypertextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleHypertextPackage))) { + GetAccessibleHypertextPackage *pkg = + (GetAccessibleHypertextPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleHypertext( + (jobject)pkg->accessibleContext, &(pkg->rAccessibleHypertextInfo)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleHypertextPackage)); + } + break; + + case cActivateAccessibleHyperlinkPackage: + PrintDebugString(" ##### type == cActivateAccessibleHyperlinkPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(ActivateAccessibleHyperlinkPackage))) { + ActivateAccessibleHyperlinkPackage *pkg = + (ActivateAccessibleHyperlinkPackage *) (buffer + sizeof(PackageType)); + pkg->rResult = windowsThreadEntryPoints->activateAccessibleHyperlink( + (jobject)pkg->accessibleContext, (jobject)pkg->accessibleHyperlink); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(ActivateAccessibleHyperlinkPackage)); + } + break; + + case cGetAccessibleHyperlinkCountPackage: + PrintDebugString(" ##### type == cGetAccessibleHyperlinkCountPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleHyperlinkCountPackage))) { + GetAccessibleHyperlinkCountPackage *pkg = + (GetAccessibleHyperlinkCountPackage *) (buffer + sizeof(PackageType)); + pkg->rLinkCount = windowsThreadEntryPoints->getAccessibleHyperlinkCount( + (jobject)pkg->accessibleContext); + PrintDebugString(" ##### processing succeeded: pkg->rLinkCount = %d", pkg->rLinkCount); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleHyperlinkCountPackage)); + } + break; + + case cGetAccessibleHypertextExtPackage: + PrintDebugString(" ##### type == cGetAccessibleHypertextExtPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleHypertextExtPackage))) { + GetAccessibleHypertextExtPackage *pkg = + (GetAccessibleHypertextExtPackage *) (buffer + sizeof(PackageType)); + pkg->rSuccess = windowsThreadEntryPoints->getAccessibleHypertextExt( + (jobject)pkg->accessibleContext, pkg->startIndex, &(pkg->rAccessibleHypertextInfo)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleHypertextExtPackage)); + } + break; + + case cGetAccessibleHypertextLinkIndexPackage: + PrintDebugString(" ##### type == cGetAccessibleHypertextLinkIndexPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleHypertextLinkIndexPackage))) { + GetAccessibleHypertextLinkIndexPackage *pkg = + (GetAccessibleHypertextLinkIndexPackage *) (buffer + sizeof(PackageType)); + pkg->rLinkIndex = windowsThreadEntryPoints->getAccessibleHypertextLinkIndex( + (jobject)pkg->hypertext, pkg->charIndex); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleHypertextLinkIndexPackage)); + } + break; + + case cGetAccessibleHyperlinkPackage: + PrintDebugString(" ##### type == cGetAccessibleHyperlinkPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleHyperlinkPackage))) { + GetAccessibleHyperlinkPackage *pkg = + (GetAccessibleHyperlinkPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleHyperlink((jobject)pkg->hypertext, pkg->linkIndex, + &(pkg->rAccessibleHyperlinkInfo)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleHyperlinkPackage)); + } + break; + + // ------------ end AccessibleHypertext packages + + // ------------ begin Accessible KeyBindings, Icons and Actions + + case cGetAccessibleKeyBindingsPackage: + PrintDebugString(" ##### type == cGetAccessibleKeyBindingsPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleKeyBindingsPackage))) { + GetAccessibleKeyBindingsPackage *pkg = + (GetAccessibleKeyBindingsPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleKeyBindings ( + (jobject)pkg->accessibleContext, &(pkg->rAccessibleKeyBindings)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleKeyBindingsPackage)); + } + break; + + case cGetAccessibleIconsPackage: + PrintDebugString(" ##### type == cGetAccessibleIconsPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleIconsPackage))) { + GetAccessibleIconsPackage *pkg = + (GetAccessibleIconsPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleIcons ( + (jobject)pkg->accessibleContext, &(pkg->rAccessibleIcons)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleIconsPackage)); + } + break; + + + case cGetAccessibleActionsPackage: + PrintDebugString(" ##### type == cGetAccessibleActionsPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleActionsPackage))) { + GetAccessibleActionsPackage *pkg = + (GetAccessibleActionsPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleActions ( + (jobject)pkg->accessibleContext, &(pkg->rAccessibleActions)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleActionsPackage)); + } + break; + + case cDoAccessibleActionsPackage: + PrintDebugString(" ##### type == cDoAccessibleActionsPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(DoAccessibleActionsPackage))) { + DoAccessibleActionsPackage *pkg = + (DoAccessibleActionsPackage *) (buffer + sizeof(PackageType)); + pkg->rResult = + windowsThreadEntryPoints->doAccessibleActions((jobject)pkg->accessibleContext, &(pkg->actionsToDo), + &(pkg->failure)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(DoAccessibleActionsPackage)); + } + break; + + // ------------ begin addtional methods for Teton + + case cGetVirtualAccessibleNamePackage: + PrintDebugString(" ##### type == GetVirtualAccessibleNamePackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetVirtualAccessibleNamePackage))) { + GetVirtualAccessibleNamePackage *pkg = + (GetVirtualAccessibleNamePackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getVirtualAccessibleName ((const jobject)pkg->accessibleContext, + pkg->rName, + pkg->len); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetVirtualAccessibleNamePackage)); + } + break; + + case cRequestFocusPackage: + PrintDebugString(" ##### type == RequestFocusPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(RequestFocusPackage))) { + RequestFocusPackage *pkg = + (RequestFocusPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->requestFocus ( + (jobject)pkg->accessibleContext); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(RequestFocusPackage)); + } + break; + + case cSelectTextRangePackage: + PrintDebugString(" ##### type == SelectTextRangePackage"); + if (bufsize == (sizeof(PackageType) + sizeof(SelectTextRangePackage))) { + SelectTextRangePackage *pkg = + (SelectTextRangePackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->selectTextRange ( + (jobject)pkg->accessibleContext, pkg->startIndex, pkg->endIndex); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(SelectTextRangePackage)); + } + break; + + case cGetTextAttributesInRangePackage: + PrintDebugString(" ##### type == GetTextAttributesInRangePackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetTextAttributesInRangePackage))) { + GetTextAttributesInRangePackage *pkg = + (GetTextAttributesInRangePackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getTextAttributesInRange ( + (jobject)pkg->accessibleContext, pkg->startIndex, pkg->endIndex, + (AccessibleTextAttributesInfo *)&(pkg->attributes), + &(pkg->rLength)); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetTextAttributesInRangePackage)); + } + break; + + + case cGetVisibleChildrenCountPackage: + PrintDebugString(" ##### type == GetVisibleChildrenCountPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetVisibleChildrenCountPackage))) { + GetVisibleChildrenCountPackage *pkg = + (GetVisibleChildrenCountPackage *) (buffer + sizeof(PackageType)); + pkg->rChildrenCount = windowsThreadEntryPoints->getVisibleChildrenCount ((jobject)pkg->accessibleContext); + + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetVisibleChildrenCountPackage)); + } + break; + + case cGetVisibleChildrenPackage: + PrintDebugString(" ##### type == GetVisibleChildrenPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetVisibleChildrenPackage))) { + GetVisibleChildrenPackage *pkg = + (GetVisibleChildrenPackage *) (buffer + sizeof(PackageType)); + pkg->rSuccess = windowsThreadEntryPoints->getVisibleChildren ((jobject)pkg->accessibleContext, + pkg->startIndex, + &(pkg->rVisibleChildrenInfo)); + + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetVisibleChildrenPackage)); + } + break; + + case cSetCaretPositionPackage: + PrintDebugString(" ##### type == SetCaretPositionPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(SetCaretPositionPackage))) { + SetCaretPositionPackage *pkg = + (SetCaretPositionPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->setCaretPosition ( + (jobject)pkg->accessibleContext, pkg->position); + PrintDebugString(" ##### processing succeeded"); + } else { + PrintDebugString(" ##### processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(SetCaretPositionPackage)); + } + break; + + // ------------ end additional methods for Teton + + // ------------ end Accessible KeyBindings, Icons and Actions + + // ------------ Accessible Text packages ------------------ + + case cGetAccessibleTextInfoPackage: + PrintDebugString(" type == cGetAccessibleTextInfoPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTextInfoPackage))) { + GetAccessibleTextInfoPackage *pkg = + (GetAccessibleTextInfoPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTextInfo((jobject)pkg->AccessibleContext, + &(pkg->rTextInfo), pkg->x, pkg->y); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTextInfoPackage)); + } + break; + + case cGetAccessibleTextItemsPackage: + PrintDebugString(" type == cGetAccessibleTextItemsPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTextItemsPackage))) { + GetAccessibleTextItemsPackage *pkg = + (GetAccessibleTextItemsPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTextItems((jobject)pkg->AccessibleContext, + &(pkg->rTextItemsInfo), pkg->index); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTextInfoPackage)); + } + break; + + case cGetAccessibleTextSelectionInfoPackage: + PrintDebugString(" type == cGetAccessibleTextSelectionInfoPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTextSelectionInfoPackage))) { + GetAccessibleTextSelectionInfoPackage *pkg = + (GetAccessibleTextSelectionInfoPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTextSelectionInfo( + (jobject)pkg->AccessibleContext, &(pkg->rTextSelectionItemsInfo)); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTextSelectionInfoPackage)); + } + break; + + case cGetAccessibleTextAttributeInfoPackage: + PrintDebugString(" type == cGetAccessibleTextAttributeInfoPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTextAttributeInfoPackage))) { + GetAccessibleTextAttributeInfoPackage *pkg = + (GetAccessibleTextAttributeInfoPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTextAttributes( + (jobject)pkg->AccessibleContext, pkg->index, (AccessibleTextAttributesInfo *) &(pkg->rAttributeInfo)); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTextAttributeInfoPackage)); + } + break; + + case cGetAccessibleTextRectInfoPackage: + PrintDebugString(" type == cGetAccessibleTextRectInfoPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTextRectInfoPackage))) { + GetAccessibleTextRectInfoPackage *pkg = + (GetAccessibleTextRectInfoPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTextRect((jobject)pkg->AccessibleContext, + &(pkg->rTextRectInfo), pkg->index); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTextRectInfoPackage)); + } + break; + + case cGetCaretLocationPackage: + PrintDebugString(" type == cGetCaretLocationPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetCaretLocationPackage))) { + GetCaretLocationPackage *pkg = + (GetCaretLocationPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getCaretLocation((jobject)pkg->AccessibleContext, + &(pkg->rTextRectInfo), pkg->index); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetCaretLocationPackage)); + } + break; + + case cGetAccessibleTextLineBoundsPackage: + PrintDebugString(" type == cGetAccessibleTextLineBoundsPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTextLineBoundsPackage))) { + GetAccessibleTextLineBoundsPackage *pkg = + (GetAccessibleTextLineBoundsPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTextLineBounds((jobject)pkg->AccessibleContext, + pkg->index, &(pkg->rLineStart), &(pkg->rLineEnd)); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTextLineBoundsPackage)); + } + break; + + case cGetAccessibleTextRangePackage: + PrintDebugString(" type == cGetAccessibleTextRangePackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleTextRangePackage))) { + GetAccessibleTextRangePackage *pkg = + (GetAccessibleTextRangePackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getAccessibleTextRange((jobject)pkg->AccessibleContext, + pkg->start, pkg->end, (wchar_t *) &(pkg->rText), (sizeof(pkg->rText) / sizeof(wchar_t))); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleTextRangePackage)); + } + break; + + + // ------------ Accessible Value packages ------------------ + + case cGetCurrentAccessibleValueFromContextPackage: + PrintDebugString(" type == cGetCurrentAccessibleValueFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetCurrentAccessibleValueFromContextPackage))) { + GetCurrentAccessibleValueFromContextPackage *pkg = + (GetCurrentAccessibleValueFromContextPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getCurrentAccessibleValueFromContext((jobject)pkg->AccessibleContext, + (wchar_t *) &(pkg->rValue), (sizeof(pkg->rValue) / sizeof(wchar_t))); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetCurrentAccessibleValueFromContextPackage)); + } + break; + + case cGetMaximumAccessibleValueFromContextPackage: + PrintDebugString(" type == cGetMaximumAccessibleValueFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetMaximumAccessibleValueFromContextPackage))) { + GetMaximumAccessibleValueFromContextPackage *pkg = + (GetMaximumAccessibleValueFromContextPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getMaximumAccessibleValueFromContext((jobject)pkg->AccessibleContext, + (wchar_t *) &(pkg->rValue), (sizeof(pkg->rValue) / sizeof(wchar_t))); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetMaximumAccessibleValueFromContextPackage)); + } + break; + + case cGetMinimumAccessibleValueFromContextPackage: + PrintDebugString(" type == cGetMinimumAccessibleValueFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetMinimumAccessibleValueFromContextPackage))) { + GetMinimumAccessibleValueFromContextPackage *pkg = + (GetMinimumAccessibleValueFromContextPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->getMinimumAccessibleValueFromContext((jobject)pkg->AccessibleContext, + (wchar_t *) &(pkg->rValue), (sizeof(pkg->rValue) / sizeof(wchar_t))); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetMinimumAccessibleValueFromContextPackage)); + } + break; + + // ------------ Accessible Selection packages ------------------ + + case cAddAccessibleSelectionFromContextPackage: + PrintDebugString(" type == cAddAccessibleSelectionFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(AddAccessibleSelectionFromContextPackage))) { + AddAccessibleSelectionFromContextPackage *pkg = + (AddAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->addAccessibleSelectionFromContext((jobject)pkg->AccessibleContext, + pkg->index); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(AddAccessibleSelectionFromContextPackage)); + } + break; + + case cClearAccessibleSelectionFromContextPackage: + PrintDebugString(" type == cClearAccessibleSelectionFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(ClearAccessibleSelectionFromContextPackage))) { + ClearAccessibleSelectionFromContextPackage *pkg = + (ClearAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->clearAccessibleSelectionFromContext((jobject)pkg->AccessibleContext); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(ClearAccessibleSelectionFromContextPackage)); + } + break; + + case cGetAccessibleSelectionFromContextPackage: + PrintDebugString(" type == cGetAccessibleSelectionFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleSelectionFromContextPackage))) { + GetAccessibleSelectionFromContextPackage *pkg = + (GetAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + pkg->rAccessibleContext = (JOBJECT64)windowsThreadEntryPoints->getAccessibleSelectionFromContext( + (jobject)pkg->AccessibleContext, pkg->index); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleSelectionFromContextPackage)); + } + break; + + case cGetAccessibleSelectionCountFromContextPackage: + PrintDebugString(" type == cGetAccessibleSelectionCountFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(GetAccessibleSelectionCountFromContextPackage))) { + GetAccessibleSelectionCountFromContextPackage *pkg = + (GetAccessibleSelectionCountFromContextPackage *) (buffer + sizeof(PackageType)); + pkg->rCount = windowsThreadEntryPoints->getAccessibleSelectionCountFromContext( + (jobject)pkg->AccessibleContext); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(GetAccessibleSelectionCountFromContextPackage)); + } + break; + + case cIsAccessibleChildSelectedFromContextPackage: + PrintDebugString(" type == cIsAccessibleChildSelectedFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(IsAccessibleChildSelectedFromContextPackage))) { + IsAccessibleChildSelectedFromContextPackage *pkg = + (IsAccessibleChildSelectedFromContextPackage *) (buffer + sizeof(PackageType)); + pkg->rResult = windowsThreadEntryPoints->isAccessibleChildSelectedFromContext( + (jobject)pkg->AccessibleContext, pkg->index); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(IsAccessibleChildSelectedFromContextPackage)); + } + break; + + case cRemoveAccessibleSelectionFromContextPackage: + PrintDebugString(" type == cRemoveAccessibleSelectionFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(RemoveAccessibleSelectionFromContextPackage))) { + RemoveAccessibleSelectionFromContextPackage *pkg = + (RemoveAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->removeAccessibleSelectionFromContext((jobject)pkg->AccessibleContext, + pkg->index); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(RemoveAccessibleSelectionFromContextPackage)); + } + break; + + case cSelectAllAccessibleSelectionFromContextPackage: + PrintDebugString(" type == cSelectAllAccessibleSelectionFromContextPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(SelectAllAccessibleSelectionFromContextPackage))) { + SelectAllAccessibleSelectionFromContextPackage *pkg = + (SelectAllAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + windowsThreadEntryPoints->selectAllAccessibleSelectionFromContext((jobject)pkg->AccessibleContext); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(SelectAllAccessibleSelectionFromContextPackage)); + } + break; + + + // ------------ event notification management packages ------------------ + + case cAddJavaEventNotificationPackage: + PrintDebugString(" type = cAddJavaEventNotificationPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(AddJavaEventNotificationPackage))) { + AddJavaEventNotificationPackage *pkg = + (AddJavaEventNotificationPackage *) (buffer + sizeof(PackageType)); + addJavaEventNotification(pkg->type, (HWND)ABLongToHandle( pkg->DLLwindow ) ); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(AddJavaEventNotificationPackage)); + } + break; + + case cRemoveJavaEventNotificationPackage: + PrintDebugString(" type = cRemoveJavaEventNotificationPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(RemoveJavaEventNotificationPackage))) { + RemoveJavaEventNotificationPackage *pkg = + (RemoveJavaEventNotificationPackage *) (buffer + sizeof(PackageType)); + removeJavaEventNotification(pkg->type, (HWND)ABLongToHandle( pkg->DLLwindow )); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(RemoveJavaEventNotificationPackage)); + } + break; + + case cAddAccessibilityEventNotificationPackage: + PrintDebugString(" type = cAddAccessibilityEventNotificationPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(AddAccessibilityEventNotificationPackage))) { + AddAccessibilityEventNotificationPackage *pkg = + (AddAccessibilityEventNotificationPackage *) (buffer + sizeof(PackageType)); + addAccessibilityEventNotification(pkg->type, (HWND)ABLongToHandle(pkg->DLLwindow)); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(AddAccessibilityEventNotificationPackage)); + } + break; + + case cRemoveAccessibilityEventNotificationPackage: + PrintDebugString(" type = cRemoveAccessibilityEventNotificationPackage"); + if (bufsize == (sizeof(PackageType) + sizeof(RemoveAccessibilityEventNotificationPackage))) { + RemoveAccessibilityEventNotificationPackage *pkg = + (RemoveAccessibilityEventNotificationPackage *) (buffer + sizeof(PackageType)); + removeAccessibilityEventNotification(pkg->type, (HWND)ABLongToHandle(pkg->DLLwindow)); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(RemoveAccessibilityEventNotificationPackage)); + } + break; + + default: + PrintDebugString(" processing FAILED!! -> don't know how to handle type = %X", *type); + returnVal = -1; + break; + } + + PrintDebugString(" package processing completed"); + return returnVal; +} + + +// ----------------------------- + + +/** + * MemoryMappedFileCreated + * - WindowsDLL letting us know it's created a memory-mapped file + * for IPC. We need to open it and write a magic string into + * it to let the WindowsDLL know all is OK. Also we need to + * set up our own data structures to communicate with the + * WindowsDLL + * + */ +LRESULT +JavaAccessBridge::MemoryMappedFileCreated(HWND ATBridgeDLLWindow, char *filename) { + PrintDebugString(" in MemoryMappedFileCreated(%p, %s)!", ATBridgeDLLWindow, filename); + AccessBridgeATInstance *newAT = + new AccessBridgeATInstance(dialogWindow, ATBridgeDLLWindow, filename, ATs); + PrintDebugString(" just created a new ATInstance = %p, old = %p", newAT, ATs); + ATs = newAT; + + LRESULT returnVal = ATs->initiateIPC(); + if (returnVal == 0) { + PrintDebugString(" Successfully initiated IPC with AT!!!"); + } else { + PrintDebugString(" ERROR: Failed to initiate IPC with AT!!!"); + } + + return returnVal; +} + + +/** + * WindowsATDestroyed - lets the JavaABDLL know a Windows AT disappeared + * + */ +void +JavaAccessBridge::WindowsATDestroyed(HWND ATBridgeDLLWindow) { + PrintDebugString("\r\nin JavaAccessBridge::WindowsATDestroyed(%p)", ATBridgeDLLWindow); + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! -> ATs == 0! (shouldn't happen here)"); + return; + } + + AccessBridgeATInstance *currentAT = ATs; + AccessBridgeATInstance *previousAT = ATs; + if (ATs->winAccessBridgeWindow == ATBridgeDLLWindow) { + ATs = ATs->nextATInstance; + // remove event notification for this AT + removeJavaEventNotification(currentAT->javaEventMask, ATBridgeDLLWindow); + removeAccessibilityEventNotification(currentAT->accessibilityEventMask, ATBridgeDLLWindow); + delete currentAT; + PrintDebugString(" data structures successfully removed"); + } else { + while (currentAT != (AccessBridgeATInstance *) NULL) { + if (currentAT->winAccessBridgeWindow == ATBridgeDLLWindow) { + previousAT->nextATInstance = currentAT->nextATInstance; + delete currentAT; + PrintDebugString(" data structures successfully removed"); + return; + } else { + previousAT = currentAT; + currentAT = currentAT->nextATInstance; + } + } + PrintDebugString(" ERROR!! couldn't find matching data structures!"); + } +} + + +// ----------------------------- + + +/** + * releaseJavaObject - lets the JavaVM know it can release the Java Object + * + * Note: once you have made this call, the JavaVM will garbage collect + * the jobject you pass in. If you later use that jobject in another + * call, you will cause all maner of havoc! + * + */ +void +JavaAccessBridge::releaseJavaObject(jobject object) { + PrintDebugString("In JavaAccessBridge::releaseJavaObject"); + PrintDebugString(" object X: %p", object); + if (windowsThreadJNIEnv != (JNIEnv *) 0) { + windowsThreadJNIEnv->DeleteGlobalRef(object); + PrintDebugString(" global reference deleted.", object); + } else { + PrintDebugString(" Error! windowsThreadJNIEnv == 0"); + } +} + +// ----------------------------- + +/** + * addJavaEventNotification - this AT now wants this type of events + * + */ +void +JavaAccessBridge::addJavaEventNotification(jlong type, HWND DLLwindow) { + // walk through list of ATs, find this one and add this type + // and, if we weren't listening for these before, ask Java for 'em + PrintDebugString(" adding Java event type %016I64X to HWND %p", type, DLLwindow); + AccessBridgeATInstance *ati = ATs; + long globalEventMask = 0; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->winAccessBridgeWindow == DLLwindow) { + ati->javaEventMask |= type; + PrintDebugString(" found HWND, javaEventMask now is %X", ati->javaEventMask); + } else { + globalEventMask |= ati->javaEventMask; + } + ati = ati->nextATInstance; + } + PrintDebugString(" union of all Java AT event masks: %X", globalEventMask); + if (!(globalEventMask & type)) { + // no other ATs wanted this event; + // start getting them from Java + PrintDebugString(" no other AT wanted this Java event (so not registered); adding to AccessBridge.java"); + windowsThreadEntryPoints->addJavaEventNotification(type); + } +} + +/** + * removeJavaEventNotification - this AT no longer wants this type of events + * + */ +void +JavaAccessBridge::removeJavaEventNotification(jlong type, HWND DLLwindow) { + // walk through list of ATs, find this one and remove this type + // and, if no other AT wants 'em either, tell Java we no longer want 'em + PrintDebugString(" removing Java event type %016I64X from HWND %p", type, DLLwindow); + AccessBridgeATInstance *ati = ATs; + long globalEventMask = 0; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->winAccessBridgeWindow == DLLwindow) { + ati->javaEventMask &= (0xFFFFFFFF - type); + PrintDebugString(" found HWND, javaEventMask now is %X", ati->javaEventMask); + } else { + globalEventMask |= ati->javaEventMask; + } + ati = ati->nextATInstance; + } + PrintDebugString(" union of all Java AT event masks: %X", globalEventMask); + if (!(globalEventMask & type)) { + // no other ATs wanted this event; + // stop getting them from Java + PrintDebugString(" no other AT wanted this Java event (so can remove); removing from AccessBridge.java"); + windowsThreadEntryPoints->removeJavaEventNotification(type); + } +} + + +/** + * addAccesibilityEventNotification - this AT now wants this type of events + * + */ +void +JavaAccessBridge::addAccessibilityEventNotification(jlong type, HWND DLLwindow) { + // walk through list of ATs, find this one and add this type + // and, if we weren't listening for these before, ask Java for 'em + PrintDebugString(" adding Accesibility event type %016I64X to HWND %p", type, DLLwindow); + AccessBridgeATInstance *ati = ATs; + long globalEventMask = 0; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->winAccessBridgeWindow == DLLwindow) { + ati->accessibilityEventMask |= type; + PrintDebugString(" found HWND, accessibilityEventMask now is %X", ati->accessibilityEventMask); + } else { + globalEventMask |= ati->accessibilityEventMask; + } + ati = ati->nextATInstance; + } + PrintDebugString(" union of all Accessibility AT event masks: %X", globalEventMask); + if (!(globalEventMask & type)) { + // no other ATs wanted this event; + // start getting them from Java + PrintDebugString(" no other AT wanted this Accesibility event (so not registered); adding to AccessBridge.java"); + windowsThreadEntryPoints->addAccessibilityEventNotification(type); + } +} + +/** + * removeAccesibilityEventNotification - this AT no longer wants this type of events + * + */ +void +JavaAccessBridge::removeAccessibilityEventNotification(jlong type, HWND DLLwindow) { + // walk through list of ATs, find this one and remove this type + // and, if no other AT wants 'em either, tell Java we no longer want 'em + PrintDebugString(" removing Accesibility event type %016I64X from HWND %p", type, DLLwindow); + AccessBridgeATInstance *ati = ATs; + long globalEventMask = 0; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->winAccessBridgeWindow == DLLwindow) { + ati->accessibilityEventMask &= (0xFFFFFFFF - type); + PrintDebugString(" found HWND, accessibilityEventMask now is %X", ati->accessibilityEventMask); + } else { + globalEventMask |= ati->accessibilityEventMask; + } + ati = ati->nextATInstance; + } + PrintDebugString(" union of all Accessibility AT event masks: %X", globalEventMask); + if (!(globalEventMask & type)) { + // no other ATs wanted this event; + // stop getting them from Java + PrintDebugString(" no other AT wanted this Accessibility event (so can remove); removing from AccessBridge.java"); + windowsThreadEntryPoints->removeAccessibilityEventNotification(type); + } +} + + + + +/** + * firePropertyCaretChange + * + */ +void +JavaAccessBridge::firePropertyCaretChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jint oldValue, jint newValue) { + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyCaretChanged(%p, %p, %p, %p, %d, %d)", + env, callingObj, event, + source, oldValue, newValue); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + char buffer[sizeof(PackageType) + sizeof(PropertyCaretChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyCaretChangePackage *pkg = (PropertyCaretChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyCaretChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyCaretChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + + pkg->oldPosition = oldValue; + pkg->newPosition = newValue; + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyCaretChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyCaretChange event"); +} + +/** + * firePropertyDescriptionChange + * + */ +void +JavaAccessBridge::firePropertyDescriptionChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue){ + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyDescriptionChanged(%p, %p, %p, %p, %p, %p)", + env, callingObj, event, + source, oldValue, newValue); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + const wchar_t *stringBytes; + char buffer[sizeof(PackageType) + sizeof(PropertyDescriptionChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyDescriptionChangePackage *pkg = (PropertyDescriptionChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyDescriptionChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyCaretChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + + if (oldValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(oldValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->oldDescription, stringBytes, (sizeof(pkg->oldDescription) / sizeof(wchar_t))); + env->ReleaseStringChars(oldValue, stringBytes); + } else { + wcsncpy(pkg->oldDescription, L"(null)", (sizeof(pkg->oldDescription) / sizeof(wchar_t))); + } + + if (newValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(newValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->newDescription, stringBytes, (sizeof(pkg->newDescription) / sizeof(wchar_t))); + env->ReleaseStringChars(newValue, stringBytes); + } else { + wcsncpy(pkg->newDescription, L"(null)", (sizeof(pkg->newDescription) / sizeof(wchar_t))); + } + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyDescriptionChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyDescriptionChange event"); +} + +/** + * firePropertyNameChange + * + */ +void +JavaAccessBridge::firePropertyNameChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue){ + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyNameChanged(%p, %p, %p, %p, %p, %p)", + env, callingObj, event, + source, oldValue, newValue); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + const wchar_t *stringBytes; + char buffer[sizeof(PackageType) + sizeof(PropertyNameChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyNameChangePackage *pkg = (PropertyNameChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyNameChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyNameChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + + if (oldValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(oldValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->oldName, stringBytes, (sizeof(pkg->oldName) / sizeof(wchar_t))); + env->ReleaseStringChars(oldValue, stringBytes); + } else { + wcsncpy(pkg->oldName, L"(null)", (sizeof(pkg->oldName) / sizeof(wchar_t))); + } + + if (newValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(newValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->newName, stringBytes, (sizeof(pkg->newName) / sizeof(wchar_t))); + env->ReleaseStringChars(newValue, stringBytes); + } else { + wcsncpy(pkg->newName, L"(null)", (sizeof(pkg->newName) / sizeof(wchar_t))); + } + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyNameChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyNameChange event"); +} + + +/** + * firePropertySelectionChange + * + */ +void +JavaAccessBridge::firePropertySelectionChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source) { + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertySelectionChanged(%p, %p, %p, %p)", + env, callingObj, event, source); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + char buffer[sizeof(PackageType) + sizeof(PropertySelectionChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertySelectionChangePackage *pkg = (PropertySelectionChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertySelectionChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertySelectionChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertySelectionChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertySelectionChange event"); +} + + +/** + * firePropertyStateChange + * + */ +void +JavaAccessBridge::firePropertyStateChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue){ + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyStateChanged(%p, %p, %p, %p, %p, %p)", + env, callingObj, event, + source, oldValue, newValue); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + const wchar_t *stringBytes; + char buffer[sizeof(PackageType) + sizeof(PropertyStateChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyStateChangePackage *pkg = (PropertyStateChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyStateChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyStateChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + + if (oldValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(oldValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->oldState, stringBytes, (sizeof(pkg->oldState) / sizeof(wchar_t))); + env->ReleaseStringChars(oldValue, stringBytes); + } else { + wcsncpy(pkg->oldState, L"(null)", (sizeof(pkg->oldState) / sizeof(wchar_t))); + } + + if (newValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(newValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->newState, stringBytes, (sizeof(pkg->newState) / sizeof(wchar_t))); + env->ReleaseStringChars(newValue, stringBytes); + } else { + wcsncpy(pkg->newState, L"(null)", (sizeof(pkg->newState) / sizeof(wchar_t))); + } + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyStateChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyStateChange event"); +} + + +/** + * firePropertyTextChange + * + */ +void +JavaAccessBridge::firePropertyTextChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source) { + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyTextChanged(%p, %p, %p, %p)", + env, callingObj, event, source); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + char buffer[sizeof(PackageType) + sizeof(PropertyTextChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyTextChangePackage *pkg = (PropertyTextChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyTextChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyTextChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyTextChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyTextChange event"); +} + + +/** + * firePropertyValueChange + * + */ +void +JavaAccessBridge::firePropertyValueChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue){ + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyValueChanged(%p, %p, %p, %p, %p, %p)", + env, callingObj, event, + source, oldValue, newValue); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + const wchar_t *stringBytes; + char buffer[sizeof(PackageType) + sizeof(PropertyValueChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyValueChangePackage *pkg = (PropertyValueChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyValueChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyValueChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + + if (oldValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(oldValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->oldValue, stringBytes, (sizeof(pkg->oldValue) / sizeof(wchar_t))); + env->ReleaseStringChars(oldValue, stringBytes); + } else { + wcsncpy(pkg->oldValue, L"(null)", (sizeof(pkg->oldValue) / sizeof(wchar_t))); + } + + if (newValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(newValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->newValue, stringBytes, (sizeof(pkg->newValue) / sizeof(wchar_t))); + env->ReleaseStringChars(newValue, stringBytes); + } else { + wcsncpy(pkg->newValue, L"(null)", (sizeof(pkg->newValue) / sizeof(wchar_t))); + } + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyValueChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyValueChange event"); +} + +/** + * firePropertyVisibleDataChange + * + */ +void +JavaAccessBridge::firePropertyVisibleDataChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source) { + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyVisibleDataChanged(%p, %p, %p, %p)", + env, callingObj, event, source); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + char buffer[sizeof(PackageType) + sizeof(PropertyVisibleDataChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyVisibleDataChangePackage *pkg = (PropertyVisibleDataChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyVisibleDataChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyVisibleDataChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyVisibleDataChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyVisibleDataChange event"); +} + + +/** + * firePropertyChildChange + * + */ +void +JavaAccessBridge::firePropertyChildChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jobject oldValue, jobject newValue){ + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyChildPropertyChanged(%p, %p, %p, %p, %p, %p)", + env, callingObj, event, + source, oldValue, newValue); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + char buffer[sizeof(PackageType) + sizeof(PropertyChildChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyChildChangePackage *pkg = (PropertyChildChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyChildChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyChildChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); + pkg->oldChildAccessibleContext = (JOBJECT64)env->NewGlobalRef(oldValue); + pkg->newChildAccessibleContext = (JOBJECT64)env->NewGlobalRef(newValue); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); + PrintDebugString(" GlobalRef'd OldChildAC: %p", pkg->oldChildAccessibleContext); + PrintDebugString(" GlobalRef'd NewChildAC: %p", pkg->newChildAccessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); + PrintDebugString(" GlobalRef'd OldChildAC: %016I64X", pkg->oldChildAccessibleContext); + PrintDebugString(" GlobalRef'd NewChildAC: %016I64X", pkg->newChildAccessibleContext); +#endif + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyChildChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyChildChange event"); +} + + +/** + * firePropertyActiveDescendentChange + * + */ +void +JavaAccessBridge::firePropertyActiveDescendentChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jobject oldValue, jobject newValue){ + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyActiveDescendentPropertyChanged(%p, %p, %p, %p, %p, %p)", + env, callingObj, event, + source, oldValue, newValue); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + char buffer[sizeof(PackageType) + sizeof(PropertyActiveDescendentChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyActiveDescendentChangePackage *pkg = (PropertyActiveDescendentChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyActiveDescendentChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyActiveDescendentChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); + pkg->oldActiveDescendentAccessibleContext = (JOBJECT64)env->NewGlobalRef(oldValue); + pkg->newActiveDescendentAccessibleContext = (JOBJECT64)env->NewGlobalRef(newValue); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); + PrintDebugString(" GlobalRef'd OldActiveDescendentAC: %p", pkg->oldActiveDescendentAccessibleContext); + PrintDebugString(" GlobalRef'd NewActiveDescendentAC: %p", pkg->newActiveDescendentAccessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); + PrintDebugString(" GlobalRef'd OldActiveDescendentAC: %016I64X", pkg->oldActiveDescendentAccessibleContext); + PrintDebugString(" GlobalRef'd NewActiveDescendentAC: %016I64X", pkg->newActiveDescendentAccessibleContext); +#endif + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyActiveDescendentChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyActiveChange event"); +} + +/** + * firePropertyValueChange + * + */ +void +JavaAccessBridge::firePropertyTableModelChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue){ + + PrintDebugString("\r\nJava_com_sun_java_accessibility_AccessBridge_propertyTableModelChange(%p, %p, %p, %p, %p, %p)", + env, callingObj, event, + source, oldValue, newValue); + + // sanity check + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; // panic! + } + + // common setup + const wchar_t *stringBytes; + char buffer[sizeof(PackageType) + sizeof(PropertyTableModelChangePackage)]; + PackageType *type = (PackageType *) buffer; + PropertyTableModelChangePackage *pkg = (PropertyTableModelChangePackage *) (buffer + sizeof(PackageType)); + *type = cPropertyTableModelChangePackage; + pkg->vmID = (long) dialogWindow; + + // make new Global Refs and send events only to those ATs that want 'em + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->accessibilityEventMask & cPropertyTableModelChangeEvent) { + + PrintDebugString(" sending to AT"); + + // make new GlobalRefs for this AT + pkg->Event = (JOBJECT64)env->NewGlobalRef(event); + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + + if (oldValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(oldValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->oldValue, stringBytes, (sizeof(pkg->oldValue) / sizeof(wchar_t))); + env->ReleaseStringChars(oldValue, stringBytes); + } else { + wcsncpy(pkg->oldValue, L"(null)", (sizeof(pkg->oldValue) / sizeof(wchar_t))); + } + + if (newValue != (jstring) 0) { + stringBytes = (const wchar_t *) env->GetStringChars(newValue, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wcsncpy(pkg->newValue, stringBytes, (sizeof(pkg->newValue) / sizeof(wchar_t))); + env->ReleaseStringChars(newValue, stringBytes); + } else { + wcsncpy(pkg->newValue, L"(null)", (sizeof(pkg->newValue) / sizeof(wchar_t))); + } + + ati->sendAccessibilityEventPackage(buffer, sizeof(buffer), cPropertyTableModelChangeEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with propertyTableModelChange event"); +} + + + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) +#define PRINT_GLOBALREFS() \ + PrintDebugString(" GlobalRef'd Event: %p", pkg->Event); \ + PrintDebugString(" GlobalRef'd Source: %p", pkg->AccessibleContextSource); +#else // JOBJECT64 is jlong (64 bit) +#define PRINT_GLOBALREFS() \ + PrintDebugString(" GlobalRef'd Event: %016I64X", pkg->Event); \ + PrintDebugString(" GlobalRef'd Source: %016I64X", pkg->AccessibleContextSource); +#endif + +#define FIRE_EVENT(function, packageStruct, packageConstant, eventConstant) \ + void JavaAccessBridge::function(JNIEnv *env, jobject callingObj, \ + jobject eventObj, jobject source) { \ + \ + PrintDebugString("\r\nFiring event id = %d(%p, %p, %p, %p); vmID = %X", \ + eventConstant, env, callingObj, eventObj, source, javaVM); \ + \ + /* sanity check */ \ + if (ATs == (AccessBridgeATInstance *) 0) { \ + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); \ + return; /* panic! */ \ + } \ + \ + /* common setup */ \ + char buffer[sizeof(PackageType) + sizeof(packageStruct)]; \ + PackageType *type = (PackageType *) buffer; \ + packageStruct *pkg = (packageStruct *) (buffer + sizeof(PackageType)); \ + *type = packageConstant; \ + pkg->vmID = (long) dialogWindow; \ + \ + /* make new Global Refs, send events only to those ATs that want 'em */ \ + AccessBridgeATInstance *ati = ATs; \ + while (ati != (AccessBridgeATInstance *) 0) { \ + PrintDebugString("\r\njavaEventMask = %X eventConstant=%d pkg->vmID=%X", \ + ati->javaEventMask, eventConstant, pkg->vmID ); \ + if (ati->javaEventMask & eventConstant) { \ + \ + PrintDebugString(" sending to AT"); \ + /* make new GlobalRefs for this AT */ \ + pkg->Event = (JOBJECT64)env->NewGlobalRef(eventObj); \ + pkg->AccessibleContextSource = (JOBJECT64)env->NewGlobalRef(source); \ + PRINT_GLOBALREFS() \ + \ + ati->sendJavaEventPackage(buffer, sizeof(buffer), eventConstant); \ + } \ + ati = ati->nextATInstance; \ + } \ + PrintDebugString(" done with firing AWT event"); \ + } + + void JavaAccessBridge::javaShutdown(JNIEnv *env, jobject callingObj) { + + PrintDebugString("\r\nFiring event id = %d(%p, %p); vmID = %X", + cJavaShutdownEvent, env, callingObj, javaVM); + + /* sanity check */ + if (ATs == (AccessBridgeATInstance *) 0) { + PrintDebugString(" ERROR!! ATs == 0! (shouldn't happen here!)"); + return; /* panic! */ + } + + /* common setup */ + char buffer[sizeof(PackageType) + sizeof(JavaShutdownPackage)]; + PackageType *type = (PackageType *) buffer; + JavaShutdownPackage *pkg = (JavaShutdownPackage *) (buffer + sizeof(PackageType)); + *type = cJavaShutdownPackage; + pkg->vmID = (long) dialogWindow; + + /* make new Global Refs, send events only to those ATs that want 'em */ + AccessBridgeATInstance *ati = ATs; + while (ati != (AccessBridgeATInstance *) 0) { + if (ati->javaEventMask & cJavaShutdownEvent) { + PrintDebugString(" sending to AT"); + ati->sendJavaEventPackage(buffer, sizeof(buffer), cJavaShutdownEvent); + } + ati = ati->nextATInstance; + } + PrintDebugString(" done with firing AWT event"); + } + + FIRE_EVENT(fireFocusGained, FocusGainedPackage, cFocusGainedPackage, cFocusGainedEvent) + FIRE_EVENT(fireFocusLost, FocusLostPackage, cFocusLostPackage, cFocusLostEvent) + FIRE_EVENT(fireCaretUpdate, CaretUpdatePackage, cCaretUpdatePackage, cCaretUpdateEvent) + FIRE_EVENT(fireMouseClicked, MouseClickedPackage, cMouseClickedPackage, cMouseClickedEvent) + FIRE_EVENT(fireMouseEntered, MouseEnteredPackage, cMouseEnteredPackage, cMouseEnteredEvent) + FIRE_EVENT(fireMouseExited, MouseExitedPackage, cMouseExitedPackage, cMouseExitedEvent) + FIRE_EVENT(fireMousePressed, MousePressedPackage, cMousePressedPackage, cMousePressedEvent) + FIRE_EVENT(fireMouseReleased, MouseReleasedPackage, cMouseReleasedPackage, cMouseReleasedEvent) + FIRE_EVENT(fireMenuCanceled, MenuCanceledPackage, cMenuCanceledPackage, cMenuCanceledEvent) + FIRE_EVENT(fireMenuDeselected, MenuDeselectedPackage, cMenuDeselectedPackage, cMenuDeselectedEvent) + FIRE_EVENT(fireMenuSelected, MenuSelectedPackage, cMenuSelectedPackage, cMenuSelectedEvent) + FIRE_EVENT(firePopupMenuCanceled, PopupMenuCanceledPackage, cPopupMenuCanceledPackage, cPopupMenuCanceledEvent) + FIRE_EVENT(firePopupMenuWillBecomeInvisible, PopupMenuWillBecomeInvisiblePackage, cPopupMenuWillBecomeInvisiblePackage, cPopupMenuWillBecomeInvisibleEvent) + FIRE_EVENT(firePopupMenuWillBecomeVisible, PopupMenuWillBecomeVisiblePackage, cPopupMenuWillBecomeVisiblePackage, cPopupMenuWillBecomeVisibleEvent) + + + // ----------------------------- + + +extern "C" { // event stuff from AccessBridge.h, generated by JNI + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_sendDebugString(JNIEnv *env, jobject callingObj, jstring debugStr) { + + const wchar_t *stringBytes; + stringBytes = (const wchar_t *) env->GetStringChars(debugStr, 0); + if (stringBytes == NULL) { + if (!env->ExceptionCheck()) { + jclass cls = env->FindClass("java/lang/OutOfMemoryError"); + if (cls != NULL) { + env->ThrowNew(cls, NULL); + } + } + return; + } + wPrintJavaDebugString(L"AccessBridge.java: %ls", stringBytes); + env->ReleaseStringChars(debugStr, stringBytes); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyCaretChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jint oldValue, jint newValue) { + theJavaAccessBridge->firePropertyCaretChange(env, callingObj, + event, source, + oldValue, newValue); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyDescriptionChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue) { + theJavaAccessBridge->firePropertyDescriptionChange(env, callingObj, + event, source, + oldValue, newValue); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyNameChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue) { + theJavaAccessBridge->firePropertyNameChange(env, callingObj, + event, source, + oldValue, newValue); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertySelectionChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source) { + theJavaAccessBridge->firePropertySelectionChange(env, callingObj, + event, source); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyStateChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue) { + theJavaAccessBridge->firePropertyStateChange(env, callingObj, + event, source, + oldValue, newValue); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyTextChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source) { + theJavaAccessBridge->firePropertyTextChange(env, callingObj, + event, source); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyValueChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue) { + theJavaAccessBridge->firePropertyValueChange(env, callingObj, + event, source, + oldValue, newValue); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyVisibleDataChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source) { + theJavaAccessBridge->firePropertyVisibleDataChange(env, callingObj, + event, source); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyChildChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jobject oldValue, jobject newValue) { + theJavaAccessBridge->firePropertyChildChange(env, callingObj, + event, source, + oldValue, newValue); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyActiveDescendentChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jobject oldValue, + jobject newValue) { + theJavaAccessBridge->firePropertyActiveDescendentChange(env, callingObj, + event, source, + oldValue, newValue); + } + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_propertyTableModelChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue) { + + theJavaAccessBridge->firePropertyTableModelChange(env, callingObj, + event, source, + oldValue, newValue); + } + +#define HANDLE_STANDARD_EVENT_FROM_JAVA(function, method) \ + JNIEXPORT void JNICALL \ + function(JNIEnv *env, jobject callingObj, jobject event, jobject source) { \ + theJavaAccessBridge->method(env, callingObj, event, source); \ + } + + + JNIEXPORT void JNICALL + Java_com_sun_java_accessibility_AccessBridge_javaShutdown(JNIEnv *env, jobject callingObj) { + theJavaAccessBridge->javaShutdown(env, callingObj); + } + + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_focusGained, fireFocusGained) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_focusLost, fireFocusLost) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_caretUpdate, fireCaretUpdate) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_mouseClicked, fireMouseClicked) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_mouseEntered, fireMouseEntered) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_mouseExited, fireMouseExited) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_mousePressed, fireMousePressed) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_mouseReleased, fireMouseReleased) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_menuCanceled, fireMenuCanceled) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_menuDeselected, fireMenuDeselected) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_menuSelected, fireMenuSelected) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_popupMenuCanceled, firePopupMenuCanceled) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_popupMenuWillBecomeInvisible, firePopupMenuWillBecomeInvisible) + HANDLE_STANDARD_EVENT_FROM_JAVA(Java_com_sun_java_accessibility_AccessBridge_popupMenuWillBecomeVisible, firePopupMenuWillBecomeVisible) + + /* + * Map a HWND to a Java component + * + * Class: com_sun_java_accessibility_AccessBridge + * Method: jawtGetComponentFromNativeWindowHandle + * Signature: (I)Ljava/awt/Component; + */ + JNIEXPORT jobject JNICALL + Java_com_sun_java_accessibility_AccessBridge_jawtGetComponentFromNativeWindowHandle + (JNIEnv *env, jobject callingObj, jint windowHandle) { + + JAWT awt; + jboolean result; + jobject component = (jobject)0; + + // Get the AWT + awt.version = JAWT_VERSION_1_4; + result = JAWT_GetAWT(env, &awt); + if (result == JNI_FALSE) { + return (jobject)0; + } + + // Get the component + return awt.GetComponent(env, (void *)windowHandle); + } + + + /* + * Map a Java component to a HWND + * + * Class: com_sun_java_accessibility_AccessBridge + * Method: jawtGetNativeWindowHandleFromComponent + * Signature: (Ljava/awt/Component;)I + */ + JNIEXPORT jint JNICALL + Java_com_sun_java_accessibility_AccessBridge_jawtGetNativeWindowHandleFromComponent + (JNIEnv *env, jobject callingObj, jobject component) { + + JAWT awt; + JAWT_DrawingSurface* ds; + JAWT_DrawingSurfaceInfo* dsi; + JAWT_Win32DrawingSurfaceInfo* dsi_win; + jboolean result; + // jint lock; + jint windowHandle = -1; + + // Get the AWT + awt.version = JAWT_VERSION_1_4; + result = JAWT_GetAWT(env, &awt); + if (result == JNI_FALSE) { + return -1; + } + + // Get the drawing surface + ds = awt.GetDrawingSurface(env, component); + if (ds == NULL) { + return -1; + } + + // Get the drawing surface info + dsi = ds->GetDrawingSurfaceInfo(ds); + + // Get the platform-specific drawing info + dsi_win = (JAWT_Win32DrawingSurfaceInfo *)dsi->platformInfo; + + // Get the window handle + windowHandle = (jint)dsi_win->hwnd; + + // Free the drawing surface info + ds->FreeDrawingSurfaceInfo(dsi); + + // Free the drawing surface + awt.FreeDrawingSurface(ds); + + return windowHandle; + } + +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/JavaAccessBridge.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libjavaaccessbridge/JavaAccessBridge.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A DLL which is loaded by Java applications to handle communication + * between Java VMs purposes of Accessbility. + */ + +#include +#include + +#include "AccessBridgePackages.h" +#include "AccessBridgeATInstance.h" +#include "AccessBridgeJavaEntryPoints.h" + +#ifndef __JavaAccessBridge_H__ +#define __JavaAccessBridge_H__ + + +extern "C" { + BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, + LPVOID lpvReserved); + void AppendToCallOutput(char *s); + BOOL APIENTRY AccessBridgeDialogProc(HWND hDlg, UINT message, + UINT wParam, LONG lParam); +} + +/** + * The JavaAccessBridge class. The core of the Windows AT AccessBridge dll + */ +class JavaAccessBridge { +// for debugging +public: +// for debugging + HINSTANCE windowsInstance; + HWND dialogWindow; + AccessBridgeATInstance *ATs; + JavaVM *javaVM; + JNIEnv *windowsThreadJNIEnv; // for calls initiated from Windows + AccessBridgeJavaEntryPoints *javaThreadEntryPoints; + AccessBridgeJavaEntryPoints *windowsThreadEntryPoints; + jobject javaThreadABObject; // for calls initiated from Java + jobject windowsThreadABObject; // for calls initiated from Windows + +public: + JavaAccessBridge(HINSTANCE hInstance); + ~JavaAccessBridge(); + void javaRun(JNIEnv *env, jobject obj); + BOOL initWindow(); + + // IPC with the Java AccessBridge DLL + void postHelloToWindowsDLLMsg(HWND destHwnd); + LRESULT MemoryMappedFileCreated(HWND srcHwnd, char *filename); + + void sendPackage(char *buffer, int bufsize, HWND destHwnd); + void sendJavaEventPackage(char *buffer, int bufsize, long type); + void sendAccessibilityEventPackage(char *buffer, int bufsize, long type); + BOOL sendMemoryPackage(char *buffer, long bufsize, HWND destWindow); + LRESULT processPackage(char *buffer, int bufsize); + BOOL receiveMemoryPackage(HWND srcWindow, long bufsize); + void WindowsATDestroyed(HWND ATBridgeDLLWindow); + + // Java VM object memory management + void releaseJavaObject(jobject object); + + // Event handling methods + void addJavaEventNotification(jlong type, HWND DLLwindow); + void removeJavaEventNotification(jlong type, HWND DLLwindow); + void addAccessibilityEventNotification(jlong type, HWND DLLwindow); + void removeAccessibilityEventNotification(jlong type, HWND DLLwindow); + + // Event firing methods +/* + void firePropertyChange(JNIEnv *env, jobject callingObj, + jobject propertyChangeEvent, + jobject source, jstring propertyName, + jstring oldValue, jstring newValue); +*/ + + void javaShutdown(JNIEnv *env, jobject callingObj); + + void fireFocusGained(JNIEnv *env, jobject callingObj, + jobject focusEvent, jobject source); + void fireFocusLost(JNIEnv *env, jobject callingObj, + jobject focusEvent,jobject source); + void fireCaretUpdate(JNIEnv *env, jobject callingObj, + jobject caretEvent, jobject source); + void fireMouseClicked(JNIEnv *env, jobject callingObj, + jobject mouseEvent, jobject source); + void fireMouseEntered(JNIEnv *env, jobject callingObj, + jobject mouseEvent, jobject source); + void fireMouseExited(JNIEnv *env, jobject callingObj, + jobject mouseEvent, jobject source); + void fireMousePressed(JNIEnv *env, jobject callingObj, + jobject mouseEvent, jobject source); + void fireMouseReleased(JNIEnv *env, jobject callingObj, + jobject mouseEvent, jobject source); + void fireMenuCanceled(JNIEnv *env, jobject callingObj, + jobject menuEvent, jobject source); + void fireMenuDeselected(JNIEnv *env, jobject callingObj, + jobject menuEvent, jobject source); + void fireMenuSelected(JNIEnv *env, jobject callingObj, + jobject menuEvent, jobject source); + void firePopupMenuCanceled(JNIEnv *env, jobject callingObj, + jobject popupMenuEvent, jobject source); + void firePopupMenuWillBecomeInvisible(JNIEnv *env, jobject callingObj, + jobject popupMenuEvent, jobject source); + void firePopupMenuWillBecomeVisible(JNIEnv *env, jobject callingObj, + jobject popupMenuEvent, jobject source); + + void firePropertyCaretChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jint oldValue, jint newValue); + void firePropertyDescriptionChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue); + void firePropertyNameChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue); + void firePropertySelectionChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source); + void firePropertyStateChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue); + void firePropertyTextChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source); + void firePropertyValueChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue); + void firePropertyVisibleDataChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source); + void firePropertyChildChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jobject oldValue, jobject newValue); + void firePropertyActiveDescendentChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jobject oldValue, jobject newValue); + + void firePropertyTableModelChange(JNIEnv *env, jobject callingObj, + jobject event, jobject source, + jstring oldValue, jstring newValue); +}; + + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeEventHandler.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeEventHandler.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to manage firing Accessibility events to Windows AT + */ + +#include "AccessBridgeDebug.h" +#include "AccessBridgeEventHandler.h" +#include "AccessBridgePackages.h" +#include "WinAccessBridge.h" + +DEBUG_CODE(extern HWND theDialogWindow); +extern "C" { +DEBUG_CODE(void AppendToCallInfo(char *s)); +} + + +// ----------------------------- + +/** + * Initialization. Set all callbacks to null + */ +AccessBridgeEventHandler::AccessBridgeEventHandler() { + javaEventMask = 0; + accessibilityEventMask = 0; + + propertyChangeFP = (AccessBridge_PropertyChangeFP) NULL; + javaShutdownFP = (AccessBridge_JavaShutdownFP) NULL; + focusGainedFP = (AccessBridge_FocusGainedFP) NULL; + focusLostFP = (AccessBridge_FocusLostFP) NULL; + caretUpdateFP = (AccessBridge_CaretUpdateFP) NULL; + mouseClickedFP = (AccessBridge_MouseClickedFP) NULL; + mouseEnteredFP = (AccessBridge_MouseEnteredFP) NULL; + mouseExitedFP = (AccessBridge_MouseExitedFP) NULL; + mousePressedFP = (AccessBridge_MousePressedFP) NULL; + mouseReleasedFP = (AccessBridge_MouseReleasedFP) NULL; + menuCanceledFP = (AccessBridge_MenuCanceledFP) NULL; + menuDeselectedFP = (AccessBridge_MenuDeselectedFP) NULL; + menuSelectedFP = (AccessBridge_MenuSelectedFP) NULL; + popupMenuCanceledFP = (AccessBridge_PopupMenuCanceledFP) NULL; + popupMenuWillBecomeInvisibleFP = (AccessBridge_PopupMenuWillBecomeInvisibleFP) NULL; + popupMenuWillBecomeVisibleFP = (AccessBridge_PopupMenuWillBecomeVisibleFP) NULL; + + propertyNameChangeFP = (AccessBridge_PropertyNameChangeFP) NULL; + propertyDescriptionChangeFP = (AccessBridge_PropertyDescriptionChangeFP) NULL; + propertyStateChangeFP = (AccessBridge_PropertyStateChangeFP) NULL; + propertyValueChangeFP = (AccessBridge_PropertyValueChangeFP) NULL; + propertySelectionChangeFP = (AccessBridge_PropertySelectionChangeFP) NULL; + propertyTextChangeFP = (AccessBridge_PropertyTextChangeFP) NULL; + propertyCaretChangeFP = (AccessBridge_PropertyCaretChangeFP) NULL; + propertyVisibleDataChangeFP = (AccessBridge_PropertyVisibleDataChangeFP) NULL; + propertyChildChangeFP = (AccessBridge_PropertyChildChangeFP) NULL; + propertyActiveDescendentChangeFP = (AccessBridge_PropertyActiveDescendentChangeFP) NULL; + + propertyTableModelChangeFP = (AccessBridge_PropertyTableModelChangeFP) NULL; + +} + +/** + * Destruction. + */ +AccessBridgeEventHandler::~AccessBridgeEventHandler() { +} + + +// ------------ Event handling methods + +#define SET_JAVA_EVENT_FP(function, eventFP, callbackFP, eventConstant) \ + void AccessBridgeEventHandler::function(eventFP fp, WinAccessBridge *wab) { \ + callbackFP = fp; \ + if (fp != (eventFP) 0) { \ + javaEventMask |= eventConstant; \ + wab->addJavaEventNotification(eventConstant); \ + } else { \ + javaEventMask &= (0xFFFFFFFF - eventConstant); \ + wab->removeJavaEventNotification(eventConstant); \ + } \ + } + +SET_JAVA_EVENT_FP(setPropertyChangeFP, AccessBridge_PropertyChangeFP, propertyChangeFP, cPropertyChangeEvent) +SET_JAVA_EVENT_FP(setJavaShutdownFP, AccessBridge_JavaShutdownFP, javaShutdownFP, cJavaShutdownEvent) +SET_JAVA_EVENT_FP(setFocusGainedFP, AccessBridge_FocusGainedFP, focusGainedFP, cFocusGainedEvent) +SET_JAVA_EVENT_FP(setFocusLostFP, AccessBridge_FocusLostFP, focusLostFP, cFocusLostEvent) +SET_JAVA_EVENT_FP(setCaretUpdateFP, AccessBridge_CaretUpdateFP, caretUpdateFP, cCaretUpdateEvent) +SET_JAVA_EVENT_FP(setMouseClickedFP, AccessBridge_MouseClickedFP, mouseClickedFP, cMouseClickedEvent) +SET_JAVA_EVENT_FP(setMouseEnteredFP, AccessBridge_MouseEnteredFP, mouseEnteredFP, cMouseEnteredEvent) +SET_JAVA_EVENT_FP(setMouseExitedFP, AccessBridge_MouseExitedFP, mouseExitedFP, cMouseExitedEvent) +SET_JAVA_EVENT_FP(setMousePressedFP, AccessBridge_MousePressedFP, mousePressedFP, cMousePressedEvent) +SET_JAVA_EVENT_FP(setMouseReleasedFP, AccessBridge_MouseReleasedFP, mouseReleasedFP, cMouseReleasedEvent) +SET_JAVA_EVENT_FP(setMenuCanceledFP, AccessBridge_MenuCanceledFP, menuCanceledFP, cMenuCanceledEvent) +SET_JAVA_EVENT_FP(setMenuDeselectedFP, AccessBridge_MenuDeselectedFP, menuDeselectedFP, cMenuDeselectedEvent) +SET_JAVA_EVENT_FP(setMenuSelectedFP, AccessBridge_MenuSelectedFP, menuSelectedFP, cMenuSelectedEvent) +SET_JAVA_EVENT_FP(setPopupMenuCanceledFP, AccessBridge_PopupMenuCanceledFP, popupMenuCanceledFP, cPopupMenuCanceledEvent) +SET_JAVA_EVENT_FP(setPopupMenuWillBecomeInvisibleFP, AccessBridge_PopupMenuWillBecomeInvisibleFP, popupMenuWillBecomeInvisibleFP, cPopupMenuWillBecomeInvisibleEvent) +SET_JAVA_EVENT_FP(setPopupMenuWillBecomeVisibleFP, AccessBridge_PopupMenuWillBecomeVisibleFP, popupMenuWillBecomeVisibleFP, cPopupMenuWillBecomeVisibleEvent) + +#define SET_ACCESSIBILITY_EVENT_FP(function, eventFP, callbackFP, eventConstant) \ + void AccessBridgeEventHandler::function(eventFP fp, WinAccessBridge *wab) { \ + callbackFP = fp; \ + if (fp != (eventFP) 0) { \ + accessibilityEventMask |= eventConstant; \ + wab->addAccessibilityEventNotification(eventConstant); \ + } else { \ + accessibilityEventMask &= (0xFFFFFFFF - eventConstant); \ + wab->removeAccessibilityEventNotification(eventConstant); \ + } \ + } + + +SET_ACCESSIBILITY_EVENT_FP(setPropertyNameChangeFP, AccessBridge_PropertyNameChangeFP, propertyNameChangeFP, cPropertyNameChangeEvent) +SET_ACCESSIBILITY_EVENT_FP(setPropertyDescriptionChangeFP, AccessBridge_PropertyDescriptionChangeFP, propertyDescriptionChangeFP, cPropertyDescriptionChangeEvent) +SET_ACCESSIBILITY_EVENT_FP(setPropertyStateChangeFP, AccessBridge_PropertyStateChangeFP, propertyStateChangeFP, cPropertyStateChangeEvent) +SET_ACCESSIBILITY_EVENT_FP(setPropertyValueChangeFP, AccessBridge_PropertyValueChangeFP, propertyValueChangeFP, cPropertyValueChangeEvent) +SET_ACCESSIBILITY_EVENT_FP(setPropertySelectionChangeFP, AccessBridge_PropertySelectionChangeFP, propertySelectionChangeFP, cPropertySelectionChangeEvent) +SET_ACCESSIBILITY_EVENT_FP(setPropertyTextChangeFP, AccessBridge_PropertyTextChangeFP, propertyTextChangeFP, cPropertyTextChangeEvent) +SET_ACCESSIBILITY_EVENT_FP(setPropertyCaretChangeFP, AccessBridge_PropertyCaretChangeFP, propertyCaretChangeFP, cPropertyCaretChangeEvent) +SET_ACCESSIBILITY_EVENT_FP(setPropertyVisibleDataChangeFP, AccessBridge_PropertyVisibleDataChangeFP, propertyVisibleDataChangeFP, cPropertyVisibleDataChangeEvent) +SET_ACCESSIBILITY_EVENT_FP(setPropertyChildChangeFP, AccessBridge_PropertyChildChangeFP, propertyChildChangeFP, cPropertyChildChangeEvent) +SET_ACCESSIBILITY_EVENT_FP(setPropertyActiveDescendentChangeFP, AccessBridge_PropertyActiveDescendentChangeFP, propertyActiveDescendentChangeFP, cPropertyActiveDescendentChangeEvent) + +SET_ACCESSIBILITY_EVENT_FP(setPropertyTableModelChangeFP, AccessBridge_PropertyTableModelChangeFP, propertyTableModelChangeFP, cPropertyTableModelChangeEvent) + + +/** + * propertyChange - extends the Java method call to Windows: + * propertyChange(PropertyChangeEvent e, ) + * + * Note: PropertyChangeEvent object passed in is a globalReference; + * It is critical that releaseJavaObject() be called + * on the PropertyChangeEvent once it is no longer needed, + * otherwise the JavaVM/JNI will suffer memory leaks + * + */ +void +AccessBridgeEventHandler::firePropertyChange(long vmID, + JOBJECT64 event, JOBJECT64 source, + wchar_t *property, wchar_t *oldName, + wchar_t *newName) { + DEBUG_CODE(char debugBuf[255]); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + DEBUG_CODE(sprintf(debugBuf, "\r\nCalling firePropertyChange(%p, %p):\r\n", event, source)); +#else // JOBJECT64 is jlong (64 bit) + DEBUG_CODE(sprintf(debugBuf, "\r\nCalling firePropertyChange(%016I64X, %016I64X):\r\n", event, source)); +#endif + DEBUG_CODE(AppendToCallInfo(debugBuf)); + + if (propertyChangeFP != (AccessBridge_PropertyChangeFP) 0) { + propertyChangeFP(vmID, event, source, property, oldName, newName); + } else { + DEBUG_CODE(AppendToCallInfo(" Error! propertyChangeFP == 0\r\n")); + } +} + + +/** + * FIRE_EVENT - macro for all fireXXX methods (which + * all are basically identical to one another...) + * + * Note: the event and source objects passed in are globalReferences; + * It is critical that releaseJavaObject() be called + * on them once they are no longer needed, otherwise + * the JavaVM/JNI will suffer memory leaks + * + */ +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) +const char fireEventDebugString[] = "\r\nIn AccessBridgeEventHandler::%s(%p, %p); vmID = %X\r\n"; +#else // JOBJECT64 is jlong (64 bit) +const char fireEventDebugString[] = "\r\nIn AccessBridgeEventHandler::%s(%016I64X, %016I64X); vmID = %X\r\n"; +#endif + +#define FIRE_EVENT(method, FPprototype, eventFP) \ + void AccessBridgeEventHandler::method(long vmID, JOBJECT64 event, JOBJECT64 source) { \ + DEBUG_CODE(char debugBuf[255]); \ + DEBUG_CODE(sprintf(debugBuf, fireEventDebugString, #method, event, source, vmID)); \ + DEBUG_CODE(AppendToCallInfo(debugBuf)); \ + if (eventFP != (FPprototype) 0) { \ + eventFP(vmID, event, source); \ + } else { \ + DEBUG_CODE(AppendToCallInfo(" Error! eventFP == 0\r\n")); \ + } \ + } + + void AccessBridgeEventHandler::fireJavaShutdown(long vmID) { + DEBUG_CODE(char debugBuf[255]); + DEBUG_CODE(sprintf(debugBuf, "\r\nCalling fireJavaShutdown; vmID = %X\r\n", vmID)); + DEBUG_CODE(AppendToCallInfo(debugBuf)); + if (javaShutdownFP != (AccessBridge_JavaShutdownFP) 0) { + javaShutdownFP(vmID); + } else { + DEBUG_CODE(AppendToCallInfo(" Error! javaShutdownFP == 0\r\n")); + } + } + +FIRE_EVENT(fireFocusGained, AccessBridge_FocusGainedFP, focusGainedFP) +FIRE_EVENT(fireFocusLost, AccessBridge_FocusLostFP, focusLostFP) +FIRE_EVENT(fireCaretUpdate, AccessBridge_CaretUpdateFP, caretUpdateFP) +FIRE_EVENT(fireMouseClicked, AccessBridge_MouseClickedFP, mouseClickedFP) +FIRE_EVENT(fireMouseEntered, AccessBridge_MouseEnteredFP, mouseEnteredFP) +FIRE_EVENT(fireMouseExited, AccessBridge_MouseExitedFP, mouseExitedFP) +FIRE_EVENT(fireMousePressed, AccessBridge_MousePressedFP, mousePressedFP) +FIRE_EVENT(fireMouseReleased, AccessBridge_MouseReleasedFP, mouseReleasedFP) +FIRE_EVENT(fireMenuCanceled, AccessBridge_MenuCanceledFP, menuCanceledFP) +FIRE_EVENT(fireMenuDeselected, AccessBridge_MenuDeselectedFP, menuDeselectedFP) +FIRE_EVENT(fireMenuSelected, AccessBridge_MenuSelectedFP, menuSelectedFP) +FIRE_EVENT(firePopupMenuCanceled, AccessBridge_PopupMenuCanceledFP, popupMenuCanceledFP) +FIRE_EVENT(firePopupMenuWillBecomeInvisible, AccessBridge_PopupMenuWillBecomeInvisibleFP, popupMenuWillBecomeInvisibleFP) +FIRE_EVENT(firePopupMenuWillBecomeVisible, AccessBridge_PopupMenuWillBecomeVisibleFP, popupMenuWillBecomeVisibleFP) + + +/** + * FIRE_PROPERTY_CHANGE - macro for all fireXXX methods (which + * all are basically identical to one another... + * + * Note: the event and source objects passed in are globalReferences; + * It is critical that releaseJavaObject() be called + * on them once they are no longer needed, otherwise + * the JavaVM/JNI will suffer memory leaks + * + */ +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) +const char firePropertyChangeDebugString[] = "\r\nIn AccessBridgeEventHandler::%s, Firing a no-param property change (%p, %p):\r\n"; +#else // JOBJECT64 is jlong (64 bit) +const char firePropertyChangeDebugString[] = "\r\nIn AccessBridgeEventHandler::%s, Firing a no-param property change (%016I64X, %016I64X):\r\n"; +#endif + +#define FIRE_PROPERTY_CHANGE(method, FPprototype, eventFP) \ + void AccessBridgeEventHandler::method(long vmID, JOBJECT64 event, JOBJECT64 source) { \ + DEBUG_CODE(char debugBuf[255]); \ + DEBUG_CODE(sprintf(debugBuf, firePropertyChangeDebugString, #method, event, source)); \ + DEBUG_CODE(AppendToCallInfo(debugBuf)); \ + if (eventFP != (FPprototype) 0) { \ + eventFP(vmID, event, source); \ + } else { \ + DEBUG_CODE(AppendToCallInfo(" Error! eventFP == 0\r\n")); \ + } \ + } + +/** + * FIRE_STRING_PROPERTY_CHANGE - macro for all firePropertyXXXChange methods + * that have strings as the old/new values + + * Note: the event and source objects passed in are globalReferences; + * It is critical that releaseJavaObject() be called + * on them once they are no longer needed, otherwise + * the JavaVM/JNI will suffer memory leaks + * + */ +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) +const char fireStringPropertyChangeDebugString[] = "\r\nIn AccessBridgeEventHandler::%s, Firing a string property change (%p, %p, %ls, %ls):\r\n"; +#else // JOBJECT64 is jlong (64 bit) +const char fireStringPropertyChangeDebugString[] = "\r\nIn AccessBridgeEventHandler::%s, Firing a string property change (%016I64X, %016I64X, %ls, %ls):\r\n"; +#endif + +#define FIRE_STRING_PROPERTY_CHANGE(method, FPprototype, eventFP, oldValue, newValue) \ + void AccessBridgeEventHandler::method(long vmID, JOBJECT64 event, JOBJECT64 source, \ + wchar_t *oldValue, wchar_t *newValue) { \ + DEBUG_CODE(char debugBuf[255]); \ + DEBUG_CODE(sprintf(debugBuf, fireStringPropertyChangeDebugString, #method, event, source, oldValue, newValue)); \ + DEBUG_CODE(AppendToCallInfo(debugBuf)); \ + if (eventFP != (FPprototype) 0) { \ + eventFP(vmID, event, source, oldValue, newValue); \ + } else { \ + DEBUG_CODE(AppendToCallInfo(" Error! eventFP == 0\r\n")); \ + } \ + } + +/** + * FIRE_INT_PROPERTY_CHANGE - macro for all firePropertyXXXChange methods + * that have ints as the old/new values + * + * Note: the event and source objects passed in are globalReferences; + * It is critical that releaseJavaObject() be called + * on them once they are no longer needed, otherwise + * the JavaVM/JNI will suffer memory leaks + * + */ +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) +const char fireIntPropertyChangeDebugString[] = "\r\nIn AccessBridgeEventHandler::%s, Firing an int property change (%p, %p, %d, %d):\r\n"; +#else // JOBJECT64 is jlong (64 bit) +const char fireIntPropertyChangeDebugString[] = "\r\nIn AccessBridgeEventHandler::%s, Firing an int property change (%016I64X, %016I64X, %d, %d):\r\n"; +#endif + +#define FIRE_INT_PROPERTY_CHANGE(method, FPprototype, eventFP) \ + void AccessBridgeEventHandler::method(long vmID, JOBJECT64 event, JOBJECT64 source, \ + int oldValue, int newValue) { \ + DEBUG_CODE(char debugBuf[255]); \ + DEBUG_CODE(sprintf(debugBuf, fireIntPropertyChangeDebugString, #method, event, source, oldValue, newValue)); \ + DEBUG_CODE(AppendToCallInfo(debugBuf)); \ + if (eventFP != (FPprototype) 0) { \ + eventFP(vmID, event, source, oldValue, newValue); \ + } else { \ + DEBUG_CODE(AppendToCallInfo(" Error! eventFP == 0\r\n")); \ + } \ + } + +/** + * FIRE_AC_PROPERTY_CHANGE - macro for all firePropertyXXXChange methods + * that have jobjects (AccessibleContexts) as the old/new values + * + * Note: the event and source objects passed in are globalReferences; + * It is critical that releaseJavaObject() be called + * on them once they are no longer needed, otherwise + * the JavaVM/JNI will suffer memory leaks + * + */ +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) +const char fireACPropertyChangeDebugString[] = "\r\nIn AccessBridgeEventHandler::%s, Firing an AC property change (%p, %p, %p, %p):\r\n"; +#else // JOBJECT64 is jlong (64 bit) +const char fireACPropertyChangeDebugString[] = "\r\nIn AccessBridgeEventHandler::%s, Firing an AC property change (%016I64X, %016I64X, %016I64X, %016I64X):\r\n"; +#endif + +#define FIRE_AC_PROPERTY_CHANGE(method, FPprototype, eventFP) \ + void AccessBridgeEventHandler::method(long vmID, JOBJECT64 event, JOBJECT64 source, \ + JOBJECT64 oldValue, JOBJECT64 newValue) { \ + DEBUG_CODE(char debugBuf[255]); \ + DEBUG_CODE(sprintf(debugBuf, fireACPropertyChangeDebugString, #method, event, source, oldValue, newValue)); \ + DEBUG_CODE(AppendToCallInfo(debugBuf)); \ + if (eventFP != (FPprototype) 0) { \ + eventFP(vmID, event, source, oldValue, newValue); \ + } else { \ + DEBUG_CODE(AppendToCallInfo(" Error! eventFP == 0\r\n")); \ + } \ + } + +FIRE_STRING_PROPERTY_CHANGE(firePropertyNameChange, + AccessBridge_PropertyNameChangeFP, + propertyNameChangeFP, oldName, newName) +FIRE_STRING_PROPERTY_CHANGE(firePropertyDescriptionChange, + AccessBridge_PropertyDescriptionChangeFP, + propertyDescriptionChangeFP, + oldDescription, newDescription) +FIRE_STRING_PROPERTY_CHANGE(firePropertyStateChange, + AccessBridge_PropertyStateChangeFP, + propertyStateChangeFP, oldState, newState) +FIRE_STRING_PROPERTY_CHANGE(firePropertyValueChange, + AccessBridge_PropertyValueChangeFP, + propertyValueChangeFP, oldValue, newValue) +FIRE_PROPERTY_CHANGE(firePropertySelectionChange, + AccessBridge_PropertySelectionChangeFP, + propertySelectionChangeFP) +FIRE_PROPERTY_CHANGE(firePropertyTextChange, + AccessBridge_PropertyTextChangeFP, + propertyTextChangeFP); +FIRE_INT_PROPERTY_CHANGE(firePropertyCaretChange, + AccessBridge_PropertyCaretChangeFP, + propertyCaretChangeFP) +FIRE_PROPERTY_CHANGE(firePropertyVisibleDataChange, + AccessBridge_PropertyVisibleDataChangeFP, + propertyVisibleDataChangeFP) +FIRE_AC_PROPERTY_CHANGE(firePropertyChildChange, + AccessBridge_PropertyChildChangeFP, + propertyChildChangeFP) +FIRE_AC_PROPERTY_CHANGE(firePropertyActiveDescendentChange, + AccessBridge_PropertyActiveDescendentChangeFP, + propertyActiveDescendentChangeFP) + +FIRE_STRING_PROPERTY_CHANGE(firePropertyTableModelChange, + AccessBridge_PropertyTableModelChangeFP, + propertyTableModelChangeFP, oldValue, newValue) diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeEventHandler.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeEventHandler.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to manage firing Accessibility events to Windows AT + */ + +#ifndef __AccessBridgeEventHandler_H__ +#define __AccessBridgeEventHandler_H__ + +#include "AccessBridgeCallbacks.h" +#include "AccessBridgePackages.h" + +class WinAccessBridge; + +class AccessBridgeEventHandler { + long javaEventMask; + long accessibilityEventMask; + + AccessBridge_PropertyChangeFP propertyChangeFP; + AccessBridge_JavaShutdownFP javaShutdownFP; + AccessBridge_FocusGainedFP focusGainedFP; + AccessBridge_FocusLostFP focusLostFP; + AccessBridge_CaretUpdateFP caretUpdateFP; + AccessBridge_MouseClickedFP mouseClickedFP; + AccessBridge_MouseEnteredFP mouseEnteredFP; + AccessBridge_MouseExitedFP mouseExitedFP; + AccessBridge_MousePressedFP mousePressedFP; + AccessBridge_MouseReleasedFP mouseReleasedFP; + AccessBridge_MenuCanceledFP menuCanceledFP; + AccessBridge_MenuDeselectedFP menuDeselectedFP; + AccessBridge_MenuSelectedFP menuSelectedFP; + AccessBridge_PopupMenuCanceledFP popupMenuCanceledFP; + AccessBridge_PopupMenuWillBecomeInvisibleFP popupMenuWillBecomeInvisibleFP; + AccessBridge_PopupMenuWillBecomeVisibleFP popupMenuWillBecomeVisibleFP; + + AccessBridge_PropertyNameChangeFP propertyNameChangeFP; + AccessBridge_PropertyDescriptionChangeFP propertyDescriptionChangeFP; + AccessBridge_PropertyStateChangeFP propertyStateChangeFP; + AccessBridge_PropertyValueChangeFP propertyValueChangeFP; + AccessBridge_PropertySelectionChangeFP propertySelectionChangeFP; + AccessBridge_PropertyTextChangeFP propertyTextChangeFP; + AccessBridge_PropertyCaretChangeFP propertyCaretChangeFP; + AccessBridge_PropertyVisibleDataChangeFP propertyVisibleDataChangeFP; + AccessBridge_PropertyChildChangeFP propertyChildChangeFP; + AccessBridge_PropertyActiveDescendentChangeFP propertyActiveDescendentChangeFP; + + AccessBridge_PropertyTableModelChangeFP propertyTableModelChangeFP; + + + +public: + AccessBridgeEventHandler(); + ~AccessBridgeEventHandler(); + long getJavaEventMask() {return javaEventMask;}; + long getAccessibilityEventMask() {return accessibilityEventMask;}; + + // ------- Registry methods + void setPropertyChangeFP(AccessBridge_PropertyChangeFP fp, WinAccessBridge *wab); + void setJavaShutdownFP(AccessBridge_JavaShutdownFP fp, WinAccessBridge *wab); + void setFocusGainedFP(AccessBridge_FocusGainedFP fp, WinAccessBridge *wab); + void setFocusLostFP(AccessBridge_FocusLostFP fp, WinAccessBridge *wab); + void setCaretUpdateFP(AccessBridge_CaretUpdateFP fp, WinAccessBridge *wab); + void setMouseClickedFP(AccessBridge_MouseClickedFP fp, WinAccessBridge *wab); + void setMouseEnteredFP(AccessBridge_MouseEnteredFP fp, WinAccessBridge *wab); + void setMouseExitedFP(AccessBridge_MouseExitedFP fp, WinAccessBridge *wab); + void setMousePressedFP(AccessBridge_MousePressedFP fp, WinAccessBridge *wab); + void setMouseReleasedFP(AccessBridge_MouseReleasedFP fp, WinAccessBridge *wab); + void setMenuCanceledFP(AccessBridge_MenuCanceledFP fp, WinAccessBridge *wab); + void setMenuDeselectedFP(AccessBridge_MenuDeselectedFP fp, WinAccessBridge *wab); + void setMenuSelectedFP(AccessBridge_MenuSelectedFP fp, WinAccessBridge *wab); + void setPopupMenuCanceledFP(AccessBridge_PopupMenuCanceledFP fp, WinAccessBridge *wab); + void setPopupMenuWillBecomeInvisibleFP(AccessBridge_PopupMenuWillBecomeInvisibleFP fp, + WinAccessBridge *wab); + void setPopupMenuWillBecomeVisibleFP(AccessBridge_PopupMenuWillBecomeVisibleFP fp, + WinAccessBridge *wab); + + void setPropertyNameChangeFP(AccessBridge_PropertyNameChangeFP fp, WinAccessBridge *wab); + void setPropertyDescriptionChangeFP(AccessBridge_PropertyDescriptionChangeFP fp, + WinAccessBridge *wab); + void setPropertyStateChangeFP(AccessBridge_PropertyStateChangeFP fp, WinAccessBridge *wab); + void setPropertyValueChangeFP(AccessBridge_PropertyValueChangeFP fp, WinAccessBridge *wab); + void setPropertySelectionChangeFP(AccessBridge_PropertySelectionChangeFP fp, + WinAccessBridge *wab); + void setPropertyTextChangeFP(AccessBridge_PropertyTextChangeFP fp, WinAccessBridge *wab); + void setPropertyCaretChangeFP(AccessBridge_PropertyCaretChangeFP fp, WinAccessBridge *wab); + void setPropertyVisibleDataChangeFP(AccessBridge_PropertyVisibleDataChangeFP fp, + WinAccessBridge *wab); + void setPropertyChildChangeFP(AccessBridge_PropertyChildChangeFP fp, WinAccessBridge *wab); + void setPropertyActiveDescendentChangeFP(AccessBridge_PropertyActiveDescendentChangeFP fp, + WinAccessBridge *wab); + + void setPropertyTableModelChangeFP(AccessBridge_PropertyTableModelChangeFP fp, + WinAccessBridge *wab); + + // ------- Event notification methods + void firePropertyChange(long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *property, wchar_t *oldName, wchar_t *newName); + void fireJavaShutdown(long vmID); + void fireFocusGained(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireFocusLost(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireCaretUpdate(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireMouseClicked(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireMouseEntered(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireMouseExited(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireMousePressed(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireMouseReleased(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireMenuCanceled(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireMenuDeselected(long vmID, JOBJECT64 event, JOBJECT64 source); + void fireMenuSelected(long vmID, JOBJECT64 event, JOBJECT64 source); + void firePopupMenuCanceled(long vmID, JOBJECT64 event, JOBJECT64 source); + void firePopupMenuWillBecomeInvisible(long vmID, JOBJECT64 event, JOBJECT64 source); + void firePopupMenuWillBecomeVisible(long vmID, JOBJECT64 event, JOBJECT64 source); + + void firePropertyNameChange(long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldName, wchar_t *newName); + void firePropertyDescriptionChange(long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldDescription, wchar_t *newDescription); + void firePropertyStateChange(long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldState, wchar_t *newState); + void firePropertyValueChange(long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldValue, wchar_t *newValue); + void firePropertySelectionChange(long vmID, JOBJECT64 event, JOBJECT64 source); + void firePropertyTextChange(long vmID, JOBJECT64 event, JOBJECT64 source); + void firePropertyCaretChange(long vmID, JOBJECT64 event, JOBJECT64 source, + int oldPosition, int newPosition); + void firePropertyVisibleDataChange(long vmID, JOBJECT64 event, JOBJECT64 source); + void firePropertyChildChange(long vmID, JOBJECT64 event, JOBJECT64 source, + JOBJECT64 oldChild, JOBJECT64 newChild); + void firePropertyActiveDescendentChange(long vmID, JOBJECT64 event, JOBJECT64 source, + JOBJECT64 oldActiveDescendent, JOBJECT64 newActiveDescendent); + + void firePropertyTableModelChange(long vmID, JOBJECT64 event, JOBJECT64 source, + wchar_t *oldValue, wchar_t *newValue); + +}; + + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeJavaVMInstance.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeJavaVMInstance.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to track key JVM instance info from the AT WinAccessBridge + */ + +#include "AccessBridgeDebug.h" +#include "AccessBridgeJavaVMInstance.h" +#include "AccessBridgeMessages.h" +#include "AccessBridgePackages.h" +#include "accessBridgeResource.h" // for debugging messages + +#include +#include + +// The initialization must only be done one time and to provide for that the initialization +// is now done in WinAccessBridge and the CRITICAL_SECTION memory has been moved to there. +// send memory lock +//CRITICAL_SECTION sendMemoryIPCLock; +extern CRITICAL_SECTION sendMemoryIPCLock; + +// protects the javaVMs chain while in use +extern bool isVMInstanceChainInUse; + +DEBUG_CODE(extern HWND theDialogWindow); +extern "C" { + DEBUG_CODE(void AppendToCallInfo(char *s)); +} + + +/** + * + * + */ +AccessBridgeJavaVMInstance::AccessBridgeJavaVMInstance(HWND ourABWindow, + HWND javaABWindow, + long javaVMID, + AccessBridgeJavaVMInstance *next) { + goingAway = FALSE; + // This should be called once. Moved to WinAccessBridge c'tor + //InitializeCriticalSection(&sendMemoryIPCLock); + ourAccessBridgeWindow = ourABWindow; + javaAccessBridgeWindow = javaABWindow; + vmID = javaVMID; + nextJVMInstance = next; + memoryMappedFileMapHandle = (HANDLE) 0; + memoryMappedView = (char *) 0; + sprintf(memoryMappedFileName, "AccessBridge-%p-%p.mmf", + ourAccessBridgeWindow, javaAccessBridgeWindow); +} + +/** + * + * + */ +AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance() { + DEBUG_CODE(char buffer[256]); + + DEBUG_CODE(AppendToCallInfo("***** in AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance\r\n")); + EnterCriticalSection(&sendMemoryIPCLock); + + // if IPC memory mapped file view is valid, unmap it + goingAway = TRUE; + if (memoryMappedView != (char *) 0) { + DEBUG_CODE(sprintf(buffer, " unmapping memoryMappedView; view = %p\r\n", memoryMappedView)); + DEBUG_CODE(AppendToCallInfo(buffer)); + UnmapViewOfFile(memoryMappedView); + memoryMappedView = (char *) 0; + } + // if IPC memory mapped file handle map is open, close it + if (memoryMappedFileMapHandle != (HANDLE) 0) { + DEBUG_CODE(sprintf(buffer, " closing memoryMappedFileMapHandle; handle = %p\r\n", memoryMappedFileMapHandle)); + DEBUG_CODE(AppendToCallInfo(buffer)); + CloseHandle(memoryMappedFileMapHandle); + memoryMappedFileMapHandle = (HANDLE) 0; + } + LeaveCriticalSection(&sendMemoryIPCLock); + +} + +/** + * initiateIPC - sets up the memory-mapped file to do IPC messaging + * 1 file is created: to handle requests for information + * initiated from Windows AT. The package is placed into + * the memory-mapped file (char *memoryMappedView), + * and then a special SendMessage() is sent. When the + * JavaDLL returns from SendMessage() processing, the + * data will be in memoryMappedView. The SendMessage() + * return value tells us if all is right with the world. + * + * The set-up proces involves creating the memory-mapped + * file, and handshaking with the JavaDLL so it knows + * about it as well. + * + */ +LRESULT +AccessBridgeJavaVMInstance::initiateIPC() { + DEBUG_CODE(char debugBuf[256]); + DWORD errorCode; + + DEBUG_CODE(AppendToCallInfo(" in AccessBridgeJavaVMInstance::initiateIPC()\r\n")); + + // create Windows-initiated IPC file & map it to a ptr + memoryMappedFileMapHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, + PAGE_READWRITE, 0, + // 8 bytes for return code + sizeof(WindowsInitiatedPackages) + 8, + memoryMappedFileName); + if (memoryMappedFileMapHandle == NULL) { + errorCode = GetLastError(); + DEBUG_CODE(sprintf(debugBuf, " Failed to CreateFileMapping for %s, error: %X", memoryMappedFileName, errorCode)); + DEBUG_CODE(AppendToCallInfo(debugBuf)); + return errorCode; + } else { + DEBUG_CODE(sprintf(debugBuf, " CreateFileMapping worked - filename: %s\r\n", memoryMappedFileName)); + DEBUG_CODE(AppendToCallInfo(debugBuf)); + } + + memoryMappedView = (char *) MapViewOfFile(memoryMappedFileMapHandle, + FILE_MAP_READ | FILE_MAP_WRITE, + 0, 0, 0); + if (memoryMappedView == NULL) { + errorCode = GetLastError(); + DEBUG_CODE(sprintf(debugBuf, " Failed to MapViewOfFile for %s, error: %X", memoryMappedFileName, errorCode)); + DEBUG_CODE(AppendToCallInfo(debugBuf)); + return errorCode; + } else { + DEBUG_CODE(sprintf(debugBuf, " MapViewOfFile worked - view: %p\r\n", memoryMappedView)); + DEBUG_CODE(AppendToCallInfo(debugBuf)); + } + + + // write some data to the memory mapped file + strcpy(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_QUERY); + + + // inform the JavaDLL that we've a memory mapped file ready for it + char buffer[sizeof(PackageType) + sizeof(MemoryMappedFileCreatedPackage)]; + PackageType *type = (PackageType *) buffer; + MemoryMappedFileCreatedPackage *pkg = (MemoryMappedFileCreatedPackage *) (buffer + sizeof(PackageType)); + *type = cMemoryMappedFileCreatedPackage; + pkg->bridgeWindow = ABHandleToLong(ourAccessBridgeWindow); + strncpy(pkg->filename, memoryMappedFileName, cMemoryMappedNameSize); + sendPackage(buffer, sizeof(buffer)); + + + // look for the JavaDLL's answer to see if it could read the file + if (strcmp(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_ANSWER) != 0) { + DEBUG_CODE(sprintf(debugBuf, " JavaVM failed to deal with memory mapped file %s\r\n", + memoryMappedFileName)); + DEBUG_CODE(AppendToCallInfo(debugBuf)); + return -1; + } else { + DEBUG_CODE(sprintf(debugBuf, " Success! JavaVM accpeted our file\r\n")); + DEBUG_CODE(AppendToCallInfo(debugBuf)); + } + + return 0; +} + +// ----------------------- + +/** + * sendPackage - uses SendMessage(WM_COPYDATA) to do IPC messaging + * with the Java AccessBridge DLL + * + * NOTE: WM_COPYDATA is only for one-way IPC; there + * is now way to return parameters (especially big ones) + * Use sendMemoryPackage() to do that! + */ +LRESULT +AccessBridgeJavaVMInstance::sendPackage(char *buffer, long bufsize) { + COPYDATASTRUCT toCopy; + toCopy.dwData = 0; // 32-bits we could use for something... + toCopy.cbData = bufsize; + toCopy.lpData = buffer; + + PrintDebugString("In AccessBridgeVMInstance::sendPackage"); + PrintDebugString(" javaAccessBridgeWindow: %p", javaAccessBridgeWindow); + /* This was SendMessage. Normally that is a blocking call. However, if + * SendMessage is sent to another process, e.g. another JVM and an incoming + * SendMessage is pending, control will be passed to the DialogProc to handle + * the incoming message. A bug occurred where this allowed an AB_DLL_GOING_AWAY + * message to be processed deleting an AccessBridgeJavaVMInstance object in + * the javaVMs chain. SendMessageTimeout with SMTO_BLOCK set will prevent the + * calling thread from processing other requests while waiting, i.e control + * will not be passed to the DialogProc. Also note that PostMessage or + * SendNotifyMessage can't be used. Although they don't allow transfer to + * the DialogProc they can't be used in cases where pointers are passed. This + * is because the referenced memory needs to be available when the other thread + * gets control. + */ + UINT flags = SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG; + DWORD_PTR out; // not used + LRESULT lr = SendMessageTimeout( javaAccessBridgeWindow, WM_COPYDATA, + (WPARAM)ourAccessBridgeWindow, (LPARAM)&toCopy, + flags, 4000, &out ); + return lr; +} + + +/** + * sendMemoryPackage - uses Memory-Mapped files to do IPC messaging + * with the Java AccessBridge DLL, informing the + * Java AccessBridge DLL via SendMessage that something + * is waiting for it in the shared file... + * + * In the SendMessage call, the third param (WPARAM) is + * the source HWND (ourAccessBridgeWindow in this case), + * and the fourth param (LPARAM) is the size in bytes of + * the package put into shared memory. + * + */ +BOOL +AccessBridgeJavaVMInstance::sendMemoryPackage(char *buffer, long bufsize) { + + // Protect against race condition where the memory mapped file is + // deallocated before the memory package is being sent + if (goingAway) { + return FALSE; + } + BOOL retval = FALSE; + + DEBUG_CODE(char outputBuf[256]); + DEBUG_CODE(sprintf(outputBuf, "AccessBridgeJavaVMInstance::sendMemoryPackage(, %d)", bufsize)); + DEBUG_CODE(AppendToCallInfo(outputBuf)); + + DEBUG_CODE(PackageType *type = (PackageType *) buffer); + DEBUG_CODE(if (*type == cGetAccessibleTextRangePackage) {) + DEBUG_CODE(AppendToCallInfo(" 'buffer' contains:")); + DEBUG_CODE(GetAccessibleTextRangePackage *pkg = (GetAccessibleTextRangePackage *) (buffer + sizeof(PackageType))); + DEBUG_CODE(sprintf(outputBuf, " PackageType = %X", *type)); + DEBUG_CODE(AppendToCallInfo(outputBuf)); + DEBUG_CODE(sprintf(outputBuf, " GetAccessibleTextRange: start = %d, end = %d, rText = %ls", + pkg->start, pkg->end, pkg->rText)); + DEBUG_CODE(AppendToCallInfo(outputBuf)); + DEBUG_CODE(}) + + EnterCriticalSection(&sendMemoryIPCLock); + { + // copy the package into shared memory + if (!goingAway) { + memcpy(memoryMappedView, buffer, bufsize); + + DEBUG_CODE(PackageType *type = (PackageType *) memoryMappedView); + DEBUG_CODE(if (*type == cGetAccessibleTextItemsPackage) {) + DEBUG_CODE(AppendToCallInfo(" 'memoryMappedView' now contains:")); + DEBUG_CODE(GetAccessibleTextItemsPackage *pkg = (GetAccessibleTextItemsPackage *) (buffer + sizeof(PackageType))); + DEBUG_CODE(sprintf(outputBuf, " PackageType = %X", *type)); + DEBUG_CODE(AppendToCallInfo(outputBuf)); + DEBUG_CODE(}) + } + + if (!goingAway) { + // Let the recipient know there is a package waiting for them. The unset byte + // at end of buffer which will only be set if message is properly received + char *done = &memoryMappedView[bufsize]; + *done = 0; + + PrintDebugString(" javaAccessBridgeWindow: %p", javaAccessBridgeWindow); + // See the comment above the call to SendMessageTimeout in SendPackage method above. + UINT flags = SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG; + DWORD_PTR out; // not used + SendMessageTimeout( javaAccessBridgeWindow, AB_MESSAGE_WAITING, (WPARAM)ourAccessBridgeWindow, (LPARAM)bufsize, + flags, 4000, &out ); + + // only succeed if message has been properly received + if(!goingAway) retval = (*done == 1); + } + + // copy the package back from shared memory + if (!goingAway) { + memcpy(buffer, memoryMappedView, bufsize); + } + } + LeaveCriticalSection(&sendMemoryIPCLock); + return retval; +} + + +/** + * findAccessBridgeWindow - walk through linked list from where we are, + * return the HWND of the ABJavaVMInstance that + * matches the passed in vmID; no match: return 0 + * + */ +HWND +AccessBridgeJavaVMInstance::findAccessBridgeWindow(long javaVMID) { + PrintDebugString("In findAccessBridgeWindow"); + // no need to recurse really + if (vmID == javaVMID) { + return javaAccessBridgeWindow; + } else { + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *current = nextJVMInstance; + while (current != (AccessBridgeJavaVMInstance *) 0) { + if (current->vmID == javaVMID) { + isVMInstanceChainInUse = false; + return current->javaAccessBridgeWindow; + } + current = current->nextJVMInstance; + } + isVMInstanceChainInUse = false; + } + return 0; +} + +/** + * findABJavaVMInstanceFromJavaHWND - walk through linked list from + * where we are. Return the + * AccessBridgeJavaVMInstance + * of the ABJavaVMInstance that + * matches the passed in vmID; + * no match: return 0 + */ +AccessBridgeJavaVMInstance * +AccessBridgeJavaVMInstance::findABJavaVMInstanceFromJavaHWND(HWND window) { + PrintDebugString("In findABJavaInstanceFromJavaHWND"); + // no need to recurse really + if (javaAccessBridgeWindow == window) { + return this; + } else { + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *current = nextJVMInstance; + while (current != (AccessBridgeJavaVMInstance *) 0) { + if (current->javaAccessBridgeWindow == window) { + isVMInstanceChainInUse = false; + return current; + } + current = current->nextJVMInstance; + } + } + isVMInstanceChainInUse = false; + return (AccessBridgeJavaVMInstance *) 0; +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeJavaVMInstance.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeJavaVMInstance.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to track key JVM instance info from the AT WinAccessBridge + */ + +#ifndef __AccessBridgeJavaVMInstance_H__ +#define __AccessBridgeJavaVMInstance_H__ + +#include "AccessBridgePackages.h" + +#include +#include + +/** + * The AccessBridgeJavaVMInstance class. + */ +class AccessBridgeJavaVMInstance { + friend class WinAccessBridge; + + AccessBridgeJavaVMInstance *nextJVMInstance; + HWND ourAccessBridgeWindow; + HWND javaAccessBridgeWindow; + long vmID; + + // IPC variables + HANDLE memoryMappedFileMapHandle; // handle to file map + char *memoryMappedView; // ptr to shared memory + char memoryMappedFileName[cMemoryMappedNameSize]; + BOOL goingAway; + + +public: + AccessBridgeJavaVMInstance(HWND ourABWindow, HWND javaABWindow, + long javaVMID, + AccessBridgeJavaVMInstance *next); + ~AccessBridgeJavaVMInstance(); + LRESULT initiateIPC(); + LRESULT sendPackage(char *buffer, long bufsize); + BOOL sendMemoryPackage(char *buffer, long bufsize); + HWND findAccessBridgeWindow(long javaVMID); + AccessBridgeJavaVMInstance *findABJavaVMInstanceFromJavaHWND(HWND window); +}; + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeMessageQueue.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeMessageQueue.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to manage queueing of messages for IPC + */ + +#include "AccessBridgeDebug.h" +#include "AccessBridgeMessageQueue.h" +#include "AccessBridgePackages.h" // for debugging only +#include +#include + +DEBUG_CODE(extern HWND theDialogWindow); +extern "C" { + DEBUG_CODE(void AppendToCallInfo(char *s)); +} + +// ------------------- + + +AccessBridgeQueueElement::AccessBridgeQueueElement(char *buf, int size) { + bufsize = size; + next = (AccessBridgeQueueElement *) 0; + previous = (AccessBridgeQueueElement *) 0; + buffer = (char *) malloc(bufsize); + memcpy(buffer, buf, bufsize); +} + +AccessBridgeQueueElement::~AccessBridgeQueueElement() { + // delete buffer; + free(buffer); +} + + +// ------------------- + + +AccessBridgeMessageQueue::AccessBridgeMessageQueue() { + queueLocked = FALSE; + queueRemoveLocked = FALSE; + start = (AccessBridgeQueueElement *) 0; + end = (AccessBridgeQueueElement *) 0; + size = 0; +} + +AccessBridgeMessageQueue::~AccessBridgeMessageQueue() { + // empty queue, then exit +} + +/** + * getEventsWaiting - gets the number of events waiting to fire + */ +int +AccessBridgeMessageQueue::getEventsWaiting() { + return size; +} + +/** + * add - add an element to the queue, which is locked with semaphores + * + */ +QueueReturns +AccessBridgeMessageQueue::add(AccessBridgeQueueElement *element) { + PrintDebugString(" in AccessBridgeMessageQueue::add()"); + PrintDebugString(" queue size = %d", size); + + QueueReturns returnVal = cElementPushedOK; + if (queueLocked) { + PrintDebugString(" queue was locked; returning cQueueInUse!"); + return cQueueInUse; + } + queueLocked = TRUE; + { + PrintDebugString(" adding element to queue!"); + if (end == (AccessBridgeQueueElement *) 0) { + if (start == (AccessBridgeQueueElement *) 0 && size == 0) { + start = element; + end = element; + element->previous = (AccessBridgeQueueElement *) 0; + element->next = (AccessBridgeQueueElement *) 0; + size++; + } else { + returnVal = cQueueBroken; // bad voodo! + } + } else { + element->previous = end; + element->next = (AccessBridgeQueueElement *) 0; + end->next = element; + end = element; + size++; + } + } + queueLocked = FALSE; + PrintDebugString(" returning from AccessBridgeMessageQueue::add()"); + return returnVal; +} + + +/** + * remove - remove an element from the queue, which is locked with semaphores + * + */ +QueueReturns +AccessBridgeMessageQueue::remove(AccessBridgeQueueElement **element) { + PrintDebugString(" in AccessBridgeMessageQueue::remove()"); + PrintDebugString(" queue size = %d", size); + + QueueReturns returnVal = cMoreMessages; + if (queueLocked) { + PrintDebugString(" queue was locked; returning cQueueInUse!"); + return cQueueInUse; + } + queueLocked = TRUE; + { + PrintDebugString(" removing element from queue!"); + if (size > 0) { + if (start != (AccessBridgeQueueElement *) 0) { + *element = start; + start = start->next; + if (start != (AccessBridgeQueueElement *) 0) { + start->previous = (AccessBridgeQueueElement *) 0; + } else { + end = (AccessBridgeQueueElement *) 0; + if (size != 1) { + returnVal = cQueueBroken; // bad voodo, should only be 1 in this situation + } + } + size--; + } else { + returnVal = cQueueBroken; // bad voodo! + } + } else { + returnVal = cQueueEmpty; + } + } + queueLocked = FALSE; + PrintDebugString(" returning from AccessBridgeMessageQueue::remove()"); + return returnVal; +} + + +/** + * setRemoveLock - set the state of the removeLock (TRUE or FALSE) + * + */ +QueueReturns +AccessBridgeMessageQueue::setRemoveLock(BOOL removeLockSetting) { + if (queueLocked) { + return cQueueInUse; + } + queueRemoveLocked = removeLockSetting; + + return cQueueOK; +} + +/** + * setRemoveLock - set the state of the removeLock (TRUE or FALSE) + * + */ +BOOL +AccessBridgeMessageQueue::getRemoveLockSetting() { + return queueRemoveLocked; +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeMessageQueue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeMessageQueue.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A class to manage queueing of messages for IPC + */ + +#include + +#ifndef __AccessBridgeMessageQueue_H__ +#define __AccessBridgeMessageQueue_H__ + + +enum QueueReturns { + cQueueEmpty = 0, + cMoreMessages = 1, + cQueueInUse, + cElementPushedOK, + cQueueFull, + cQueueOK, + cQueueBroken // shouldn't ever happen! +}; + +class AccessBridgeQueueElement { + friend class AccessBridgeMessageQueue; + friend class WinAccessBridge; + char *buffer; + int bufsize; + AccessBridgeQueueElement *next; + AccessBridgeQueueElement *previous; + +public: + AccessBridgeQueueElement(char *buf, int size); + ~AccessBridgeQueueElement(); +}; + +class AccessBridgeMessageQueue { + BOOL queueLocked; + BOOL queueRemoveLocked; + AccessBridgeQueueElement *start; + AccessBridgeQueueElement *end; + int size; + +public: + AccessBridgeMessageQueue(); + ~AccessBridgeMessageQueue(); + + int getEventsWaiting(); + + QueueReturns add(AccessBridgeQueueElement *element); + QueueReturns remove(AccessBridgeQueueElement **element); + QueueReturns setRemoveLock(BOOL removeLockSetting); + BOOL getRemoveLockSetting(); +}; + + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeWindowsEntryPoints.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeWindowsEntryPoints.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,856 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * Glue routines called by Windows AT into the WindowsAccessBridge dll + */ + +#include "AccessBridgeDebug.h" +#include "AccessBridgeWindowsEntryPoints.h" +#include "WinAccessBridge.h" +#include "accessBridgeResource.h" + +#include +#include + + +extern WinAccessBridge *theWindowsAccessBridge; +extern HWND theDialogWindow; + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Windows_run - where Windows executables will load/unload us + * + */ + void Windows_run() { + // open our window + if (theWindowsAccessBridge != (WinAccessBridge *) 0) { + theWindowsAccessBridge->initWindow(); + DEBUG_CODE(SetDlgItemText(theDialogWindow, cInvokedByText, "Windows")); + } + } + + /* + /** + * Windows_shutdown - where Windows executables will load/unload us + * + * + void Windows_shutdown() { + if (theWindowsAccessBridge != (WinAccessBridge *) 0) { + theWindowsAccessBridge->initWindow(); + } + } + */ + + /** + * getTopLevelHWND - returns the top-level window parent of the descendent + * + */ + HWND getTopLevelHWND(HWND descendent) { + HWND hwnd; + if (descendent == NULL) { + return NULL; + } + + if (!IsWindow(descendent)) { + return NULL; + } + + hwnd = descendent; + for(;;) { + LONG style = GetWindowLong(hwnd, GWL_STYLE); + if ( (style & WS_CHILD) == 0 ) { + // found a non-child window so terminate + break; + } + hwnd = GetParent(hwnd); + } + + return hwnd; + } + + void releaseJavaObject(long vmID, JOBJECT64 object) { + if (theWindowsAccessBridge != 0) { + theWindowsAccessBridge->releaseJavaObject(vmID, object); + } + } + + void getVersionInfo(long vmID, AccessBridgeVersionInfo *info) { + if (theWindowsAccessBridge != 0) { + theWindowsAccessBridge->getVersionInfo(vmID, info); + } + } + + + BOOL isJavaWindow(HWND window) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->isJavaWindow(window); + } + return FALSE; + } + + /* + * Returns whether two object references refer to the same object + */ + BOOL isSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2) { +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("\r\nAccessBridgeWindowsEntryPoints::isSameObject(%p %p)", obj1, obj2); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("\r\nAccessBridgeWindowsEntryPoints::isSameObject(%016I64X %016I64X)", obj1, obj2); +#endif + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->isSameObject(vmID, obj1, obj2); + } + return FALSE; + } + + /** + * Sets a text field to the specified string. Returns whether successful + */ + BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext,const wchar_t *text) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->setTextContents(vmID, accessibleContext, text); + } + return FALSE; + } + + /** + * Returns the Accessible Context of an object of the specified role that is the + * ancestor of a given object. If the object is of the specified role + * or an ancestor object of the specified role was found, returns the object's + * AccessibleContext. + * If there is no ancestor object of the specified role, + * returns (AccessibleContext)0. + */ + AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext, const wchar_t *role) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getParentWithRole(vmID, accessibleContext, role); + } + return (AccessibleContext)0; + } + + + /** + * Returns the Accessible Context for the top level object in + * a Java Window. This is same Accessible Context that is obtained + * from GetAccessibleContextFromHWND for that window. Returns + * (AccessibleContext)0 on error. + */ + AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getTopLevelObject(vmID, accessibleContext); + } + return (AccessibleContext)0; + } + + /** + * If there is an Ancestor object of the specified role, + * returns the Accessible Context of the found object. + * Otherwise, returns the top level object for that + * Java Window. Returns (AccessibleContext)0 on error. + */ + AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext, const wchar_t *role) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getParentWithRoleElseRoot(vmID, accessibleContext, role); + } + return (AccessibleContext)0; + } + + /** + * Returns how deep in the object hierarchy a given object is. + * The top most object in the object hierarchy has an object depth of 0. + * Returns -1 on error. + */ + int getObjectDepth (const long vmID, const AccessibleContext accessibleContext) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getObjectDepth(vmID, accessibleContext); + } + return -1; + } + + /** + * Returns the Accessible Context of the currently ActiveDescendent of an object. + * Returns (AccessibleContext)0 on error. + */ + AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getActiveDescendent(vmID, accessibleContext); + } + return (AccessibleContext)0; + } + + // -------- Accessible Context methods ------------- + + BOOL getAccessibleContextFromHWND(HWND window, long *vmID, JOBJECT64 *AccessibleContext) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleContextFromHWND(window, vmID, AccessibleContext); + } + return FALSE; + } + + HWND getHWNDFromAccessibleContext(long vmID, JOBJECT64 accessibleContext) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getHWNDFromAccessibleContext(vmID, accessibleContext); + } + return (HWND)0; + } + + BOOL getAccessibleContextAt(long vmID, JOBJECT64 AccessibleContextParent, + jint x, jint y, JOBJECT64 *AccessibleContext) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleContextAt(vmID, AccessibleContextParent, + x, y, AccessibleContext); + } + return FALSE; + } + + BOOL getAccessibleContextWithFocus(HWND window, long *vmID, JOBJECT64 *AccessibleContext) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleContextWithFocus(window, vmID, AccessibleContext); + } + return FALSE; + } + + BOOL getAccessibleContextInfo(long vmID, + JOBJECT64 AccessibleContext, + AccessibleContextInfo *info) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleContextInfo( + vmID, + AccessibleContext, + info); + } + return FALSE; + } + + JOBJECT64 getAccessibleChildFromContext(long vmID, + JOBJECT64 AccessibleContext, + jint childIndex) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleChildFromContext( + vmID, + AccessibleContext, + childIndex); + } + return (JOBJECT64) 0; + } + + JOBJECT64 getAccessibleParentFromContext(long vmID, + JOBJECT64 AccessibleContext) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleParentFromContext( + vmID, + AccessibleContext); + } + return (JOBJECT64) 0; + } + + // -------- begin AccessibleTable routines ------------- + + BOOL getAccessibleTableInfo(long vmID, JOBJECT64 ac, + AccessibleTableInfo *tableInfo) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTableInfo( + vmID, + ac, + tableInfo); + } + return FALSE; + } + + BOOL getAccessibleTableCellInfo(long vmID, JOBJECT64 accessibleTable, + jint row, jint column, AccessibleTableCellInfo *tableCellInfo) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTableCellInfo( + vmID, + accessibleTable, + row, column, tableCellInfo); + } + return FALSE; + } + + BOOL getAccessibleTableRowHeader(long vmID, JOBJECT64 acParent, AccessibleTableInfo *tableInfo) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTableRowHeader( + vmID, + acParent, + tableInfo); + } + return FALSE; + } + + BOOL getAccessibleTableColumnHeader(long vmID, JOBJECT64 acParent, AccessibleTableInfo *tableInfo) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTableColumnHeader( + vmID, + acParent, + tableInfo); + } + return FALSE; + } + + JOBJECT64 getAccessibleTableRowDescription(long vmID, JOBJECT64 acParent, jint row) { + + if (theWindowsAccessBridge != 0) { + return (JOBJECT64)theWindowsAccessBridge->getAccessibleTableRowDescription( + vmID, + acParent, + row); + } + return (JOBJECT64)0; + } + + JOBJECT64 getAccessibleTableColumnDescription(long vmID, JOBJECT64 acParent, jint column) { + + if (theWindowsAccessBridge != 0) { + return (JOBJECT64)theWindowsAccessBridge->getAccessibleTableColumnDescription( + vmID, + acParent, + column); + } + return (JOBJECT64)0; + } + + jint getAccessibleTableRowSelectionCount(long vmID, JOBJECT64 accessibleTable) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTableRowSelectionCount(vmID, accessibleTable); + } + return -1; + } + + BOOL isAccessibleTableRowSelected(long vmID, JOBJECT64 accessibleTable, jint row) { + if (theWindowsAccessBridge != 0 ) { + return theWindowsAccessBridge->isAccessibleTableRowSelected(vmID, accessibleTable, row); + } + return FALSE; + } + + BOOL getAccessibleTableRowSelections(long vmID, JOBJECT64 accessibleTable, jint count, jint *selections) { + if (theWindowsAccessBridge != 0 ) { + return theWindowsAccessBridge->getAccessibleTableRowSelections(vmID, accessibleTable, count, + selections); + } + return FALSE; + } + + + jint getAccessibleTableColumnSelectionCount(long vmID, JOBJECT64 accessibleTable) { + if (theWindowsAccessBridge != 0 ) { + return theWindowsAccessBridge->getAccessibleTableColumnSelectionCount(vmID, accessibleTable); + } + return -1; + } + + BOOL isAccessibleTableColumnSelected(long vmID, JOBJECT64 accessibleTable, jint column) { + if (theWindowsAccessBridge != 0 ) { + return theWindowsAccessBridge->isAccessibleTableColumnSelected(vmID, accessibleTable, column); + } + return FALSE; + } + + BOOL getAccessibleTableColumnSelections(long vmID, JOBJECT64 accessibleTable, jint count, jint *selections) { + if (theWindowsAccessBridge != 0 ) { + return theWindowsAccessBridge->getAccessibleTableColumnSelections(vmID, accessibleTable, count, + selections); + } + return FALSE; + } + + jint getAccessibleTableRow(long vmID, JOBJECT64 accessibleTable, jint index) { + if (theWindowsAccessBridge != 0 ) { + return theWindowsAccessBridge->getAccessibleTableRow(vmID, accessibleTable, index); + } + return -1; + } + + jint getAccessibleTableColumn(long vmID, JOBJECT64 accessibleTable, jint index) { + if (theWindowsAccessBridge != 0 ) { + return theWindowsAccessBridge->getAccessibleTableColumn(vmID, accessibleTable, index); + } + return -1; + } + + jint getAccessibleTableIndex(long vmID, JOBJECT64 accessibleTable, jint row, jint column) { + if (theWindowsAccessBridge != 0 ) { + return theWindowsAccessBridge->getAccessibleTableIndex(vmID, accessibleTable, row, column); + } + return -1; + } + + /* --------- end AccessibleTable routines ------- */ + + // --------- AccessibleRelationSet methods + + BOOL getAccessibleRelationSet(long vmID, JOBJECT64 accessibleContext, + AccessibleRelationSetInfo *relationSetInfo) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleRelationSet(vmID, accessibleContext, relationSetInfo); + } + return FALSE; + } + + // --------- AccessibleHypertext methods + + BOOL getAccessibleHypertext(long vmID, JOBJECT64 accessibleContext, + AccessibleHypertextInfo *accessibleHypertextInfo) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleHypertext(vmID, accessibleContext, + accessibleHypertextInfo); + } + return FALSE; + } + + BOOL activateAccessibleHyperlink(long vmID, JOBJECT64 accessibleContext, JOBJECT64 accessibleHyperlink) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->activateAccessibleHyperlink(vmID, accessibleContext, + accessibleHyperlink); + } + return FALSE; + } + + jint getAccessibleHyperlinkCount(const long vmID, + const AccessibleContext accessibleContext) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleHyperlinkCount(vmID, accessibleContext); + } + return -1; + } + + + BOOL getAccessibleHypertextExt(const long vmID, + const AccessibleContext accessibleContext, + const jint nStartIndex, + /* OUT */ AccessibleHypertextInfo *hypertextInfo) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleHypertextExt(vmID, + accessibleContext, + nStartIndex, + hypertextInfo); + } + return FALSE; + } + + + jint getAccessibleHypertextLinkIndex(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleHypertextLinkIndex(vmID, + hypertext, + nIndex); + } + return -1; + } + + + BOOL getAccessibleHyperlink(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex, + /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleHyperlink(vmID, + hypertext, + nIndex, + hyperlinkInfo); + } + return FALSE; + } + + + /* Accessible KeyBindings, Icons and Actions */ + BOOL getAccessibleKeyBindings(long vmID, JOBJECT64 accessibleContext, AccessibleKeyBindings *keyBindings) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleKeyBindings(vmID, accessibleContext, keyBindings); + } + return FALSE; + } + + BOOL getAccessibleIcons(long vmID, JOBJECT64 accessibleContext, AccessibleIcons *icons) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleIcons(vmID, accessibleContext, icons); + } + return FALSE; + } + + BOOL getAccessibleActions(long vmID, JOBJECT64 accessibleContext, AccessibleActions *actions) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleActions(vmID, accessibleContext, actions); + } + return FALSE; + } + + BOOL doAccessibleActions(long vmID, JOBJECT64 accessibleContext, AccessibleActionsToDo *actionsToDo, + jint *failure) { + + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->doAccessibleActions(vmID, accessibleContext, actionsToDo, + failure); + } + return FALSE; + } + + /** + * Additional methods for Teton + */ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + BOOL getVirtualAccessibleName(long vmID, AccessibleContext accessibleContext, wchar_t *name, int len) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getVirtualAccessibleName(vmID, accessibleContext, name, len); + } + return FALSE; + } + + /** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ + BOOL requestFocus(long vmID, AccessibleContext accessibleContext) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->requestFocus(vmID, accessibleContext); + } + return FALSE; + } + + /** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ + BOOL selectTextRange(long vmID, AccessibleContext accessibleContext, int startIndex, int endIndex) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->selectTextRange(vmID, accessibleContext, startIndex, endIndex); + } + return FALSE; + } + + /** + * Get text attributes between two indices. The attribute list includes the text at the + * start index and the text at the end index. Returns whether successful; + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + BOOL getTextAttributesInRange(long vmID, AccessibleContext accessibleContext, int startIndex, int endIndex, + AccessibleTextAttributesInfo *attributes, short *len) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getTextAttributesInRange(vmID, accessibleContext, + startIndex, endIndex, attributes, len); + } + return FALSE; + } + + /** + * Gets the number of visible children of a component. Returns -1 on error. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + int getVisibleChildrenCount(long vmID, AccessibleContext accessibleContext) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getVisibleChildrenCount(vmID, accessibleContext); + } + return FALSE; + } + + /** + * Gets the visible children of an AccessibleContext. Returns whether successful; + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + BOOL getVisibleChildren(long vmID, AccessibleContext accessibleContext, int startIndex, + VisibleChildrenInfo *visibleChildrenInfo) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getVisibleChildren(vmID, accessibleContext, startIndex, + visibleChildrenInfo); + } + return FALSE; + } + + /** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ + BOOL setCaretPosition(const long vmID, const AccessibleContext accessibleContext, + const int position) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->setCaretPosition(vmID, accessibleContext, position); + } + return FALSE; + } + + // -------- Accessible Text methods ------------- + + BOOL getAccessibleTextInfo(long vmID, JOBJECT64 AccessibleContext, + AccessibleTextInfo *textInfo, jint x, jint y) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTextInfo( + vmID, + AccessibleContext, + textInfo, x, y); + } + return FALSE; + } + + BOOL getAccessibleTextItems(long vmID, JOBJECT64 AccessibleContext, + AccessibleTextItemsInfo *textItems, jint index) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTextItems( + vmID, + AccessibleContext, + textItems, index); + } + return FALSE; + } + + BOOL getAccessibleTextSelectionInfo(long vmID, JOBJECT64 AccessibleContext, + AccessibleTextSelectionInfo *selectionInfo) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTextSelectionInfo( + vmID, + AccessibleContext, + selectionInfo); + } + return FALSE; + } + + BOOL getAccessibleTextAttributes(long vmID, JOBJECT64 AccessibleContext, + jint index, AccessibleTextAttributesInfo *attributes) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTextAttributes( + vmID, + AccessibleContext, + index, attributes); + } + return FALSE; + } + + BOOL getAccessibleTextRect(long vmID, JOBJECT64 AccessibleContext, + AccessibleTextRectInfo *rectInfo, jint index) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTextRect( + vmID, + AccessibleContext, + rectInfo, index); + } + return FALSE; + } + + BOOL getCaretLocation(long vmID, JOBJECT64 AccessibleContext, + AccessibleTextRectInfo *rectInfo, jint index) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getCaretLocation(vmID, + AccessibleContext, + rectInfo, index); + } + return FALSE; + } + + int getEventsWaiting() { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getEventsWaiting(); + } + return FALSE; + } + + BOOL getAccessibleTextLineBounds(long vmID, JOBJECT64 AccessibleContext, + jint index, jint *startIndex, jint *endIndex) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTextLineBounds( + vmID, + AccessibleContext, + index, startIndex, endIndex); + } + return FALSE; + } + + BOOL getAccessibleTextRange(long vmID, JOBJECT64 AccessibleContext, + jint start, jint end, wchar_t *text, short len) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleTextRange( + vmID, + AccessibleContext, + start, end, text, len); + } + return FALSE; + } + + + // -------- Accessible Value methods ------------- + + BOOL getCurrentAccessibleValueFromContext(long vmID, JOBJECT64 AccessibleContext, + wchar_t *value, short len) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getCurrentAccessibleValueFromContext( + vmID, AccessibleContext, value, len); + } + return FALSE; + } + + BOOL getMaximumAccessibleValueFromContext(long vmID, JOBJECT64 AccessibleContext, + wchar_t *value, short len) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getMaximumAccessibleValueFromContext( + vmID, AccessibleContext, value, len); + } + return FALSE; + } + + BOOL getMinimumAccessibleValueFromContext(long vmID, JOBJECT64 AccessibleContext, + wchar_t *value, short len) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getMinimumAccessibleValueFromContext( + vmID, AccessibleContext, value, len); + } + return FALSE; + } + + // -------- Accessible Selection methods ------------- + + void addAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext, int i) { + if (theWindowsAccessBridge != 0) { + theWindowsAccessBridge->addAccessibleSelectionFromContext( + vmID, AccessibleContext, i); + } + } + + void clearAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext) { + if (theWindowsAccessBridge != 0) { + theWindowsAccessBridge->clearAccessibleSelectionFromContext( + vmID, AccessibleContext); + } + } + + JOBJECT64 getAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext, int i) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleSelectionFromContext( + vmID, AccessibleContext, i); + } + return (JOBJECT64) 0; + } + + int getAccessibleSelectionCountFromContext(long vmID, JOBJECT64 AccessibleContext) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->getAccessibleSelectionCountFromContext( + vmID, AccessibleContext); + } + return -1; + } + + BOOL isAccessibleChildSelectedFromContext(long vmID, JOBJECT64 AccessibleContext, int i) { + if (theWindowsAccessBridge != 0) { + return theWindowsAccessBridge->isAccessibleChildSelectedFromContext( + vmID, AccessibleContext, i); + } + return FALSE; + } + + void removeAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext, int i) { + if (theWindowsAccessBridge != 0) { + theWindowsAccessBridge->removeAccessibleSelectionFromContext( + vmID, AccessibleContext, i); + } + } + + void selectAllAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext) { + if (theWindowsAccessBridge != 0) { + theWindowsAccessBridge->selectAllAccessibleSelectionFromContext( + vmID, AccessibleContext); + } + } + + + // -------- Event Handler methods ------------- + +#define SET_EVENT_FP(function, callbackFP) \ + void function(callbackFP fp) { \ + if (theWindowsAccessBridge != 0) { \ + theWindowsAccessBridge->function(fp); \ + } \ +} + + void setJavaShutdownFP(AccessBridge_JavaShutdownFP fp) { + if (theWindowsAccessBridge != 0) { + theWindowsAccessBridge->setJavaShutdownFP(fp); + } + } + + SET_EVENT_FP(setPropertyChangeFP, AccessBridge_PropertyChangeFP) + SET_EVENT_FP(setFocusGainedFP, AccessBridge_FocusGainedFP) + SET_EVENT_FP(setFocusLostFP, AccessBridge_FocusLostFP) + SET_EVENT_FP(setCaretUpdateFP, AccessBridge_CaretUpdateFP) + SET_EVENT_FP(setMouseClickedFP, AccessBridge_MouseClickedFP) + SET_EVENT_FP(setMouseEnteredFP, AccessBridge_MouseEnteredFP) + SET_EVENT_FP(setMouseExitedFP, AccessBridge_MouseExitedFP) + SET_EVENT_FP(setMousePressedFP, AccessBridge_MousePressedFP) + SET_EVENT_FP(setMouseReleasedFP, AccessBridge_MouseReleasedFP) + SET_EVENT_FP(setMenuCanceledFP, AccessBridge_MenuCanceledFP) + SET_EVENT_FP(setMenuDeselectedFP, AccessBridge_MenuDeselectedFP) + SET_EVENT_FP(setMenuSelectedFP, AccessBridge_MenuSelectedFP) + SET_EVENT_FP(setPopupMenuCanceledFP, AccessBridge_PopupMenuCanceledFP) + SET_EVENT_FP(setPopupMenuWillBecomeInvisibleFP, AccessBridge_PopupMenuWillBecomeInvisibleFP) + SET_EVENT_FP(setPopupMenuWillBecomeVisibleFP, AccessBridge_PopupMenuWillBecomeVisibleFP) + + SET_EVENT_FP(setPropertyNameChangeFP, AccessBridge_PropertyNameChangeFP) + SET_EVENT_FP(setPropertyDescriptionChangeFP, AccessBridge_PropertyDescriptionChangeFP) + SET_EVENT_FP(setPropertyStateChangeFP, AccessBridge_PropertyStateChangeFP) + SET_EVENT_FP(setPropertyValueChangeFP, AccessBridge_PropertyValueChangeFP) + SET_EVENT_FP(setPropertySelectionChangeFP, AccessBridge_PropertySelectionChangeFP) + SET_EVENT_FP(setPropertyTextChangeFP, AccessBridge_PropertyTextChangeFP) + SET_EVENT_FP(setPropertyCaretChangeFP, AccessBridge_PropertyCaretChangeFP) + SET_EVENT_FP(setPropertyVisibleDataChangeFP, AccessBridge_PropertyVisibleDataChangeFP) + SET_EVENT_FP(setPropertyChildChangeFP, AccessBridge_PropertyChildChangeFP) + SET_EVENT_FP(setPropertyActiveDescendentChangeFP, AccessBridge_PropertyActiveDescendentChangeFP) + + SET_EVENT_FP(setPropertyTableModelChangeFP, AccessBridge_PropertyTableModelChangeFP) + +#ifdef __cplusplus + } +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeWindowsEntryPoints.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/AccessBridgeWindowsEntryPoints.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * Glue routines called by Windows AT into the WindowsAccessBridge dll + */ + +#ifndef __AccessBridgeWindowsEntryPoints_H__ +#define __AccessBridgeWindowsEntryPoints_H__ + +#include +#include + +#include "AccessBridgePackages.h" +#include "AccessBridgeCallbacks.h" + +#ifdef __cplusplus +extern "C" { +#endif + + void Windows_run(); + + void releaseJavaObject(long vmID, JOBJECT64 object); + void getVersionInfo(long vmID, AccessBridgeVersionInfo *info); + + // Window related functions + HWND getTopLevelHWND(HWND descendent); + BOOL isJavaWindow(HWND window); + BOOL getAccessibleContextFromHWND(HWND window, long *vmID, JOBJECT64 *AccessibleContext); + HWND getHWNDFromAccessibleContext(long vmID, JOBJECT64 accessibleContext); + + // returns whether two objects are the same + BOOL isSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2); + + // Accessible Context functions + BOOL getAccessibleContextAt(long vmID, JOBJECT64 AccessibleContextParent, + jint x, jint y, JOBJECT64 *AccessibleContext); + BOOL getAccessibleContextWithFocus(HWND window, long *vmID, JOBJECT64 *AccessibleContext); + BOOL getAccessibleContextInfo(long vmID, JOBJECT64 AccessibleContext, AccessibleContextInfo *info); + JOBJECT64 getAccessibleChildFromContext(long vmID, JOBJECT64 AccessibleContext, jint childIndex); + JOBJECT64 getAccessibleParentFromContext(long vmID, JOBJECT64 AccessibleContext); + + /* begin AccessibleTable */ + BOOL getAccessibleTableInfo(long vmID, JOBJECT64 acParent, AccessibleTableInfo *tableInfo); + BOOL getAccessibleTableCellInfo(long vmID, JOBJECT64 accessibleTable, jint row, jint column, + AccessibleTableCellInfo *tableCellInfo); + + BOOL getAccessibleTableRowHeader(long vmID, JOBJECT64 acParent, AccessibleTableInfo *tableInfo); + BOOL getAccessibleTableColumnHeader(long vmID, JOBJECT64 acParent, AccessibleTableInfo *tableInfo); + + JOBJECT64 getAccessibleTableRowDescription(long vmID, JOBJECT64 acParent, jint row); + JOBJECT64 getAccessibleTableColumnDescription(long vmID, JOBJECT64 acParent, jint column); + + jint getAccessibleTableRowSelectionCount(long vmID, JOBJECT64 accessibleTable); + BOOL isAccessibleTableRowSelected(long vmID, JOBJECT64 accessibleTable, jint row); + BOOL getAccessibleTableRowSelections(long vmID, JOBJECT64 accessibleTable, jint count, + jint *selections); + + jint getAccessibleTableColumnSelectionCount(long vmID, JOBJECT64 accessibleTable); + BOOL isAccessibleTableColumnSelected(long vmID, JOBJECT64 accessibleTable, jint column); + BOOL getAccessibleTableColumnSelections(long vmID, JOBJECT64 accessibleTable, jint count, + jint *selections); + + jint getAccessibleTableRow(long vmID, JOBJECT64 accessibleTable, jint index); + jint getAccessibleTableColumn(long vmID, JOBJECT64 accessibleTable, jint index); + jint getAccessibleTableIndex(long vmID, JOBJECT64 accessibleTable, jint row, jint column); + + /* end AccessibleTable */ + + BOOL getAccessibleRelationSet(long vmID, JOBJECT64 accessibleContext, + AccessibleRelationSetInfo *relationSetInfo); + + // AccessibleHypertext methods + BOOL getAccessibleHypertext(long vmID, JOBJECT64 accessibleContext, AccessibleHypertextInfo *hypertextInfo); + + BOOL activateAccessibleHyperlink(long vmID, JOBJECT64 accessibleContext, JOBJECT64 accessibleHyperlink); + + jint getAccessibleHyperlinkCount(const long vmID, + const AccessibleContext accessibleContext); + + BOOL getAccessibleHypertextExt(const long vmID, + const AccessibleContext accessibleContext, + const jint nStartIndex, + /* OUT */ AccessibleHypertextInfo *hypertextInfo); + + jint getAccessibleHypertextLinkIndex(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex); + + BOOL getAccessibleHyperlink(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex, + /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo); + + + /* Accessible KeyBindings, Icons and Actions */ + BOOL getAccessibleKeyBindings(long vmID, JOBJECT64 accessibleContext, + AccessibleKeyBindings *keyBindings); + + BOOL getAccessibleIcons(long vmID, JOBJECT64 accessibleContext, + AccessibleIcons *icons); + + BOOL getAccessibleActions(long vmID, JOBJECT64 accessibleContext, + AccessibleActions *actions); + + BOOL doAccessibleActions(long vmID, JOBJECT64 accessibleContext, + AccessibleActionsToDo *actionsToDo, jint *failure); + + /* ----- Additional AccessibleHypertext methods for Teton */ + + + jint getAccessibleHypertextLinkCount(const long vmID, + const AccessibleContext accessibleContext); + + BOOL getAccessibleHypertextExt(const long vmID, + const AccessibleContext accessibleContext, + const jint nStartIndex, + /* OUT */ AccessibleHypertextInfo *hypertextInfo); + + jint getAccessibleHypertextLinkIndex(const long vmID, + const AccessibleContext accessibleContext, + const jint nIndex); + + BOOL getAccessibleHyperlink(const long vmID, + const AccessibleContext accessibleContext, + const jint nIndex, + /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo); + + + /* Additional utility methods */ + BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text); + + AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext, const wchar_t *role); + + AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext); + + AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext, const wchar_t *role); + + int getObjectDepth (const long vmID, const AccessibleContext accessibleContext); + + AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext); + + /** + * Additional methods for Teton + */ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + BOOL getVirtualAccessibleName(long vmID, AccessibleContext accessibleContext, wchar_t *name, int len); + + /** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ + BOOL requestFocus(long vmID, AccessibleContext accessibleContext); + + /** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ + BOOL selectTextRange(long vmID, AccessibleContext accessibleContext, int startIndex, int endIndex); + + /** + * Get text attributes between two indices. The attribute list includes the text at the + * start index and the text at the end index. Returns whether successful; + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + BOOL getTextAttributesInRange(long vmID, AccessibleContext accessibleContext, int startIndex, int endIndex, + AccessibleTextAttributesInfo *attributes, short *len); + + /** + * Returns the number of visible children of a component. Returns -1 on error. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + int getVisibleChildrenCount(long vmID, AccessibleContext accessibleContext); + + /** + * Gets the visible children of an AccessibleContext. Returns whether successful; + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + BOOL getVisibleChildren(long vmID, AccessibleContext accessibleContext, int startIndex, + VisibleChildrenInfo *visibleChildrenInfo); + + /** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ + BOOL setCaretPosition(long vmID, AccessibleContext accessibleContext, int position); + + /** + * Gets the text caret bounding rectangle + */ + BOOL getCaretLocation(long vmID, JOBJECT64 AccessibleContext, AccessibleTextRectInfo *rectInfo, jint index); + + // Accessible Text functions + BOOL getAccessibleTextInfo(long vmID, JOBJECT64 AccessibleContext, AccessibleTextInfo *textInfo, jint x, jint y); + BOOL getAccessibleTextItems(long vmID, JOBJECT64 AccessibleContext, AccessibleTextItemsInfo *textItems, jint index); + BOOL getAccessibleTextSelectionInfo(long vmID, JOBJECT64 AccessibleContext, AccessibleTextSelectionInfo *selectionInfo); + BOOL getAccessibleTextAttributes(long vmID, JOBJECT64 AccessibleContext, jint index, AccessibleTextAttributesInfo *attributes); + BOOL getAccessibleTextRect(long vmID, JOBJECT64 AccessibleContext, AccessibleTextRectInfo *rectInfo, jint index); + BOOL getAccessibleTextLineBounds(long vmID, JOBJECT64 AccessibleContext, jint index, jint *startIndex, jint *endIndex); + BOOL getAccessibleTextRange(long vmID, JOBJECT64 AccessibleContext, jint start, jint end, wchar_t *text, short len); + + // Accessible Value methods + BOOL getCurrentAccessibleValueFromContext(long vmID,JOBJECT64 AccessibleContext, wchar_t *value, short len); + BOOL getMaximumAccessibleValueFromContext(long vmID,JOBJECT64 AccessibleContext, wchar_t *value, short len); + BOOL getMinimumAccessibleValueFromContext(long vmID,JOBJECT64 AccessibleContext, wchar_t *value, short len); + + // Accessible Selection methods + void addAccessibleSelectionFromContext(long vmID,JOBJECT64 AccessibleContext, int i); + void clearAccessibleSelectionFromContext(long vmID,JOBJECT64 AccessibleContext); + JOBJECT64 getAccessibleSelectionFromContext(long vmID,JOBJECT64 AccessibleContext, int i); + int getAccessibleSelectionCountFromContext(long vmID,JOBJECT64 AccessibleContext); + BOOL isAccessibleChildSelectedFromContext(long vmID,JOBJECT64 AccessibleContext, int i); + void removeAccessibleSelectionFromContext(long vmID,JOBJECT64 AccessibleContext, int i); + void selectAllAccessibleSelectionFromContext(long vmID,JOBJECT64 AccessibleContext); + + + // PropertyChange Event registry routines + void setPropertyChangeFP(AccessBridge_PropertyChangeFP fp); + + // Java application shutdown + void setJavaShutdownFP(AccessBridge_JavaShutdownFP fp); + + // Focus Event registry routines + void setFocusGainedFP(AccessBridge_FocusGainedFP fp); + void setFocusLostFP(AccessBridge_FocusLostFP fp); + + // Caret Event registry routines + void setCaretUpdateFP(AccessBridge_CaretUpdateFP fp); + + // Mouse Event registry routines + void setMouseClickedFP(AccessBridge_MouseClickedFP fp); + void setMouseEnteredFP(AccessBridge_MouseEnteredFP fp); + void setMouseExitedFP(AccessBridge_MouseExitedFP fp); + void setMousePressedFP(AccessBridge_MousePressedFP fp); + void setMouseReleasedFP(AccessBridge_MouseReleasedFP fp); + + // Menu/PopupMenu Event registry routines + void setMenuCanceledFP(AccessBridge_MenuCanceledFP fp); + void setMenuDeselectedFP(AccessBridge_MenuDeselectedFP fp); + void setMenuSelectedFP(AccessBridge_MenuSelectedFP fp); + void setPopupMenuCanceledFP(AccessBridge_PopupMenuCanceledFP fp); + void setPopupMenuWillBecomeInvisibleFP(AccessBridge_PopupMenuWillBecomeInvisibleFP fp); + void setPopupMenuWillBecomeVisibleFP(AccessBridge_PopupMenuWillBecomeVisibleFP fp); + + // Accessibility PropertyChange Event registry routines + void setPropertyNameChangeFP(AccessBridge_PropertyNameChangeFP fp); + void setPropertyDescriptionChangeFP(AccessBridge_PropertyDescriptionChangeFP fp); + void setPropertyStateChangeFP(AccessBridge_PropertyStateChangeFP fp); + void setPropertyValueChangeFP(AccessBridge_PropertyValueChangeFP fp); + void setPropertySelectionChangeFP(AccessBridge_PropertySelectionChangeFP fp); + void setPropertyTextChangeFP(AccessBridge_PropertyTextChangeFP fp); + void setPropertyCaretChangeFP(AccessBridge_PropertyCaretChangeFP fp); + void setPropertyVisibleDataChangeFP(AccessBridge_PropertyVisibleDataChangeFP fp); + void setPropertyChildChangeFP(AccessBridge_PropertyChildChangeFP fp); + void setPropertyActiveDescendentChangeFP(AccessBridge_PropertyActiveDescendentChangeFP fp); + + void setPropertyTableModelChangeFP(AccessBridge_PropertyTableModelChangeFP fp); + + + +#ifdef __cplusplus +} +#endif + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.DEF --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.DEF Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,154 @@ +; +; Copyright (c) 2005, 2015, 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. +; +; +;LIBRARY WINDOWSACCESSBRIDGE + +;DESCRIPTION 'WINDOWSACCESSBRIDGE.DLL' +HEAPSIZE 4096 +EXPORTS + + addJavaEventNotification + removeJavaEventNotification + addAccessibilityEventNotification + removeAccessibilityEventNotification + + Windows_run + + getAccessibleTableInfo + getAccessibleTableCellInfo + + getAccessibleTableRowHeader + getAccessibleTableColumnHeader + + getAccessibleTableRowDescription + getAccessibleTableColumnDescription + + isAccessibleTableRowSelected + isAccessibleTableColumnSelected + + getAccessibleTableColumnSelectionCount + getAccessibleTableRowSelectionCount + + getAccessibleTableColumnSelections + getAccessibleTableRowSelections + + getAccessibleTableRow + getAccessibleTableColumn + getAccessibleTableIndex + + getAccessibleRelationSet + + getAccessibleHypertext + activateAccessibleHyperlink + getAccessibleHyperlinkCount + getAccessibleHypertextExt + getAccessibleHypertextLinkIndex + getAccessibleHyperlink + + getAccessibleKeyBindings + getAccessibleIcons + getAccessibleActions + doAccessibleActions + + setTextContents + getParentWithRole + getParentWithRoleElseRoot + getTopLevelObject + getObjectDepth + getActiveDescendent + + getVirtualAccessibleName + requestFocus + selectTextRange + getTextAttributesInRange + getVisibleChildrenCount + getVisibleChildren + setCaretPosition + getCaretLocation + + getEventsWaiting + + releaseJavaObject + getVersionInfo + + isJavaWindow + isSameObject + getAccessibleContextFromHWND + getHWNDFromAccessibleContext + + getAccessibleContextAt + getAccessibleContextWithFocus + getAccessibleContextInfo + getAccessibleChildFromContext + getAccessibleParentFromContext + + getAccessibleTextInfo + getAccessibleTextItems + getAccessibleTextSelectionInfo + getAccessibleTextAttributes + getAccessibleTextRect + getAccessibleTextLineBounds + getAccessibleTextRange + + getCurrentAccessibleValueFromContext + getMaximumAccessibleValueFromContext + getMinimumAccessibleValueFromContext + + addAccessibleSelectionFromContext + clearAccessibleSelectionFromContext + getAccessibleSelectionFromContext + getAccessibleSelectionCountFromContext + isAccessibleChildSelectedFromContext + removeAccessibleSelectionFromContext + selectAllAccessibleSelectionFromContext + + setPropertyChangeFP + setJavaShutdownFP + setFocusGainedFP + setFocusLostFP + setCaretUpdateFP + setMouseClickedFP + setMouseEnteredFP + setMouseExitedFP + setMousePressedFP + setMouseReleasedFP + setMenuCanceledFP + setMenuDeselectedFP + setMenuSelectedFP + setPopupMenuCanceledFP + setPopupMenuWillBecomeInvisibleFP + setPopupMenuWillBecomeVisibleFP + + setPropertyNameChangeFP + setPropertyDescriptionChangeFP + setPropertyStateChangeFP + setPropertyValueChangeFP + setPropertySelectionChangeFP + setPropertyTextChangeFP + setPropertyCaretChangeFP + setPropertyVisibleDataChangeFP + setPropertyChildChangeFP + setPropertyActiveDescendentChangeFP + setPropertyTableModelChangeFP diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.cpp Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,3503 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A DLL which is loaded by Windows executables to handle communication + * between Java VMs purposes of Accessbility. + */ + +#include "AccessBridgeDebug.h" +#include "WinAccessBridge.h" +#include "accessBridgeResource.h" +#include "accessBridgeCallbacks.h" +#include "AccessBridgeMessages.h" +#include "AccessBridgeMessageQueue.h" + +#include +#include +#include + +// send memory lock +// +// This lock is need to serialize access to the buffer used by sendMemoryPackage. +// If a JVM goes away while the associated memory buffer is in use, a thread switch +// allows a call to JavaVMDestroyed and deallocation of the memory buffer. +CRITICAL_SECTION sendMemoryIPCLock; + +// registry paths to newly found JVMs that don't have the bridge installed +char **newJVMs; + +WinAccessBridge *theWindowsAccessBridge; +HWND theDialogWindow; + +// unique broadcast msg. IDs gotten dymanically +extern UINT theFromJavaHelloMsgID; +extern UINT theFromWindowsHelloMsgID; + +// protects the javaVMs chain while in use +bool isVMInstanceChainInUse; + +/* =================================================================================== */ + + + +/** + * Proc for "New JVM Found" dialog + */ +BOOL CALLBACK newJVMFoundDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { + + switch (message) { + case WM_COMMAND: + // PrintDebugString(" newJVMDialogProc: LOWORD(wParam) = %d", LOWORD(wParam)); + + switch (LOWORD(wParam)) { + + // Remind user later that a new JVM was installed + case cRemindThereIsNewJVM: + PrintDebugString(" newJVMDialogProc: cRemindThereIsNewJVM"); + // do nothing + EndDialog(hwndDlg, wParam); + return TRUE; + + // Do not remind user later that a new JVM was installed + /* + case cDoNotRemindThereIsNewJVM: + PrintDebugString(" newJVMDialogProc: cDoNotRemindThereIsNewJVM"); + // remember to not remind the user there are new JVMs + PrintDebugString("theWindowsAccessBridge = %x", theWindowsAccessBridge); + if (theWindowsAccessBridge != NULL) { + dontRemindUser(newJVMs); + } + EndDialog(hwndDlg, wParam); + return TRUE; + */ + + // Run the AccessBridge installer + /* + case cInstallAccessBridge: + PrintDebugString(" newJVMDialogProc: cInstallAccessBridge"); + // start the installer + if (theWindowsAccessBridge != NULL) { + startInstaller(newJVMs); + } + EndDialog(hwndDlg, wParam); + return TRUE; + */ + + default: + ; + } + default: + ; + } + return FALSE; +} + + + +/* =========================================================================== */ + +// --------------------------------------------------------------------------- + +extern "C" { + /** + * DllMain - where Windows executables will load/unload us + * + */ + BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) { + + switch (fdwReason) { + case DLL_PROCESS_ATTACH: // A Windows executable loaded us + PrintDebugString("DLL_PROCESS_ATTACH"); + theWindowsAccessBridge = new WinAccessBridge(hinstDll); + break; + + case DLL_PROCESS_DETACH: // A Windows executable unloaded us + if (theWindowsAccessBridge != (WinAccessBridge *) 0) { + PrintDebugString("*** AccessBridgeDialogProc -> deleting theWindowsAccessBridge"); + delete theWindowsAccessBridge; + } + break; + } + + return(TRUE); + } + + /** + * Append debug info to dialog + * + * replaced with code to send output to debug file + * + */ + void AppendToCallInfo(char *s) { + + /* + _CrtDbgReport(_CRT_WARN, (const char *) NULL, NULL, (const char *) NULL, + (const char *) "WinAccessBridge: %s", s); + */ + + char buf[1024]; + sprintf(buf, "WinAccessBridge: %s", s); + OutputDebugString(buf); + } + + /** + * Our window proc + * + */ + BOOL CALLBACK AccessBridgeDialogProc(HWND hDlg, UINT message, UINT wParam, LONG lParam) { + COPYDATASTRUCT *sentToUs; + char *package; + + switch (message) { + case WM_INITDIALOG: + PrintDebugString("AccessBridgeDialogProc -> Initializing"); + break; + + // call from Java with data for us to deliver + case WM_COPYDATA: + if (theDialogWindow == (HWND) wParam) { + PrintDebugString("AccessBridgeDialogProc -> Got WM_COPYDATA from Java Bridge DLL"); + } else { + PrintDebugString("AccessBridgeDialogProc -> Got WM_COPYDATA from HWND %p", wParam); + sentToUs = (COPYDATASTRUCT *) lParam; + package = (char *) sentToUs->lpData; + theWindowsAccessBridge->preProcessPackage(package, sentToUs->cbData); + } + break; + + // message to ourselves -> de-queue messages and send 'em + case AB_MESSAGE_QUEUED: + PrintDebugString("AccessBridgeDialogProc -> Got AB_MESSAGE_QUEUED from ourselves"); + theWindowsAccessBridge->receiveAQueuedPackage(); + break; + + // a JavaAccessBridge DLL is going away + // + // When JavaVMDestroyed is called a AccessBridgeJavaVMInstance in the + // javaVMs chain will be removed. If that chain is in use this will + // cause a crash. One way AB_DLL_GOING_AWAY can arrive is on any + // outgoing SendMessage call. SendMessage normally spins waiting for + // a response. However, if there is an incoming SendMessage, e.g. for + // AB_DLL_GOING_AWAY Windows will send that request to this DialogProc. + // One seemingly easy way to combat that is to use SendMessageTimeout + // with the SMTO_BLOCK flag set. However, it has been the case that + // even after using that technique AB_DLL_GOING_AWAY can still arrive + // in the middle of processing the javaVMs chain. An alternative that + // was tried was to use a critical section around any access ot the + // javaVMs chain but unfortunately the AB_DLL_GOING_AWAY message arrives + // on the same thread and thus the use of a critical section is ineffective. + // The solution then is to set a flag whenever the javaVMs chain is being + // used and if that flag is set at this point the message will be posted + // to the message queue. That would delay the destruction of the instance + // until the chain is not being traversed. + case AB_DLL_GOING_AWAY: + PrintDebugString("***** AccessBridgeDialogProc -> Got AB_DLL_GOING_AWAY message"); + if (isVMInstanceChainInUse) { + PrintDebugString(" javaVMs chain in use, calling PostMessage"); + PostMessage(hDlg, AB_DLL_GOING_AWAY, wParam, (LPARAM)0); + } else { + PrintDebugString(" calling javaVMDestroyed"); + theWindowsAccessBridge->JavaVMDestroyed((HWND) wParam); + } + break; + + default: + // the JavaVM is saying "hi"! + // wParam == sourceHwnd; lParam == JavaVMID + if (message == theFromJavaHelloMsgID) { + PrintDebugString("AccessBridgeDialogProc -> Got theFromJavaHelloMsgID; wParam = %p, lParam = %p", wParam, lParam); + theWindowsAccessBridge->rendezvousWithNewJavaDLL((HWND) wParam, (long ) lParam); + } + break; + } + + return (FALSE); + } + +} + + + + +// --------------------------------------------------------------------------- + +/** + * Initialize the WinAccessBridge + * + */ +WinAccessBridge::WinAccessBridge(HINSTANCE hInstance) { + + PrintDebugString("WinAccessBridge ctor"); + + // IntializeCriticalSection should only be called once. + InitializeCriticalSection(&sendMemoryIPCLock); + windowsInstance = hInstance; + javaVMs = (AccessBridgeJavaVMInstance *) 0; + eventHandler = new AccessBridgeEventHandler(); + messageQueue = new AccessBridgeMessageQueue(); + initBroadcastMessageIDs(); // get the unique to us broadcast msg. IDs + theWindowsAccessBridge = this; + isVMInstanceChainInUse = false; + + + // notify the user if new JVMs are found + /* + newJVMs = (char **)malloc(MAX_NEW_JVMS_FOUND); + for (int i = 0; i < MAX_NEW_JVMS_FOUND; i++) { + newJVMs[i] = (char *)malloc(SHORT_STRING_SIZE); + newJVMs[i][0] = 0; + } + + BOOL newJ2SEFound = findNewJVMs(J2SE_REG_PATH, newJVMs); + BOOL newJ2REFound = TRUE; // findNewJVMs(J2RE_REG_PATH, newJVMs); + + if (newJ2SEFound || newJ2REFound) { + + int result = DialogBox(windowsInstance, + "FOUNDNEWJVMDIALOG", + NULL, + (DLGPROC)newJVMFoundDialogProc); + if (result < 0) { + printError("DialogBox failed"); + } + + PrintDebugString(" FOUNDNEWJVMDIALOG: result = %d", result); + + ShowWindow((HWND)result, SW_SHOW); + } + */ + + ShowWindow(theDialogWindow, SW_SHOW); +} + + + +/** + * Destroy the WinAccessBridge + * + */ +WinAccessBridge::~WinAccessBridge() { + // inform all other AccessBridges that we're going away + // -> shut down all event listening + // -> release all objects held in the JVM by us + + PrintDebugString("*****in WinAccessBridge::~WinAccessBridge()"); + + // send a broadcast msg.; let other AccessBridge DLLs know we're going away + AccessBridgeJavaVMInstance *current = javaVMs; + while (current != (AccessBridgeJavaVMInstance *) 0) { + PrintDebugString(" telling %p we're going away", current->javaAccessBridgeWindow); + SendMessage(current->javaAccessBridgeWindow, + AB_DLL_GOING_AWAY, (WPARAM) dialogWindow, (LPARAM) 0); + current = current->nextJVMInstance; + } + + PrintDebugString(" finished telling JVMs about our demise"); + + delete eventHandler; + delete messageQueue; + delete javaVMs; + + PrintDebugString(" finished deleting eventHandler, messageQueue, and javaVMs"); + PrintDebugString("GOODBYE CRUEL WORLD..."); + + DestroyWindow(theDialogWindow); +} + + +/** + * Bring up our window; make a connection to the rest of the world + * + */ +BOOL +WinAccessBridge::initWindow() { + theDialogWindow = CreateDialog(windowsInstance, + "ACCESSBRIDGESTATUSWINDOW", NULL, + (DLGPROC) AccessBridgeDialogProc); + + // If window could not be created, return "failure". + if (!theDialogWindow) + return (FALSE); + + dialogWindow = theDialogWindow; + + // Make the window visible, update its client area, & return "success". + // DEBUG_CODE(ShowWindow (theDialogWindow, SW_SHOWNORMAL)); + // DEBUG_CODE(UpdateWindow (theDialogWindow)); + + // post a broadcast msg.; let other AccessBridge DLLs know we exist + PostMessage(HWND_BROADCAST, theFromWindowsHelloMsgID, (WPARAM) dialogWindow, (LPARAM) 0); + + return (TRUE); +} + +// ----------------------- + +/** + * rendezvousWithNewJavaDLL + * - Build AccessBridgeJavaVMInstance data structure + * (including setting up Memory-Mapped file info) + * + */ +LRESULT +WinAccessBridge::rendezvousWithNewJavaDLL(HWND JavaBridgeDLLwindow, long vmID) { + LRESULT returnVal; + + PrintDebugString("in JavaAccessBridge::rendezvousWithNewJavaDLL(%p, %X)", + JavaBridgeDLLwindow, vmID); + + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *newVM = + new AccessBridgeJavaVMInstance(dialogWindow, JavaBridgeDLLwindow, vmID, javaVMs); + javaVMs = newVM; + isVMInstanceChainInUse = false; + + returnVal = javaVMs->initiateIPC(); + if (returnVal == 0) { + + // tell the newly created JavaVM what events we're interested in, if any + long javaEventMask = eventHandler->getJavaEventMask(); + long accessibilityEventMask = eventHandler->getAccessibilityEventMask(); + + PrintDebugString(" Setting Java event mask to: %X", javaEventMask); + + if (javaEventMask != 0) { + addJavaEventNotification(javaEventMask); + } + + PrintDebugString(" Setting Accessibility event mask to: %X", accessibilityEventMask); + + if (accessibilityEventMask != 0) { + addAccessibilityEventNotification(accessibilityEventMask); + } + } else { + PrintDebugString(" ERROR: Failed to initiate IPC with newly created JavaVM!!!"); + return FALSE; + } + + PrintDebugString(" Success!! We rendezvoused with the JavaDLL"); + return returnVal; +} + +// ----------------------- + +/** + * sendPackage - uses SendMessage(WM_COPYDATA) to do IPC messaging + * with the Java AccessBridge DLL + * + * NOTE: WM_COPYDATA is only for one-way IPC; there + * is now way to return parameters (especially big ones) + * Use sendMemoryPackage() to do that! + */ +void +WinAccessBridge::sendPackage(char *buffer, long bufsize, HWND destWindow) { + COPYDATASTRUCT toCopy; + toCopy.dwData = 0; // 32-bits we could use for something... + toCopy.cbData = bufsize; + toCopy.lpData = buffer; + + SendMessage(destWindow, WM_COPYDATA, (WPARAM) dialogWindow, (LPARAM) &toCopy); +} + + +/** + * sendMemoryPackage - uses Memory-Mapped files to do IPC messaging + * with the Java AccessBridge DLL, informing the + * Java AccessBridge DLL via SendMessage that something + * is waiting for it in the shared file... + * + * In the SendMessage call, the third param (WPARAM) is + * the source HWND (theDialogWindow in this case), and + * the fourth param (LPARAM) is the size in bytes of + * the package put into shared memory. + * + */ +BOOL +WinAccessBridge::sendMemoryPackage(char *buffer, long bufsize, HWND destWindow) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + AccessBridgeJavaVMInstance *ourABJavaVMInstance; + ourABJavaVMInstance = javaVMs->findABJavaVMInstanceFromJavaHWND(destWindow); + if (ourABJavaVMInstance != (AccessBridgeJavaVMInstance *) 0) { + if (!ourABJavaVMInstance->sendMemoryPackage(buffer, bufsize)) { + // return falue to the caller + memset(buffer, 0, bufsize); + return FALSE; + } + } else { + PrintDebugString("ERROR sending memory package: couldn't find destWindow"); + return FALSE; + } + return TRUE; +} + + +/** + * queuePackage - put a package onto the queue for latter processing + * + */ +BOOL +WinAccessBridge::queuePackage(char *buffer, long bufsize) { + PrintDebugString(" in WinAccessBridge::queuePackage(%p, %d)", buffer, bufsize); + + AccessBridgeQueueElement *element = new AccessBridgeQueueElement(buffer, bufsize); + + messageQueue->add(element); + PostMessage(dialogWindow, AB_MESSAGE_QUEUED, (WPARAM) 0, (LPARAM) 0); + return TRUE; +} + + +/** + * receiveAQueuedPackage - remove a pending packge from the queue and + * handle it. If the queue is busy, post a + * message to self to retrieve it later + * + */ +BOOL +WinAccessBridge::receiveAQueuedPackage() { + AccessBridgeQueueElement *element; + + PrintDebugString("in WinAccessBridge::receiveAQueuedPackage()"); + + // ensure against re-entrancy problems... + if (messageQueue->getRemoveLockSetting() == FALSE) { + messageQueue->setRemoveLock(TRUE); + + PrintDebugString(" dequeueing message"); + + QueueReturns result = messageQueue->remove(&element); + + PrintDebugString(" 'element->buffer' contains:"); + DEBUG_CODE(PackageType *type = (PackageType *) element->buffer); + DEBUG_CODE(FocusGainedPackageTag *pkg = (FocusGainedPackageTag *) (((char *) element->buffer) + sizeof(PackageType))); + DEBUG_CODE(PrintDebugString(" PackageType = %X", *type)); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + DEBUG_CODE(PrintDebugString(" EventPackage: vmID = %X, event = %p, source = %p", pkg->vmID, pkg->Event, pkg->AccessibleContextSource)); +#else // JOBJECT64 is jlong (64 bit) + DEBUG_CODE(PrintDebugString(" EventPackage: vmID = %X, event = %016I64X, source = %016I64X", pkg->vmID, pkg->Event, pkg->AccessibleContextSource)); +#endif + switch (result) { + + case cQueueBroken: + PrintDebugString(" ERROR!!! Queue seems to be broken!"); + messageQueue->setRemoveLock(FALSE); + return FALSE; + + case cMoreMessages: + case cQueueEmpty: + if (element != (AccessBridgeQueueElement *) 0) { + PrintDebugString(" found one; sending it!"); + processPackage(element->buffer, element->bufsize); + delete element; + } else { + PrintDebugString(" ODD... element == 0!"); + return FALSE; + } + break; + + case cQueueInUse: + PrintDebugString(" Queue in use, will try again later..."); + PostMessage(dialogWindow, AB_MESSAGE_QUEUED, (WPARAM) 0, (LPARAM) 0); + break; + + default: + messageQueue->setRemoveLock(FALSE); + return FALSE; // should never get something we don't recognize! + } + } else { + PrintDebugString(" unable to dequeue message; remove lock is set"); + PostMessage(dialogWindow, AB_MESSAGE_QUEUED, (WPARAM) 0, (LPARAM) 0); // Fix for 6995891 + } + + messageQueue->setRemoveLock(FALSE); + return TRUE; +} + +// ----------------------- + +/** + * preProcessPackage + * - do triage on incoming packages; queue some, deal with others + * + */ +void +WinAccessBridge::preProcessPackage(char *buffer, long bufsize) { + PrintDebugString("PreProcessing package sent from Java:"); + + PackageType *type = (PackageType *) buffer; + + switch (*type) { + + PrintDebugString(" type == %X", *type); + + // event packages all get queued for later handling + //case cPropertyChangePackage: + case cJavaShutdownPackage: + case cFocusGainedPackage: + case cFocusLostPackage: + case cCaretUpdatePackage: + case cMouseClickedPackage: + case cMouseEnteredPackage: + case cMouseExitedPackage: + case cMousePressedPackage: + case cMouseReleasedPackage: + case cMenuCanceledPackage: + case cMenuDeselectedPackage: + case cMenuSelectedPackage: + case cPopupMenuCanceledPackage: + case cPopupMenuWillBecomeInvisiblePackage: + case cPopupMenuWillBecomeVisiblePackage: + + case cPropertyCaretChangePackage: + case cPropertyDescriptionChangePackage: + case cPropertyNameChangePackage: + case cPropertySelectionChangePackage: + case cPropertyStateChangePackage: + case cPropertyTextChangePackage: + case cPropertyValueChangePackage: + case cPropertyVisibleDataChangePackage: + case cPropertyChildChangePackage: + case cPropertyActiveDescendentChangePackage: + + case cPropertyTableModelChangePackage: + + queuePackage(buffer, bufsize); + break; + + // perhaps there will be some other packages to process at some point... // + + default: + PrintDebugString(" processing FAILED!! -> don't know how to handle type = %X", *type); + break; + } + + PrintDebugString(" package preprocessing completed"); +} + + +#define DISPATCH_EVENT_PACKAGE(packageID, eventPackage, fireEventMethod) \ + case packageID: \ + if (bufsize == sizeof(PackageType) + sizeof(eventPackage)) { \ + eventPackage *pkg = \ + (eventPackage *) (buffer + sizeof(PackageType)); \ + PrintDebugString(" begin callback to AT, type == %X", *type); \ + theWindowsAccessBridge->eventHandler->fireEventMethod( \ + pkg->vmID, pkg->Event, pkg->AccessibleContextSource); \ + PrintDebugString(" event callback complete!"); \ + } else { \ + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", \ + bufsize, sizeof(PackageType) + sizeof(eventPackage)); \ + } \ + break; + +#define DISPATCH_PROPERTY_CHANGE_PACKAGE(packageID, eventPackage, fireEventMethod, oldValue, newValue) \ + case packageID: \ + if (bufsize == sizeof(PackageType) + sizeof(eventPackage)) { \ + eventPackage *pkg = \ + (eventPackage *) (buffer + sizeof(PackageType)); \ + PrintDebugString(" begin callback to AT, type == %X", *type); \ + theWindowsAccessBridge->eventHandler->fireEventMethod( \ + pkg->vmID, pkg->Event, pkg->AccessibleContextSource, \ + pkg->oldValue, pkg->newValue); \ + PrintDebugString(" event callback complete!"); \ + } else { \ + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", \ + bufsize, sizeof(PackageType) + sizeof(eventPackage)); \ + } \ + break; + +#define DISPATCH_PROPERTY_TABLE_MODEL_CHANGE_PACKAGE(packageID, eventPackage, fireEventMethod, oldValue, newValue) \ + case packageID: \ + if (bufsize == sizeof(PackageType) + sizeof(eventPackage)) { \ + eventPackage *pkg = \ + (eventPackage *) (buffer + sizeof(PackageType)); \ + PrintDebugString(" begin callback to AT, type == %X", *type); \ + theWindowsAccessBridge->eventHandler->fireEventMethod( \ + pkg->vmID, pkg->Event, pkg->AccessibleContextSource, \ + pkg->oldValue, pkg->newValue); \ + PrintDebugString(" event callback complete!"); \ + } else { \ + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", \ + bufsize, sizeof(PackageType) + sizeof(eventPackage)); \ + } \ + break; + +/** + * processPackage - processes the output of SendMessage(WM_COPYDATA) + * to do IPC messaging with the Java AccessBridge DLL + * + */ +void +WinAccessBridge::processPackage(char *buffer, long bufsize) { + PrintDebugString("WinAccessBridge::Processing package sent from Java:"); + + PackageType *type = (PackageType *) buffer; + + switch (*type) { + + PrintDebugString(" type == %X", *type); + + case cJavaShutdownPackage: + PrintDebugString(" type == cJavaShutdownPackage"); + if (bufsize == sizeof(PackageType) + sizeof(JavaShutdownPackage)) { + JavaShutdownPackage *pkg = + (JavaShutdownPackage *) (buffer + sizeof(PackageType)); + theWindowsAccessBridge->eventHandler->fireJavaShutdown(pkg->vmID); + PrintDebugString(" event callback complete!"); + PrintDebugString(" event fired!"); + } else { + PrintDebugString(" processing FAILED!! -> bufsize = %d; expectation = %d", + bufsize, sizeof(PackageType) + sizeof(JavaShutdownPackage)); + } + break; + + + DISPATCH_EVENT_PACKAGE(cFocusGainedPackage, FocusGainedPackage, fireFocusGained); + DISPATCH_EVENT_PACKAGE(cFocusLostPackage, FocusLostPackage, fireFocusLost); + + DISPATCH_EVENT_PACKAGE(cCaretUpdatePackage, CaretUpdatePackage, fireCaretUpdate); + + DISPATCH_EVENT_PACKAGE(cMouseClickedPackage, MouseClickedPackage, fireMouseClicked); + DISPATCH_EVENT_PACKAGE(cMouseEnteredPackage, MouseEnteredPackage, fireMouseEntered); + DISPATCH_EVENT_PACKAGE(cMouseExitedPackage, MouseExitedPackage, fireMouseExited); + DISPATCH_EVENT_PACKAGE(cMousePressedPackage, MousePressedPackage, fireMousePressed); + DISPATCH_EVENT_PACKAGE(cMouseReleasedPackage, MouseReleasedPackage, fireMouseReleased); + + DISPATCH_EVENT_PACKAGE(cMenuCanceledPackage, MenuCanceledPackage, fireMenuCanceled); + DISPATCH_EVENT_PACKAGE(cMenuDeselectedPackage, MenuDeselectedPackage, fireMenuDeselected); + DISPATCH_EVENT_PACKAGE(cMenuSelectedPackage, MenuSelectedPackage, fireMenuSelected); + DISPATCH_EVENT_PACKAGE(cPopupMenuCanceledPackage, PopupMenuCanceledPackage, firePopupMenuCanceled); + DISPATCH_EVENT_PACKAGE(cPopupMenuWillBecomeInvisiblePackage, PopupMenuWillBecomeInvisiblePackage, firePopupMenuWillBecomeInvisible); + DISPATCH_EVENT_PACKAGE(cPopupMenuWillBecomeVisiblePackage, PopupMenuWillBecomeVisiblePackage, firePopupMenuWillBecomeVisible); + + DISPATCH_PROPERTY_CHANGE_PACKAGE(cPropertyNameChangePackage, + PropertyNameChangePackage, + firePropertyNameChange, oldName, newName) + DISPATCH_PROPERTY_CHANGE_PACKAGE(cPropertyDescriptionChangePackage, + PropertyDescriptionChangePackage, + firePropertyDescriptionChange, + oldDescription, newDescription) + DISPATCH_PROPERTY_CHANGE_PACKAGE(cPropertyStateChangePackage, + PropertyStateChangePackage, + firePropertyStateChange, oldState, newState) + DISPATCH_PROPERTY_CHANGE_PACKAGE(cPropertyValueChangePackage, + PropertyValueChangePackage, + firePropertyValueChange, oldValue, newValue) + DISPATCH_EVENT_PACKAGE(cPropertySelectionChangePackage, + PropertySelectionChangePackage, firePropertySelectionChange) + DISPATCH_EVENT_PACKAGE(cPropertyTextChangePackage, + PropertyTextChangePackage, firePropertyTextChange) + DISPATCH_PROPERTY_CHANGE_PACKAGE(cPropertyCaretChangePackage, + PropertyCaretChangePackage, + firePropertyCaretChange, oldPosition, newPosition) + DISPATCH_EVENT_PACKAGE(cPropertyVisibleDataChangePackage, + PropertyVisibleDataChangePackage, firePropertyVisibleDataChange) + DISPATCH_PROPERTY_CHANGE_PACKAGE(cPropertyChildChangePackage, + PropertyChildChangePackage, + firePropertyChildChange, + oldChildAccessibleContext, + newChildAccessibleContext) + DISPATCH_PROPERTY_CHANGE_PACKAGE(cPropertyActiveDescendentChangePackage, + PropertyActiveDescendentChangePackage, + firePropertyActiveDescendentChange, + oldActiveDescendentAccessibleContext, + newActiveDescendentAccessibleContext) + + DISPATCH_PROPERTY_TABLE_MODEL_CHANGE_PACKAGE(cPropertyTableModelChangePackage, + PropertyTableModelChangePackage, + firePropertyTableModelChange, + oldValue, newValue) + + + default: + PrintDebugString(" processing FAILED!! -> don't know how to handle type = %X", *type); + break; + } + + PrintDebugString(" package processing completed"); +} + + +// ----------------------------- + +void +WinAccessBridge::JavaVMDestroyed(HWND VMBridgeDLLWindow) { + PrintDebugString("***** WinAccessBridge::JavaVMDestroyed(%p)", VMBridgeDLLWindow); + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *currentVM = javaVMs; + AccessBridgeJavaVMInstance *previousVM = javaVMs; + if (javaVMs->javaAccessBridgeWindow == VMBridgeDLLWindow) { + javaVMs = javaVMs->nextJVMInstance; + delete currentVM; + + PrintDebugString(" data structures successfully removed"); + + // [[[FIXME]]] inform Windows AT that a JVM went away, + // and that any jobjects it's got lying around for that JVM + // are now invalid + + } else { + while (currentVM != (AccessBridgeJavaVMInstance *) 0) { + if (currentVM->javaAccessBridgeWindow == VMBridgeDLLWindow) { + previousVM->nextJVMInstance = currentVM->nextJVMInstance; + delete currentVM; + + PrintDebugString(" data structures successfully removed"); + + // [[[FIXME]]] inform Windows AT that a JVM went away, + // and that any jobjects it's got lying around for that JVM + // are now invalid + isVMInstanceChainInUse = false; + return; + } else { + previousVM = currentVM; + currentVM = currentVM->nextJVMInstance; + } + } + PrintDebugString(" ERROR!! couldn't find matching data structures!"); + } + isVMInstanceChainInUse = false; +} + +// ----------------------- + +/** + * releaseJavaObject - lets the JavaVM know it can release the Java Object + * + * Note: once you have made this call, the JavaVM will garbage collect + * the jobject you pass in. If you later use that jobject in another + * call, you will cause all maner of havoc! + * + */ +void +WinAccessBridge::releaseJavaObject(long vmID, JOBJECT64 object) { +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::releaseJavaObject(%X, %p)", vmID, object); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::releaseJavaObject(%X, %016I64X)", vmID, object); +#endif + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + char buffer[sizeof(PackageType) + sizeof(ReleaseJavaObjectPackage)]; + PackageType *type = (PackageType *) buffer; + ReleaseJavaObjectPackage *pkg = (ReleaseJavaObjectPackage *) (buffer + sizeof(PackageType)); + *type = cReleaseJavaObjectPackage; + pkg->vmID = vmID; + pkg->object = object; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + sendPackage(buffer, sizeof(buffer), destABWindow); // no return values! + } +} + +// ----------------------- + +/** + * getVersionInfo - fill the AccessBridgeVersionInfo struct + * + */ +BOOL +WinAccessBridge::getVersionInfo(long vmID, AccessBridgeVersionInfo *info) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessBridgeVersionPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessBridgeVersionPackage *pkg = (GetAccessBridgeVersionPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessBridgeVersionPackage; + pkg->vmID = vmID; + + PrintDebugString("WinAccessBridge::getVersionInfo(%X, )", vmID); + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(info, &(pkg->rVersionInfo), sizeof(AccessBridgeVersionInfo)); + PrintDebugString(" VMversion: %ls", info->VMversion); + PrintDebugString(" bridgeJavaClassVersion: %ls", info->bridgeJavaClassVersion); + PrintDebugString(" bridgeJavaDLLVersion: %ls", info->bridgeJavaDLLVersion); + PrintDebugString(" bridgeWinDLLVersion: %ls", info->bridgeWinDLLVersion); + return TRUE; + } + } + return FALSE; +} + + +/********** Window-related routines ***********************************/ + +/** + * isJavaWindow - returns TRUE if the HWND is a top-level Java Window + * + * Note: just because the Windnow is a top-level Java window, that doesn't + * mean that it is accessible. Call getAccessibleContextFromHWND(HWND) to get the + * AccessibleContext, if any, for an HWND that is a Java Window. + * + */ +BOOL +WinAccessBridge::isJavaWindow(HWND window) { + HWND hwnd; + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + // quick check to see if 'window' is top-level; if not, it's not interesting... + // [[[FIXME]]] is this for sure an OK optimization? + hwnd = getTopLevelHWND(window); + if (hwnd == (HWND) NULL) { + return FALSE; + } + + PrintDebugString(" in WinAccessBridge::isJavaWindow"); + + + + char buffer[sizeof(PackageType) + sizeof(IsJavaWindowPackage)]; + PackageType *type = (PackageType *) buffer; + IsJavaWindowPackage *pkg = (IsJavaWindowPackage *) (buffer + sizeof(PackageType)); + *type = cIsJavaWindowPackage; + pkg->window = (jint) window; + + PrintDebugString("WinAccessBridge::isJavaWindow(%p)", window); + + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *current = javaVMs; + while (current != (AccessBridgeJavaVMInstance *) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), current->javaAccessBridgeWindow) == TRUE) { + if (pkg->rResult != 0) { + isVMInstanceChainInUse = false; + return TRUE; + } + } + current = current->nextJVMInstance; + } + isVMInstanceChainInUse = false; + return FALSE; + + + /* + char classname[256]; + HWND hwnd; + + hwnd = getTopLevelHWND(window); + if (hwnd == (HWND) NULL) { + return FALSE; + } + GetClassName(hwnd, classname, 256); + + if (strstr(classname, "AwtFrame") != 0) { + return TRUE; + } else if (strstr(classname, "AwtWindow") != 0) { + return TRUE; + } else if (strstr(classname, "AwtDialog") != 0) { + return TRUE; + } + */ + // JDK 1.4 introduces new (and changes old) classnames + /* + else if (strstr(classname, "SunAwtToolkit") != 0) { + return TRUE; + } else if (strstr(classname, "javax.swing.JFrame") != 0) { + return TRUE; + } + */ + + return FALSE; +} + +/** + * isSameObject - returns TRUE if the two object references refer to + * the same object. Otherwise, this method returns FALSE: + */ +BOOL +WinAccessBridge::isSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::isSameObject(%p %p)", obj1, obj2); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::isSameObject(%016I64X %016I64X)", obj1, obj2); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(IsSameObjectPackage)]; + PackageType *type = (PackageType *) buffer; + IsSameObjectPackage *pkg = (IsSameObjectPackage *) (buffer + sizeof(PackageType)); + *type = cIsSameObjectPackage; + pkg->vmID = vmID; + pkg->obj1 = obj1; + pkg->obj2 = obj2; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(pkg->vmID); + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + if (pkg->rResult != 0) { + PrintDebugString(" WinAccessBridge::isSameObject returning TRUE (same object)"); + return TRUE; + } else { + PrintDebugString(" WinAccessBridge::isSameObject returning FALSE (different object)"); + return FALSE; + } + } + PrintDebugString(" WinAccessBridge::isSameObject returning FALSE (sendMemoryPackage failed)"); + return FALSE; +} + +/** + * FromHWND - returns the AccessibleContext jobject for the HWND + * + * Note: this routine can return null, even if the HWND is a Java Window, + * because the Java Window may not be accessible. + * + */ +BOOL +WinAccessBridge::getAccessibleContextFromHWND(HWND window, long *vmID, JOBJECT64 *AccessibleContext) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleContextFromHWNDPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleContextFromHWNDPackage *pkg = (GetAccessibleContextFromHWNDPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleContextFromHWNDPackage; + pkg->window = (jint) window; + + PrintDebugString("WinAccessBridge::getAccessibleContextFromHWND(%p, )", window); + + DEBUG_CODE(pkg->rVMID = (long ) 0x01010101); + DEBUG_CODE(pkg->rAccessibleContext = (JOBJECT64) 0x01010101); + + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *current = javaVMs; + while (current != (AccessBridgeJavaVMInstance *) 0) { + + if (sendMemoryPackage(buffer, sizeof(buffer), current->javaAccessBridgeWindow) == TRUE) { + if (pkg->rAccessibleContext != 0) { + *vmID = pkg->rVMID; + *AccessibleContext = (JOBJECT64)pkg->rAccessibleContext; + PrintDebugString(" current->vmID = %X", current->vmID); + PrintDebugString(" pkg->rVMID = %X", pkg->rVMID); +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" pkg->rAccessibleContext = %p", pkg->rAccessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" pkg->rAccessibleContext = %016I64X", pkg->rAccessibleContext); +#endif + if (pkg->rVMID != current->vmID) { + PrintDebugString(" ERROR! getAccessibleContextFromHWND vmIDs don't match!"); + isVMInstanceChainInUse = false; + return FALSE; + } + isVMInstanceChainInUse = false; + return TRUE; + } + } + current = current->nextJVMInstance; + } + isVMInstanceChainInUse = false; + + // This isn't really an error; it just means that the HWND was for a non-Java + // window. It's also possible the HWND was for a Java window but the JVM has + // since been shut down and sendMemoryPackage returned FALSE. + PrintDebugString(" ERROR! getAccessibleContextFromHWND no matching HWND found!"); + return FALSE; +} + +/** + * Returns the HWND for an AccessibleContext. Returns (HWND)0 on error. + */ +HWND +WinAccessBridge::getHWNDFromAccessibleContext(long vmID, JOBJECT64 accessibleContext) { + PrintDebugString(" in WinAccessBridge::getHWNDFromAccessibleContext"); + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return (HWND)0; + } + + char buffer[sizeof(PackageType) + sizeof(GetHWNDFromAccessibleContextPackage)]; + PackageType *type = (PackageType *) buffer; + GetHWNDFromAccessibleContextPackage *pkg = (GetHWNDFromAccessibleContextPackage *) (buffer + sizeof(PackageType)); + *type = cGetHWNDFromAccessibleContextPackage; + pkg->accessibleContext = accessibleContext; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getHWNDFromAccessibleContext(%p)", accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getHWNDFromAccessibleContext(%016I64X)", accessibleContext); +#endif + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return ((HWND)ABLongToHandle(pkg->rHWND)); + } + } + return (HWND)0; +} + +/********** AccessibleContext routines ***********************************/ + +/** + * Walk through Java Windows, in front-to-back Z-order. + * If NULL is passed it, this function starts at the top. + * + */ +HWND +WinAccessBridge::getNextJavaWindow(HWND previous) { + HWND current = previous; + if (current == NULL) { + current = GetTopWindow(NULL); + } else { + current = GetNextWindow(current, GW_HWNDNEXT); + } + while (current != NULL) { + if (isJavaWindow(current)) { + return current; + } + current = GetNextWindow(current, GW_HWNDNEXT); + } + return NULL; +} + + +/** + * getAccessibleContextAt - performs the Java code: + * Accessible a = EventQueueMonitor.getAccessibleAt(x, y); + * return a.getAccessibleContext(); + * + * Note: this call explicitly goes through the AccessBridge, + * so that the AccessBridge can hide expected changes in how this functions + * between JDK 1.1.x w/AccessibilityUtility classes, and JDK 1.2, when some + * of this functionality may be built into the platform + * + */ +BOOL +WinAccessBridge::getAccessibleContextAt(long vmID, JOBJECT64 AccessibleContextParent, + jint x, jint y, JOBJECT64 *AccessibleContext) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleContextAtPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleContextAtPackage *pkg = (GetAccessibleContextAtPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleContextAtPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContextParent; + pkg->x = x; + pkg->y = y; + + PrintDebugString("WinAccessBridge::getAccessibleContextAt(%X, %p, %d, %c)", vmID, AccessibleContextParent, x, y); + HWND destABWindow = javaVMs->findAccessBridgeWindow(pkg->vmID); + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + *AccessibleContext = pkg->rAccessibleContext; + return TRUE; + } + + return FALSE; +} + + +/** + * getAccessibleContextWithFocus - performs the Java code: + * Accessible a = Translator.getAccessible(SwingEventMonitor.getComponentWithFocus()); + * return a.getAccessibleContext(); + * + * Note: this call explicitly goes through the AccessBridge, + * so that the AccessBridge can hide expected changes in how this functions + * between JDK 1.1.x w/AccessibilityUtility classes, and JDK 1.2, when some + * of this functionality may be built into the platform + * + */ +BOOL +WinAccessBridge::getAccessibleContextWithFocus(HWND window, long *vmID, JOBJECT64 *AccessibleContext) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleContextWithFocusPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleContextWithFocusPackage *pkg = (GetAccessibleContextWithFocusPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleContextWithFocusPackage; + + PrintDebugString("WinAccessBridge::getAccessibleContextWithFocus(%p, %X, )", window, vmID); + // find vmID, etc. from HWND; ask that VM for the AC w/Focus + HWND pkgVMID = (HWND)ABLongToHandle( pkg->rVMID ) ; + if (getAccessibleContextFromHWND(window, (long *)&(pkgVMID), &(pkg->rAccessibleContext)) == TRUE) { + HWND destABWindow = javaVMs->findAccessBridgeWindow((long)pkgVMID); // ineffecient [[[FIXME]]] + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + *vmID = pkg->rVMID; + *AccessibleContext = pkg->rAccessibleContext; + return TRUE; + } + } + + return FALSE; +} + +/** + * getAccessibleContextInfo - fills a struct with a bunch of information + * contained in the Java Accessibility API + * + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +BOOL +WinAccessBridge::getAccessibleContextInfo(long vmID, + JOBJECT64 accessibleContext, + AccessibleContextInfo *info) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleContextInfoPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleContextInfoPackage *pkg = (GetAccessibleContextInfoPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleContextInfoPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = accessibleContext; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getAccessibleContextInfo(%X, %p, )", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getAccessibleContextInfo(%X, %016I64X, )", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(info, &(pkg->rAccessibleContextInfo), sizeof(AccessibleContextInfo)); + PrintDebugString(" name: %ls", info->name); + PrintDebugString(" description: %ls", info->description); + PrintDebugString(" role: %ls", info->role); + PrintDebugString(" role_en_US: %ls", info->role_en_US); + PrintDebugString(" states: %ls", info->states); + PrintDebugString(" states_en_US: %ls", info->states_en_US); + return TRUE; + } + } + + return FALSE; +} + +/** + * getAccessibleChildFromContext - performs the Java code: + * Accessible child = ac.getAccessibleChild(i); + * return child.getAccessibleContext(); + * + * Note: this call explicitly goes through the AccessBridge, + * so that the AccessBridge can hide expected changes in how this functions + * between JDK 1.1.x w/AccessibilityUtility classes, and JDK 1.2, when some + * of this functionality may be built into the platform + * + */ +JOBJECT64 +WinAccessBridge::getAccessibleChildFromContext(long vmID, + JOBJECT64 AccessibleContext, + jint childIndex) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return (JOBJECT64)0; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleChildFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleChildFromContextPackage *pkg = (GetAccessibleChildFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleChildFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->childIndex = childIndex; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getAccessibleChildFromContext(%X, %p, %d)", vmID, AccessibleContext, childIndex); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getAccessibleChildFromContext(%X, %016I64X, %d)", vmID, AccessibleContext, childIndex); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rAccessibleContext; + } + } + + return (JOBJECT64) 0; +} + +/** + * getAccessibleParentFromContext - returns the parent AccessibleContext jobject + * + * Note: this may be null, if the AccessibleContext passed in is a top-level + * window, then it has no parent. + * + */ +JOBJECT64 +WinAccessBridge::getAccessibleParentFromContext(long vmID, + JOBJECT64 AccessibleContext) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return (JOBJECT64)0; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleParentFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleParentFromContextPackage *pkg = (GetAccessibleParentFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleParentFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + + PrintDebugString("WinAccessBridge::getAccessibleParentFromContext(%X, %p)", vmID, AccessibleContext); + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rAccessibleContext; + } + } + + return (JOBJECT64) 0; +} + +/********** AccessibleTable routines ***********************************/ + +BOOL +WinAccessBridge::getAccessibleTableInfo(long vmID, + JOBJECT64 accessibleContext, + AccessibleTableInfo *tableInfo) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableInfo(%X, %p, %p)", vmID, accessibleContext, + tableInfo); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableInfo(%X, %016I64X, %p)", vmID, accessibleContext, + tableInfo); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableInfoPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableInfoPackage *pkg = (GetAccessibleTableInfoPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableInfoPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(tableInfo, &(pkg->rTableInfo), sizeof(AccessibleTableInfo)); + if (pkg->rTableInfo.rowCount != -1) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableInfo succeeded"); + return TRUE; + } + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableInfo failed"); + return FALSE; +} + +BOOL +WinAccessBridge::getAccessibleTableCellInfo(long vmID, JOBJECT64 accessibleTable, + jint row, jint column, + AccessibleTableCellInfo *tableCellInfo) { + + PrintDebugString("##### WinAccessBridge::getAccessibleTableCellInfo(%X, %p, %d, %d, %p)", vmID, + accessibleTable, row, column, tableCellInfo); + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableCellInfoPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableCellInfoPackage *pkg = (GetAccessibleTableCellInfoPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableCellInfoPackage; + pkg->vmID = vmID; + pkg->accessibleTable = accessibleTable; + pkg->row = row; + pkg->column = column; + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" XXXX pkg->rTableCellInfo.accessibleContext = %p", pkg->rTableCellInfo.accessibleContext); + memcpy(tableCellInfo, &(pkg->rTableCellInfo), sizeof(AccessibleTableCellInfo)); + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableCellInfo succeeded"); + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableCellInfo failed"); + return FALSE; +} + + +BOOL +WinAccessBridge::getAccessibleTableRowHeader(long vmID, JOBJECT64 accessibleContext, AccessibleTableInfo *tableInfo) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRowHeader(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRowHeader(%X, %016I64X)", vmID, accessibleContext); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableRowHeaderPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableRowHeaderPackage *pkg = (GetAccessibleTableRowHeaderPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableRowHeaderPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRowHeader succeeded"); + memcpy(tableInfo, &(pkg->rTableInfo), sizeof(AccessibleTableInfo)); + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRowHeader failed"); + return FALSE; +} + +BOOL +WinAccessBridge::getAccessibleTableColumnHeader(long vmID, JOBJECT64 accessibleContext, AccessibleTableInfo *tableInfo) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumnHeader(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumnHeader(%X, %016I64X)", vmID, accessibleContext); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableColumnHeaderPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableColumnHeaderPackage *pkg = (GetAccessibleTableColumnHeaderPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableColumnHeaderPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumnHeader succeeded"); + memcpy(tableInfo, &(pkg->rTableInfo), sizeof(AccessibleTableInfo)); + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumnHeader failed"); + return FALSE; +} + +JOBJECT64 +WinAccessBridge::getAccessibleTableRowDescription(long vmID, + JOBJECT64 accessibleContext, + jint row) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRowDescription(%X, %p, %d)", vmID, accessibleContext, + row); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRowDescription(%X, %016I64X, %d)", vmID, accessibleContext, + row); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableRowDescriptionPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableRowDescriptionPackage *pkg = (GetAccessibleTableRowDescriptionPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableRowDescriptionPackage; + pkg->vmID = vmID; + pkg->row = row; + pkg->accessibleContext = accessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRowDescription succeeded"); + return pkg->rAccessibleContext; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRowDescription failed"); + return (JOBJECT64)0; +} + +JOBJECT64 +WinAccessBridge::getAccessibleTableColumnDescription(long vmID, + JOBJECT64 accessibleContext, + jint column) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumnDescription(%X, %p, %d)", vmID, accessibleContext, + column); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumnDescription(%X, %016I64X, %d)", vmID, accessibleContext, + column); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableColumnDescriptionPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableColumnDescriptionPackage *pkg = + (GetAccessibleTableColumnDescriptionPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableColumnDescriptionPackage; + pkg->vmID = vmID; + pkg->column = column; + pkg->accessibleContext = accessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumnDescription succeeded"); + return pkg->rAccessibleContext; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumnDescription failed"); + return (JOBJECT64)0; +} + +jint +WinAccessBridge::getAccessibleTableRowSelectionCount(long vmID, JOBJECT64 accessibleTable) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRowSelectionCount(%X, %p)", vmID, accessibleTable); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRowSelectionCount(%X, %016I64X)", vmID, accessibleTable); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return 0; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableRowSelectionCountPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableRowSelectionCountPackage *pkg = + (GetAccessibleTableRowSelectionCountPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableRowSelectionCountPackage; + pkg->vmID = vmID; + pkg->accessibleTable = accessibleTable; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRowSelectionCount succeeded"); + return pkg->rCount; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRowSelectionCount failed"); + return 0; +} + +BOOL +WinAccessBridge::isAccessibleTableRowSelected(long vmID, JOBJECT64 accessibleTable, jint row) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::isAccessibleTableRowSelected(%X, %p)", vmID, accessibleTable); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::isAccessibleTableRowSelected(%X, %016I64X)", vmID, accessibleTable); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(IsAccessibleTableRowSelectedPackage)]; + PackageType *type = (PackageType *) buffer; + IsAccessibleTableRowSelectedPackage *pkg = (IsAccessibleTableRowSelectedPackage *) (buffer + sizeof(PackageType)); + *type = cIsAccessibleTableRowSelectedPackage; + pkg->vmID = vmID; + pkg->accessibleTable = accessibleTable; + pkg->row = row; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::isAccessibleTableRowSelected succeeded"); + return pkg->rResult; + } + } + PrintDebugString(" ##### WinAccessBridge::isAccessibleTableRowSelected failed"); + return FALSE; +} + +BOOL +WinAccessBridge::getAccessibleTableRowSelections(long vmID, JOBJECT64 accessibleTable, jint count, jint *selections) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRowSelections(%X, %p)", vmID, accessibleTable); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRowSelections(%X, %016I64X)", vmID, accessibleTable); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableRowSelectionsPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableRowSelectionsPackage *pkg = + (GetAccessibleTableRowSelectionsPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableRowSelectionsPackage; + pkg->vmID = vmID; + pkg->accessibleTable = accessibleTable; + pkg->count = count; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRowSelections succeeded"); + memcpy(selections, pkg->rSelections, count * sizeof(jint)); + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRowSelections failed"); + return FALSE; +} + + +jint +WinAccessBridge::getAccessibleTableColumnSelectionCount(long vmID, JOBJECT64 accessibleTable) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumnSelectionCount(%X, %p)", vmID, + accessibleTable); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumnSelectionCount(%X, %016I64X)", vmID, + accessibleTable); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableColumnSelectionCountPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableColumnSelectionCountPackage *pkg = + (GetAccessibleTableColumnSelectionCountPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableColumnSelectionCountPackage; + pkg->vmID = vmID; + pkg->accessibleTable = accessibleTable; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumnSelectionCount succeeded"); + return pkg->rCount; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumnSelectionCount failed"); + return 0; +} + +BOOL +WinAccessBridge::isAccessibleTableColumnSelected(long vmID, JOBJECT64 accessibleTable, jint column) { +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::isAccessibleTableColumnSelected(%X, %p)", vmID, accessibleTable); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::isAccessibleTableColumnSelected(%X, %016I64X)", vmID, accessibleTable); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(IsAccessibleTableColumnSelectedPackage)]; + PackageType *type = (PackageType *) buffer; + IsAccessibleTableColumnSelectedPackage *pkg = (IsAccessibleTableColumnSelectedPackage *) (buffer + sizeof(PackageType)); + *type = cIsAccessibleTableColumnSelectedPackage; + pkg->vmID = vmID; + pkg->accessibleTable = accessibleTable; + pkg->column = column; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::isAccessibleTableColumnSelected succeeded"); + return pkg->rResult; + } + } + PrintDebugString(" ##### WinAccessBridge::isAccessibleTableColumnSelected failed"); + return FALSE; +} + +BOOL +WinAccessBridge::getAccessibleTableColumnSelections(long vmID, JOBJECT64 accessibleTable, jint count, + jint *selections) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumnSelections(%X, %p)", vmID, accessibleTable); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumnSelections(%X, %016I64X)", vmID, accessibleTable); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableColumnSelectionsPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableColumnSelectionsPackage *pkg = + (GetAccessibleTableColumnSelectionsPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableColumnSelectionsPackage; + pkg->vmID = vmID; + pkg->count = count; + pkg->accessibleTable = accessibleTable; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumnSelections succeeded"); + memcpy(selections, pkg->rSelections, count * sizeof(jint)); + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumnSelections failed"); + return FALSE; +} + +jint +WinAccessBridge::getAccessibleTableRow(long vmID, JOBJECT64 accessibleTable, jint index) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRow(%X, %p, index=%d)", vmID, + accessibleTable, index); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableRow(%X, %016I64X, index=%d)", vmID, + accessibleTable, index); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableRowPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableRowPackage *pkg = + (GetAccessibleTableRowPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableRowPackage; + pkg->vmID = vmID; + pkg->accessibleTable = accessibleTable; + pkg->index = index; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRow succeeded"); + return pkg->rRow; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableRow failed"); + return 0; +} + +jint +WinAccessBridge::getAccessibleTableColumn(long vmID, JOBJECT64 accessibleTable, jint index) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumn(%X, %p, index=%d)", vmID, + accessibleTable, index); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableColumn(%X, %016I64X, index=%d)", vmID, + accessibleTable, index); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableColumnPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableColumnPackage *pkg = + (GetAccessibleTableColumnPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableColumnPackage; + pkg->vmID = vmID; + pkg->accessibleTable = accessibleTable; + pkg->index = index; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumn succeeded"); + return pkg->rColumn; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableColumn failed"); + return 0; +} + +jint +WinAccessBridge::getAccessibleTableIndex(long vmID, JOBJECT64 accessibleTable, jint row, jint column) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleTableIndex(%X, %p, row=%d, col=%d)", vmID, + accessibleTable, row, column); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleTableIndex(%X, %016I64X, row=%d, col=%d)", vmID, + accessibleTable, row, column); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTableIndexPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTableIndexPackage *pkg = + (GetAccessibleTableIndexPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTableIndexPackage; + pkg->vmID = vmID; + pkg->accessibleTable = accessibleTable; + pkg->row = row; + pkg->column = column; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableIndex succeeded"); + return pkg->rIndex; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleTableIndex failed"); + return 0; +} + +/********** end AccessibleTable routines ******************************/ + +BOOL +WinAccessBridge::getAccessibleRelationSet(long vmID, JOBJECT64 accessibleContext, + AccessibleRelationSetInfo *relationSetInfo) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleRelationSet(%X, %p, %X)", vmID, + accessibleContext, relationSetInfo); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleRelationSet(%X, %016I64X, %X)", vmID, + accessibleContext, relationSetInfo); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleRelationSetPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleRelationSetPackage *pkg = (GetAccessibleRelationSetPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleRelationSetPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### pkg->rAccessibleRelationSetInfo.relationCount = %X", + pkg->rAccessibleRelationSetInfo.relationCount); + memcpy(relationSetInfo, &(pkg->rAccessibleRelationSetInfo), sizeof(AccessibleRelationSetInfo)); + PrintDebugString(" ##### WinAccessBridge::getAccessibleRelationSet succeeded"); + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleRelationSet failed"); + return FALSE; +} + + +/********** AccessibleHypertext routines ***********/ + +BOOL +WinAccessBridge::getAccessibleHypertext(long vmID, JOBJECT64 accessibleContext, + AccessibleHypertextInfo *hypertextInfo) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleHypertext(%X, %p, %X)", vmID, + accessibleContext, hypertextInfo); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleHypertext(%X, %016I64X, %X)", vmID, + accessibleContext, hypertextInfo); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleHypertextPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleHypertextPackage *pkg = (GetAccessibleHypertextPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleHypertextPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(hypertextInfo, &(pkg->rAccessibleHypertextInfo), sizeof(AccessibleHypertextInfo)); + + PrintDebugString(" ##### hypertextInfo.linkCount = %d", hypertextInfo->linkCount); + PrintDebugString(" ##### WinAccessBridge::getAccessibleHypertext succeeded"); + + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleHypertext failed"); + return FALSE; +} + + +BOOL +WinAccessBridge::activateAccessibleHyperlink(long vmID, JOBJECT64 accessibleContext, + JOBJECT64 accessibleHyperlink) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::activateAccessibleHyperlink(%p %p)", accessibleContext, + accessibleHyperlink); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::activateAccessibleHyperlink(%016I64X %016I64X)", accessibleContext, + accessibleHyperlink); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(ActivateAccessibleHyperlinkPackage)]; + PackageType *type = (PackageType *) buffer; + ActivateAccessibleHyperlinkPackage *pkg = (ActivateAccessibleHyperlinkPackage *) (buffer + sizeof(PackageType)); + *type = cActivateAccessibleHyperlinkPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + pkg->accessibleHyperlink = accessibleHyperlink; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(pkg->vmID); + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rResult; + } + PrintDebugString(" WinAccessBridge::activateAccessibleHyperlink returning FALSE (sendMemoryPackage failed)"); + return FALSE; +} + +/* + * Returns the number of hyperlinks in a component + * Maps to AccessibleHypertext.getLinkCount. + * Returns -1 on error. + */ +jint +WinAccessBridge::getAccessibleHyperlinkCount(const long vmID, + const AccessibleContext accessibleContext) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleHyperlinkCount(%X, %p)", + vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleHyperlinkCount(%X, %016I64X)", + vmID, accessibleContext); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleHyperlinkCountPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleHyperlinkCountPackage *pkg = (GetAccessibleHyperlinkCountPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleHyperlinkCountPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### hypetext link count = %d", pkg->rLinkCount); + PrintDebugString(" ##### WinAccessBridge::getAccessibleHyperlinkCount succeeded"); + return pkg->rLinkCount; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleHyperlinkCount failed"); + return -1; +} + +/* + * This method is used to iterate through the hyperlinks in a component. It + * returns hypertext information for a component starting at hyperlink index + * nStartIndex. No more than MAX_HYPERLINKS AccessibleHypertextInfo objects will + * be returned for each call to this method. + * returns FALSE on error. + */ +BOOL +WinAccessBridge::getAccessibleHypertextExt(const long vmID, + const AccessibleContext accessibleContext, + const jint startIndex, + /* OUT */ AccessibleHypertextInfo *hypertextInfo) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleHypertextExt(%X, %p %p)", vmID, + accessibleContext, hypertextInfo); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleHypertextExt(%X, %016I64X %p)", vmID, + accessibleContext, hypertextInfo); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleHypertextExtPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleHypertextExtPackage *pkg = (GetAccessibleHypertextExtPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleHypertextExtPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + pkg->startIndex = startIndex; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### pkg->rSuccess = %d", pkg->rSuccess); + + memcpy(hypertextInfo, &(pkg->rAccessibleHypertextInfo), sizeof(AccessibleHypertextInfo)); + if (pkg->rSuccess == TRUE) { + PrintDebugString(" ##### hypertextInfo.linkCount = %d", hypertextInfo->linkCount); + PrintDebugString(" ##### hypertextInfo.linkCount = %d", hypertextInfo->linkCount); + } else { + PrintDebugString(" ##### WinAccessBridge::getAccessibleHypertextExt failed"); + } + return pkg->rSuccess;; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleHypertextExt failed"); + return FALSE; +} + + +/* + * Returns the index into an array of hyperlinks that is associated with + * a character index in document; + * Maps to AccessibleHypertext.getLinkIndex. + * Returns -1 on error. + */ +jint +WinAccessBridge::getAccessibleHypertextLinkIndex(const long vmID, + const AccessibleHyperlink hypertext, + const jint charIndex) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleHypertextLinkIndex(%X, %p)", + vmID, hypertext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleHypertextLinkIndex(%X, %016I64X)", + vmID, hypertext); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleHypertextLinkIndexPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleHypertextLinkIndexPackage *pkg = (GetAccessibleHypertextLinkIndexPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleHypertextLinkIndexPackage; + pkg->vmID = vmID; + pkg->hypertext = hypertext; + pkg->charIndex = charIndex; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" ##### hypetext link index = %d", pkg->rLinkIndex); + PrintDebugString(" ##### WinAccessBridge::getAccessibleHypertextLinkIndex succeeded"); + return pkg->rLinkIndex; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleHypertextLinkIndex failed"); + return -1; +} + +/* + * Returns the nth hyperlink in a document. + * Maps to AccessibleHypertext.getLink. + * Returns -1 on error + */ +BOOL +WinAccessBridge::getAccessibleHyperlink(const long vmID, + const AccessibleHyperlink hypertext, + const jint linkIndex, + /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleHyperlink(%X, %p, %p)", vmID, + hypertext, hyperlinkInfo); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleHyperlink(%X, %016I64X, %p)", vmID, + hypertext, hyperlinkInfo); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleHyperlinkPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleHyperlinkPackage *pkg = (GetAccessibleHyperlinkPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleHyperlinkPackage; + pkg->vmID = vmID; + pkg->hypertext = hypertext; + pkg->linkIndex = linkIndex; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(hyperlinkInfo, &(pkg->rAccessibleHyperlinkInfo), + sizeof(AccessibleHyperlinkInfo)); + PrintDebugString(" ##### WinAccessBridge::getAccessibleHypertext succeeded"); + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleHypertext failed"); + return FALSE; +} + + +/********** AccessibleKeyBinding routines ***********/ + +BOOL +WinAccessBridge::getAccessibleKeyBindings(long vmID, JOBJECT64 accessibleContext, + AccessibleKeyBindings *keyBindings) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleKeyBindings(%X, %p, %p)", vmID, + accessibleContext, keyBindings); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleKeyBindings(%X, %016I64X, %p)", vmID, + accessibleContext, keyBindings); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleKeyBindingsPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleKeyBindingsPackage *pkg = (GetAccessibleKeyBindingsPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleKeyBindingsPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(keyBindings, &(pkg->rAccessibleKeyBindings), sizeof(AccessibleKeyBindings)); + + PrintDebugString(" ##### keyBindings.keyBindingsCount = %d", keyBindings->keyBindingsCount); + for (int i = 0; i < keyBindings->keyBindingsCount; ++i) { + PrintDebugString(" Key Binding # %d", i+1); + PrintDebugString(" Modifiers: 0x%x", keyBindings->keyBindingInfo[i].modifiers); + PrintDebugString(" Character (hex): 0x%x", keyBindings->keyBindingInfo[i].character); + PrintDebugString(" Character (wide char): %lc", keyBindings->keyBindingInfo[i].character); + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleKeyBindings succeeded"); + + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleKeyBindings failed"); + return FALSE; +} + +BOOL +WinAccessBridge::getAccessibleIcons(long vmID, JOBJECT64 accessibleContext, AccessibleIcons *icons) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleIcons(%X, %p, %p)", vmID, + accessibleContext, icons); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleIcons(%X, %016I64X, %p)", vmID, + accessibleContext, icons); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleIconsPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleIconsPackage *pkg = (GetAccessibleIconsPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleIconsPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(icons, &(pkg->rAccessibleIcons), sizeof(AccessibleIcons)); + + PrintDebugString(" ##### icons.iconsCount = %d", icons->iconsCount); + PrintDebugString(" ##### WinAccessBridge::getAccessibleIcons succeeded"); + + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleIcons failed"); + return FALSE; +} + +BOOL +WinAccessBridge::getAccessibleActions(long vmID, JOBJECT64 accessibleContext, AccessibleActions *actions) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("##### WinAccessBridge::getAccessibleActions(%X, %p, %p)", vmID, + accessibleContext, actions); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("##### WinAccessBridge::getAccessibleActions(%X, %016I64X, %p)", vmID, + accessibleContext, actions); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + + char buffer[sizeof(PackageType) + sizeof(GetAccessibleActionsPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleActionsPackage *pkg = (GetAccessibleActionsPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleActionsPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(actions, &(pkg->rAccessibleActions), sizeof(AccessibleActions)); + + PrintDebugString(" ##### actions.actionsCount = %d", actions->actionsCount); + PrintDebugString(" ##### WinAccessBridge::getAccessibleActions succeeded"); + + return TRUE; + } + } + PrintDebugString(" ##### WinAccessBridge::getAccessibleActions failed"); + return FALSE; +} + +BOOL +WinAccessBridge::doAccessibleActions(long vmID, JOBJECT64 accessibleContext, + AccessibleActionsToDo *actionsToDo, jint *failure) { + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::doAccessibleActions(%p #actions %d %ls)", accessibleContext, + actionsToDo->actionsCount, + actionsToDo->actions[0].name); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::doAccessibleActions(%016I64X #actions %d %ls)", accessibleContext, + actionsToDo->actionsCount, + actionsToDo->actions[0].name); +#endif + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(DoAccessibleActionsPackage)]; + PackageType *type = (PackageType *) buffer; + DoAccessibleActionsPackage *pkg = (DoAccessibleActionsPackage *) (buffer + sizeof(PackageType)); + *type = cDoAccessibleActionsPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + memcpy((void *)(&(pkg->actionsToDo)), (void *)actionsToDo, sizeof(AccessibleActionsToDo)); + pkg->failure = -1; + + HWND destABWindow = javaVMs->findAccessBridgeWindow(pkg->vmID); + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + *failure = pkg->failure; + return pkg->rResult; + } + PrintDebugString(" WinAccessBridge::doAccessibleActions returning FALSE (sendMemoryPackage failed)"); + return FALSE; +} + +/* ====== Utility methods ====== */ + +/** + * Sets a text field to the specified string. Returns whether successful. + */ +BOOL +WinAccessBridge::setTextContents (const long vmID, const AccessibleContext accessibleContext, + const wchar_t *text) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(SetTextContentsPackage)]; + PackageType *type = (PackageType *) buffer; + SetTextContentsPackage *pkg = (SetTextContentsPackage *) (buffer + sizeof(PackageType)); + *type = cSetTextContentsPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + wcsncpy(pkg->text, text, sizeof(pkg->text)/sizeof(wchar_t)); // wide character copy + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::setTextContents(%X, %016I64X %ls)", vmID, accessibleContext, text); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::setTextContents(%X, %p %ls)", vmID, accessibleContext, text); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rResult; + } + } + return FALSE; +} + +/** + * Returns the Accessible Context of a Page Tab object that is the + * ancestor of a given object. If the object is a Page Tab object + * or a Page Tab ancestor object was found, returns the object + * AccessibleContext. + * If there is no ancestor object that has an Accessible Role of Page Tab, + * returns (AccessibleContext)0. + */ +AccessibleContext +WinAccessBridge::getParentWithRole (const long vmID, const AccessibleContext accessibleContext, const wchar_t *role) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return (JOBJECT64)0; + } + char buffer[sizeof(PackageType) + sizeof(GetParentWithRolePackage)]; + PackageType *type = (PackageType *) buffer; + GetParentWithRolePackage *pkg = (GetParentWithRolePackage *) (buffer + sizeof(PackageType)); + *type = cGetParentWithRolePackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + memcpy((void *)(&(pkg->role)), (void *)role, sizeof(pkg->role)); + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getParentWithRole(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getParentWithRole(%X, %016I64X)", vmID, accessibleContext); +#endif + PrintDebugString(" pkg->vmID: %X", pkg->vmID); + PrintDebugString(" pkg->accessibleContext: %p", pkg->accessibleContext); + PrintDebugString(" pkg->role: %ls", pkg->role); + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + PrintDebugString(" pkg->rAccessibleContext: %p", pkg->rAccessibleContext); + return pkg->rAccessibleContext; + } + } + return (JOBJECT64) 0; +} + + +/** + * Returns the Accessible Context for the top level object in + * a Java Window. This is same Accessible Context that is obtained + * from GetAccessibleContextFromHWND for that window. Returns + * (AccessibleContext)0 on error. + */ +AccessibleContext +WinAccessBridge::getTopLevelObject (const long vmID, const AccessibleContext accessibleContext) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return (JOBJECT64)0; + } + char buffer[sizeof(PackageType) + sizeof(GetTopLevelObjectPackage)]; + PackageType *type = (PackageType *) buffer; + GetTopLevelObjectPackage *pkg = (GetTopLevelObjectPackage *) (buffer + sizeof(PackageType)); + *type = cGetTopLevelObjectPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getTopLevelObject(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getTopLevelObject(%X, %016I64X)", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rAccessibleContext; + } + } + return (JOBJECT64) 0; +} + +/** + * If there is an Ancestor object that has an Accessible Role of + * Internal Frame, returns the Accessible Context of the Internal + * Frame object. Otherwise, returns the top level object for that + * Java Window. Returns (AccessibleContext)0 on error. + */ +AccessibleContext +WinAccessBridge::getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext, const wchar_t *role) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return (JOBJECT64)0; + } + char buffer[sizeof(PackageType) + sizeof(GetParentWithRoleElseRootPackage)]; + PackageType *type = (PackageType *) buffer; + GetParentWithRoleElseRootPackage *pkg = (GetParentWithRoleElseRootPackage *) (buffer + sizeof(PackageType)); + *type = cGetParentWithRoleElseRootPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + memcpy((void *)(&(pkg->role)), (void *)role, sizeof(pkg->role)); + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getParentWithRoleElseRoot(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getParentWithRoleElseRoot(%X, %016I64X)", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rAccessibleContext; + } + } + return (JOBJECT64) 0; +} + +/** + * Returns how deep in the object hierarchy a given object is. + * The top most object in the object hierarchy has an object depth of 0. + * Returns -1 on error. + */ +int +WinAccessBridge::getObjectDepth (const long vmID, const AccessibleContext accessibleContext) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return -1; + } + char buffer[sizeof(PackageType) + sizeof(GetObjectDepthPackage)]; + PackageType *type = (PackageType *) buffer; + GetObjectDepthPackage *pkg = (GetObjectDepthPackage *) (buffer + sizeof(PackageType)); + *type = cGetObjectDepthPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getObjectDepth(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getObjectDepth(%X, %016I64X)", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rResult; + } + } + return -1; +} + +/** + * Returns the Accessible Context of the currently ActiveDescendent of an object. + * Returns (AccessibleContext)0 on error. + */ +AccessibleContext +WinAccessBridge::getActiveDescendent (const long vmID, const AccessibleContext accessibleContext) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return (JOBJECT64)0; + } + char buffer[sizeof(PackageType) + sizeof(GetActiveDescendentPackage)]; + PackageType *type = (PackageType *) buffer; + GetActiveDescendentPackage *pkg = (GetActiveDescendentPackage *) (buffer + sizeof(PackageType)); + *type = cGetActiveDescendentPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getActiveDescendent(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getActiveDescendent(%X, %016I64X)", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rAccessibleContext; + } + } + return (JOBJECT64) 0; +} + +/** + * Additional methods for Teton + */ + +/** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ +BOOL +WinAccessBridge::getVirtualAccessibleName(long vmID, AccessibleContext accessibleContext, + wchar_t *name, int len) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetVirtualAccessibleNamePackage)]; + PackageType *type = (PackageType *) buffer; + GetVirtualAccessibleNamePackage *pkg = (GetVirtualAccessibleNamePackage *) (buffer + sizeof(PackageType)); + *type = cGetVirtualAccessibleNamePackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + size_t max = (len > sizeof(pkg->rName)) ? sizeof(pkg->rName) : len; + pkg->len = (int)max; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getVirtualAccessibleName(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getVirtualAccessibleName(%X, %016I64X)", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + wcsncpy(name, pkg->rName, max); + PrintDebugString(" WinAccessBridge::getVirtualAccessibleName: Virtual name = %ls", name); + return TRUE; + } + } + return FALSE; +} + +/** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ +BOOL +WinAccessBridge::requestFocus(long vmID, AccessibleContext accessibleContext) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(RequestFocusPackage)]; + PackageType *type = (PackageType *) buffer; + RequestFocusPackage *pkg = (RequestFocusPackage *) (buffer + sizeof(PackageType)); + *type = cRequestFocusPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::requestFocus(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::requestFocus(%X, %016I64X)", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return TRUE; + } + } + return FALSE; +} + +/** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ +BOOL +WinAccessBridge::selectTextRange(long vmID, AccessibleContext accessibleContext, int startIndex, int endIndex) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(SelectTextRangePackage)]; + PackageType *type = (PackageType *) buffer; + SelectTextRangePackage *pkg = (SelectTextRangePackage *) (buffer + sizeof(PackageType)); + *type = cSelectTextRangePackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + pkg->startIndex = startIndex; + pkg->endIndex = endIndex; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" WinAccessBridge::selectTextRange(%X, %p %d %d)", vmID, accessibleContext, + startIndex, endIndex); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" WinAccessBridge::selectTextRange(%X, %016I64X %d %d)", vmID, accessibleContext, + startIndex, endIndex); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return TRUE; + } + } + return FALSE; +} + +/** + * Get text attributes between two indices. The attribute list includes the text at the + * start index and the text at the end index. Returns whether successful; + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ +BOOL +WinAccessBridge::getTextAttributesInRange(long vmID, AccessibleContext accessibleContext, + int startIndex, int endIndex, + AccessibleTextAttributesInfo *attributes, short *len) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetTextAttributesInRangePackage)]; + PackageType *type = (PackageType *) buffer; + GetTextAttributesInRangePackage *pkg = (GetTextAttributesInRangePackage *) (buffer + sizeof(PackageType)); + *type = cGetTextAttributesInRangePackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + pkg->startIndex = startIndex; + pkg->endIndex = endIndex; + memcpy(&(pkg->attributes), attributes, sizeof(AccessibleTextAttributesInfo)); + + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString(" WinAccessBridge::getTextAttributesInRange(%X, %p %d %d)", vmID, accessibleContext, + startIndex, endIndex); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString(" WinAccessBridge::getTextAttributesInRange(%X, %016I64X %d %d)", vmID, accessibleContext, + startIndex, endIndex); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + *attributes = pkg->attributes; + *len = pkg->rLength; + return TRUE; + } + } + return FALSE; +} + +/** + * Gets the number of visible children of a component. Returns -1 on error. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ +int +WinAccessBridge::getVisibleChildrenCount(long vmID, AccessibleContext accessibleContext) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return -1; + } + char buffer[sizeof(PackageType) + sizeof(GetVisibleChildrenCountPackage)]; + PackageType *type = (PackageType *) buffer; + GetVisibleChildrenCountPackage *pkg = (GetVisibleChildrenCountPackage *) (buffer + sizeof(PackageType)); + *type = cGetVisibleChildrenCountPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getVisibleChildrenCount(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getVisibleChildrenCount(%X, %016I64X)", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rChildrenCount; + } + } + return -1; +} + +/** + * Gets the visible children of an AccessibleContext. Returns whether successful; + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ +BOOL +WinAccessBridge::getVisibleChildren(long vmID, AccessibleContext accessibleContext, int startIndex, + VisibleChildrenInfo *visibleChildrenInfo) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetVisibleChildrenPackage)]; + PackageType *type = (PackageType *) buffer; + GetVisibleChildrenPackage *pkg = (GetVisibleChildrenPackage *) (buffer + sizeof(PackageType)); + *type = cGetVisibleChildrenPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + pkg->startIndex = startIndex; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getVisibleChildren(%X, %p)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getVisibleChildren(%X, %016I64X)", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(visibleChildrenInfo, &(pkg->rVisibleChildrenInfo), sizeof(pkg->rVisibleChildrenInfo)); + return pkg->rSuccess; + } + } + return FALSE; +} + +/** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ +BOOL +WinAccessBridge::setCaretPosition(long vmID, AccessibleContext accessibleContext, int position) { + + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(SetCaretPositionPackage)]; + PackageType *type = (PackageType *) buffer; + SetCaretPositionPackage *pkg = (SetCaretPositionPackage *) (buffer + sizeof(PackageType)); + *type = cSetCaretPositionPackage; + pkg->vmID = vmID; + pkg->accessibleContext = accessibleContext; + pkg->position = position; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::setCaretPosition(%X, %p %ls)", vmID, accessibleContext); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::setCaretPosition(%X, %016I64X %ls)", vmID, accessibleContext); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return TRUE; + } + } + return FALSE; +} + + +/********** AccessibleText routines ***********************************/ + +/** + * getAccessibleTextInfo - fills a struct with a bunch of information + * contained in the Java Accessibility AccessibleText API + * + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +BOOL +WinAccessBridge::getAccessibleTextInfo(long vmID, + JOBJECT64 AccessibleContext, + AccessibleTextInfo *textInfo, + jint x, jint y) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTextInfoPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTextInfoPackage *pkg = (GetAccessibleTextInfoPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTextInfoPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->x = x; + pkg->y = y; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getAccessibleTextInfo(%X, %p, %p, %d, %d)", vmID, AccessibleContext, textInfo, x, y); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getAccessibleTextInfo(%X, %016I64X, %p, %d, %d)", vmID, AccessibleContext, textInfo, x, y); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(textInfo, &(pkg->rTextInfo), sizeof(AccessibleTextInfo)); + if (pkg->rTextInfo.charCount != -1) { + PrintDebugString(" charCount: %d", textInfo->charCount); + PrintDebugString(" caretIndex: %d", textInfo->caretIndex); + PrintDebugString(" indexAtPoint: %d", textInfo->indexAtPoint); + return TRUE; + } + } + } + + return FALSE; +} + +/** + * getAccessibleTextItems - fills a struct with letter, word, and sentence info + * of the AccessibleText interface at a given index + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +BOOL +WinAccessBridge::getAccessibleTextItems(long vmID, + JOBJECT64 AccessibleContext, + AccessibleTextItemsInfo *textItems, + jint index) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTextItemsPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTextItemsPackage *pkg = (GetAccessibleTextItemsPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTextItemsPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->index = index; + // zero things out, in case the call fails + pkg->rTextItemsInfo.letter = '\0'; + pkg->rTextItemsInfo.word[0] = '\0'; + pkg->rTextItemsInfo.sentence[0] = '\0'; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getAccessibleTextItems(%X, %p, %p, %d)", vmID, AccessibleContext, textItems, index); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getAccessibleTextItems(%X, %016I64X, %p, %d)", vmID, AccessibleContext, textItems, index); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(textItems, &(pkg->rTextItemsInfo), sizeof(AccessibleTextItemsInfo)); + if (pkg->rTextItemsInfo.letter != '/0') { + return TRUE; + } + } + } + + return FALSE; +} + +/** + * getAccessibleTextSelectionInfo - returns information about the selected + * text of the object implementing AccessibleText + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +BOOL +WinAccessBridge::getAccessibleTextSelectionInfo(long vmID, + JOBJECT64 AccessibleContext, + AccessibleTextSelectionInfo *selectionInfo) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTextSelectionInfoPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTextSelectionInfoPackage *pkg = (GetAccessibleTextSelectionInfoPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTextSelectionInfoPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getAccessibleTextSelectionInfo(%X, %p, %p)", vmID, AccessibleContext, selectionInfo); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getAccessibleTextSelectionInfo(%X, %016I64X, %p)", vmID, AccessibleContext, selectionInfo); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(selectionInfo, &(pkg->rTextSelectionItemsInfo), sizeof(AccessibleTextSelectionInfo)); + // [[[FIXME]]] should test to see if valid info returned; return FALSE if not + return TRUE; + } + } + + return FALSE; +} + +/** + * getAccessibleTextAttributes - performs the Java code: + * ...[[[FIXME]]] fill in this comment... + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +BOOL +WinAccessBridge::getAccessibleTextAttributes(long vmID, + JOBJECT64 AccessibleContext, + jint index, + AccessibleTextAttributesInfo *attributes) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTextAttributeInfoPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTextAttributeInfoPackage *pkg = (GetAccessibleTextAttributeInfoPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTextAttributeInfoPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->index = index; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getAccessibleTextAttributes(%X, %p, %d, %p)", vmID, AccessibleContext, index, attributes); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getAccessibleTextAttributes(%X, %016I64X, %d, %p)", vmID, AccessibleContext, index, attributes); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(attributes, &(pkg->rAttributeInfo), sizeof(AccessibleTextAttributesInfo)); + return TRUE; + } + } + + return FALSE; +} + +/** + * getAccessibleTextRect - gets the text bounding rectangle + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +BOOL +WinAccessBridge::getAccessibleTextRect(long vmID, + JOBJECT64 AccessibleContext, + AccessibleTextRectInfo *rectInfo, + jint index) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTextRectInfoPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTextRectInfoPackage *pkg = (GetAccessibleTextRectInfoPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTextRectInfoPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->index = index; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getAccessibleTextRect(%X, %p, %p, %d)", vmID, AccessibleContext, rectInfo, index); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getAccessibleTextRect(%X, %016I64X, %p, %d)", vmID, AccessibleContext, rectInfo, index); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(rectInfo, (&pkg->rTextRectInfo), sizeof(AccessibleTextRectInfo)); + // [[[FIXME]]] should test to see if valid info returned; return FALSE if not + return TRUE; + } + } + + return FALSE; +} + + +/** + * getAccessibleTextRect - gets the text bounding rectangle + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +BOOL +WinAccessBridge::getCaretLocation(long vmID, + JOBJECT64 AccessibleContext, + AccessibleTextRectInfo *rectInfo, + jint index) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetCaretLocationPackage)]; + PackageType *type = (PackageType *) buffer; + GetCaretLocationPackage *pkg = (GetCaretLocationPackage *) (buffer + sizeof(PackageType)); + *type = cGetCaretLocationPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->index = index; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getCaretLocation(%X, %p, %p, %d)", vmID, AccessibleContext, rectInfo, index); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getCaretLocation(%X, %016I64X, %p, %d)", vmID, AccessibleContext, rectInfo, index); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + memcpy(rectInfo, (&pkg->rTextRectInfo), sizeof(AccessibleTextRectInfo)); + return TRUE; + } + } + + return FALSE; +} + + +/** + * getEventsWaiting - gets the number of events waiting to fire + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +int +WinAccessBridge::getEventsWaiting() { + if(messageQueue) { + return(messageQueue->getEventsWaiting()); + } + return(0); +} + + +/** + * getAccessibleTextLineBounds - gets the bounding rectangle for the text line + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +BOOL +WinAccessBridge::getAccessibleTextLineBounds(long vmID, + JOBJECT64 AccessibleContext, + jint index, jint *startIndex, jint *endIndex) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTextLineBoundsPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTextLineBoundsPackage *pkg = (GetAccessibleTextLineBoundsPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTextLineBoundsPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->index = index; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getAccessibleTextLineBounds(%X, %p, %d, )", vmID, AccessibleContext, index); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getAccessibleTextLineBounds(%X, %016I64X, %d, )", vmID, AccessibleContext, index); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + *startIndex = pkg->rLineStart; + *endIndex = pkg->rLineEnd; + // [[[FIXME]]] should test to see if valid info returned; return FALSE if not + return TRUE; + } + } + + return FALSE; +} + + +/** + * getAccessibleTextLineBounds - performs the Java code: + * ...[[[FIXME]]] fill in this comment... + * + * Note: if the AccessibleContext parameter is bogus, this call will blow up + */ +BOOL +WinAccessBridge::getAccessibleTextRange(long vmID, + JOBJECT64 AccessibleContext, + jint start, jint end, wchar_t *text, short len) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleTextRangePackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleTextRangePackage *pkg = (GetAccessibleTextRangePackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleTextRangePackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->start = start; + pkg->end = end; + +#ifdef ACCESSBRIDGE_ARCH_LEGACY // JOBJECT64 is jobject (32 bit pointer) + PrintDebugString("WinAccessBridge::getAccessibleTextRange(%X, %p, %d, %d, )", vmID, AccessibleContext, start, end); +#else // JOBJECT64 is jlong (64 bit) + PrintDebugString("WinAccessBridge::getAccessibleTextRange(%X, %016I64X, %d, %d, )", vmID, AccessibleContext, start, end); +#endif + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + wcsncpy(text, pkg->rText, len); + // [[[FIXME]]] should test to see if valid info returned; return FALSE if not + return TRUE; + } + } + + return FALSE; +} + + + + +/********** AccessibleValue routines ***************/ + +BOOL +WinAccessBridge::getCurrentAccessibleValueFromContext(long vmID, + JOBJECT64 AccessibleContext, + wchar_t *value, short len) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetCurrentAccessibleValueFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + GetCurrentAccessibleValueFromContextPackage *pkg = (GetCurrentAccessibleValueFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cGetCurrentAccessibleValueFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + wcsncpy(value, pkg->rValue, len); + // [[[FIXME]]] should test to see if valid info returned; return FALSE if not + return TRUE; + } + } + + return FALSE; +} + +BOOL +WinAccessBridge::getMaximumAccessibleValueFromContext(long vmID, + JOBJECT64 AccessibleContext, + wchar_t *value, short len) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetMaximumAccessibleValueFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + GetMaximumAccessibleValueFromContextPackage *pkg = (GetMaximumAccessibleValueFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cGetMaximumAccessibleValueFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + wcsncpy(value, pkg->rValue, len); + // [[[FIXME]]] should test to see if valid info returned; return FALSE if not + return TRUE; + } + } + + return FALSE; +} + +BOOL +WinAccessBridge::getMinimumAccessibleValueFromContext(long vmID, + JOBJECT64 AccessibleContext, + wchar_t *value, short len) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(GetMinimumAccessibleValueFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + GetMinimumAccessibleValueFromContextPackage *pkg = (GetMinimumAccessibleValueFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cGetMinimumAccessibleValueFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + wcsncpy(value, pkg->rValue, len); + // [[[FIXME]]] should test to see if valid info returned; return FALSE if not + return TRUE; + } + } + + return FALSE; +} + + +/********** AccessibleSelection routines ***************/ + +void +WinAccessBridge::addAccessibleSelectionFromContext(long vmID, + JOBJECT64 AccessibleContext, int i) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + char buffer[sizeof(PackageType) + sizeof(AddAccessibleSelectionFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + AddAccessibleSelectionFromContextPackage *pkg = (AddAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cAddAccessibleSelectionFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->index = i; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + sendMemoryPackage(buffer, sizeof(buffer), destABWindow); + } +} + +void +WinAccessBridge::clearAccessibleSelectionFromContext(long vmID, + JOBJECT64 AccessibleContext) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + char buffer[sizeof(PackageType) + sizeof(ClearAccessibleSelectionFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + ClearAccessibleSelectionFromContextPackage *pkg = (ClearAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cClearAccessibleSelectionFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + sendMemoryPackage(buffer, sizeof(buffer), destABWindow); + } +} + +JOBJECT64 +WinAccessBridge::getAccessibleSelectionFromContext(long vmID, + JOBJECT64 AccessibleContext, int i) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return (JOBJECT64)0; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleSelectionFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleSelectionFromContextPackage *pkg = (GetAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleSelectionFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->index = i; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return pkg->rAccessibleContext; + } + } + + return (JOBJECT64) 0; +} + +int +WinAccessBridge::getAccessibleSelectionCountFromContext(long vmID, + JOBJECT64 AccessibleContext) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return -1; + } + char buffer[sizeof(PackageType) + sizeof(GetAccessibleSelectionCountFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + GetAccessibleSelectionCountFromContextPackage *pkg = (GetAccessibleSelectionCountFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cGetAccessibleSelectionCountFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + return (int) pkg->rCount; + } + } + + return -1; +} + +BOOL +WinAccessBridge::isAccessibleChildSelectedFromContext(long vmID, + JOBJECT64 AccessibleContext, int i) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return FALSE; + } + char buffer[sizeof(PackageType) + sizeof(IsAccessibleChildSelectedFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + IsAccessibleChildSelectedFromContextPackage *pkg = (IsAccessibleChildSelectedFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cIsAccessibleChildSelectedFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->index = i; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + if (sendMemoryPackage(buffer, sizeof(buffer), destABWindow) == TRUE) { + if (pkg->rResult != 0) { + return TRUE; + } + } + } + + return FALSE; +} + + +void +WinAccessBridge::removeAccessibleSelectionFromContext(long vmID, + JOBJECT64 AccessibleContext, int i) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + char buffer[sizeof(PackageType) + sizeof(RemoveAccessibleSelectionFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + RemoveAccessibleSelectionFromContextPackage *pkg = (RemoveAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cRemoveAccessibleSelectionFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + pkg->index = i; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + sendMemoryPackage(buffer, sizeof(buffer), destABWindow); + } +} + +void +WinAccessBridge::selectAllAccessibleSelectionFromContext(long vmID, + JOBJECT64 AccessibleContext) { + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + char buffer[sizeof(PackageType) + sizeof(SelectAllAccessibleSelectionFromContextPackage)]; + PackageType *type = (PackageType *) buffer; + SelectAllAccessibleSelectionFromContextPackage *pkg = (SelectAllAccessibleSelectionFromContextPackage *) (buffer + sizeof(PackageType)); + *type = cSelectAllAccessibleSelectionFromContextPackage; + pkg->vmID = vmID; + pkg->AccessibleContext = AccessibleContext; + + // need to call only the HWND/VM that contains this AC + HWND destABWindow = javaVMs->findAccessBridgeWindow(vmID); + if (destABWindow != (HWND) 0) { + sendMemoryPackage(buffer, sizeof(buffer), destABWindow); + } +} + + +/*********** Event handling methods **********************************/ + +/** + * addEventNotification - tell all Java-launched AccessBridge DLLs + * that we want events of the specified type + * + * [[[FIXME]]] since we're just sending a long & a source window, + * we could use a private message rather than WM_COPYDATA + * (though we still may want it to be synchronous; dunno...) + * + */ +void +WinAccessBridge::addJavaEventNotification(jlong type) { + PrintDebugString("WinAccessBridge::addJavaEventNotification(%016I64X)", type); + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + + char buffer[sizeof(PackageType) + sizeof(AddJavaEventNotificationPackage)]; + PackageType *pkgType = (PackageType *) buffer; + AddJavaEventNotificationPackage *pkg = (AddJavaEventNotificationPackage *) (buffer + sizeof(PackageType)); + *pkgType = cAddJavaEventNotificationPackage; + pkg->type = type; + pkg->DLLwindow = ABHandleToLong(dialogWindow); + + PrintDebugString(" ->pkgType = %X, eventType = %016I64X, DLLwindow = %p", + *pkgType, pkg->type, pkg->DLLwindow); + + // send addEventNotification message to all JVMs + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *current = javaVMs; + while (current != (AccessBridgeJavaVMInstance *) 0) { + current->sendPackage(buffer, sizeof(buffer)); // no return values! + current = current->nextJVMInstance; + } + isVMInstanceChainInUse = false; +} + +/** + * removeEventNotification - tell all Java-launched AccessBridge DLLs + * that we no longer want events of the + * specified type + * + * [[[FIXME]]] since we're just sending a long & a source window, + * we could use a private message rather than WM_COPYDATA + * (though we still may want it to be synchronous; dunno...) + * + */ +void +WinAccessBridge::removeJavaEventNotification(jlong type) { + PrintDebugString("in WinAccessBridge::removeJavaEventNotification(%016I64X)", type); + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + char buffer[sizeof(PackageType) + sizeof(RemoveJavaEventNotificationPackage)]; + PackageType *pkgType = (PackageType *) buffer; + RemoveJavaEventNotificationPackage *pkg = (RemoveJavaEventNotificationPackage *) (buffer + sizeof(PackageType)); + *pkgType = cRemoveJavaEventNotificationPackage; + pkg->type = type; + pkg->DLLwindow = ABHandleToLong(dialogWindow); + + PrintDebugString(" ->pkgType = %X, eventType = %016I64X, DLLwindow = %p", + *pkgType, pkg->type, pkg->DLLwindow); + + // send removeEventNotification message to all JVMs + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *current = javaVMs; + while (current != (AccessBridgeJavaVMInstance *) 0) { + current->sendPackage(buffer, sizeof(buffer)); // no return values! + current = current->nextJVMInstance; + } + isVMInstanceChainInUse = false; +} + + +/*********** Event handling methods **********************************/ + +/** + * addAccessibilityEventNotification - tell all Java-launched AccessBridge DLLs + * that we want events of the specified type + * + * [[[FIXME]]] since we're just sending a long & a source window, + * we could use a private message rather than WM_COPYDATA + * (though we still may want it to be synchronous; dunno...) + * + */ +void +WinAccessBridge::addAccessibilityEventNotification(jlong type) { + PrintDebugString("in WinAccessBridge::addAccessibilityEventNotification(%016I64X)", type); + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + char buffer[sizeof(PackageType) + sizeof(AddAccessibilityEventNotificationPackage)]; + PackageType *pkgType = (PackageType *) buffer; + AddAccessibilityEventNotificationPackage *pkg = (AddAccessibilityEventNotificationPackage *) (buffer + sizeof(PackageType)); + *pkgType = cAddAccessibilityEventNotificationPackage; + pkg->type = type; + pkg->DLLwindow = ABHandleToLong(dialogWindow); + + PrintDebugString(" ->pkgType = %X, eventType = %016I64X, DLLwindow = %X", + *pkgType, pkg->type, pkg->DLLwindow); + + // send addEventNotification message to all JVMs + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *current = javaVMs; + while (current != (AccessBridgeJavaVMInstance *) 0) { + current->sendPackage(buffer, sizeof(buffer)); // no return values! + current = current->nextJVMInstance; + } + isVMInstanceChainInUse = false; +} + +/** + * removeAccessibilityEventNotification - tell all Java-launched AccessBridge DLLs + * that we no longer want events of the + * specified type + * + * [[[FIXME]]] since we're just sending a long & a source window, + * we could use a private message rather than WM_COPYDATA + * (though we still may want it to be synchronous; dunno...) + * + */ +void +WinAccessBridge::removeAccessibilityEventNotification(jlong type) { + PrintDebugString("in WinAccessBridge::removeAccessibilityEventNotification(%016I64X)", type); + if ((AccessBridgeJavaVMInstance *) 0 == javaVMs) { + return; + } + char buffer[sizeof(PackageType) + sizeof(RemoveAccessibilityEventNotificationPackage)]; + PackageType *pkgType = (PackageType *) buffer; + RemoveAccessibilityEventNotificationPackage *pkg = (RemoveAccessibilityEventNotificationPackage *) (buffer + sizeof(PackageType)); + *pkgType = cRemoveAccessibilityEventNotificationPackage; + pkg->type = type; + pkg->DLLwindow = ABHandleToLong(dialogWindow); + + PrintDebugString(" ->pkgType = %X, eventType = %016I64X, DLLwindow = %X", + *pkgType, pkg->type, pkg->DLLwindow); + + // send removeEventNotification message to all JVMs + isVMInstanceChainInUse = true; + AccessBridgeJavaVMInstance *current = javaVMs; + while (current != (AccessBridgeJavaVMInstance *) 0) { + current->sendPackage(buffer, sizeof(buffer)); // no return values! + current = current->nextJVMInstance; + } + isVMInstanceChainInUse = false; +} + + +#define CALL_SET_EVENT_FP(function, callbackFP) \ + void WinAccessBridge::function(callbackFP fp) { \ + eventHandler->function(fp, this); \ + /* eventHandler calls back to winAccessBridgeDLL to set eventMask */ \ + } + + void WinAccessBridge::setJavaShutdownFP(AccessBridge_JavaShutdownFP fp) { + eventHandler->setJavaShutdownFP(fp, this); + } + + CALL_SET_EVENT_FP(setPropertyChangeFP, AccessBridge_PropertyChangeFP) + CALL_SET_EVENT_FP(setFocusGainedFP, AccessBridge_FocusGainedFP) + CALL_SET_EVENT_FP(setFocusLostFP, AccessBridge_FocusLostFP) + CALL_SET_EVENT_FP(setCaretUpdateFP, AccessBridge_CaretUpdateFP) + CALL_SET_EVENT_FP(setMouseClickedFP, AccessBridge_MouseClickedFP) + CALL_SET_EVENT_FP(setMouseEnteredFP, AccessBridge_MouseEnteredFP) + CALL_SET_EVENT_FP(setMouseExitedFP, AccessBridge_MouseExitedFP) + CALL_SET_EVENT_FP(setMousePressedFP, AccessBridge_MousePressedFP) + CALL_SET_EVENT_FP(setMouseReleasedFP, AccessBridge_MouseReleasedFP) + CALL_SET_EVENT_FP(setMenuCanceledFP, AccessBridge_MenuCanceledFP) + CALL_SET_EVENT_FP(setMenuDeselectedFP, AccessBridge_MenuDeselectedFP) + CALL_SET_EVENT_FP(setMenuSelectedFP, AccessBridge_MenuSelectedFP) + CALL_SET_EVENT_FP(setPopupMenuCanceledFP, AccessBridge_PopupMenuCanceledFP) + CALL_SET_EVENT_FP(setPopupMenuWillBecomeInvisibleFP, AccessBridge_PopupMenuWillBecomeInvisibleFP) + CALL_SET_EVENT_FP(setPopupMenuWillBecomeVisibleFP, AccessBridge_PopupMenuWillBecomeVisibleFP) + + CALL_SET_EVENT_FP(setPropertyNameChangeFP, AccessBridge_PropertyNameChangeFP) + CALL_SET_EVENT_FP(setPropertyDescriptionChangeFP, AccessBridge_PropertyDescriptionChangeFP) + CALL_SET_EVENT_FP(setPropertyStateChangeFP, AccessBridge_PropertyStateChangeFP) + CALL_SET_EVENT_FP(setPropertyValueChangeFP, AccessBridge_PropertyValueChangeFP) + CALL_SET_EVENT_FP(setPropertySelectionChangeFP, AccessBridge_PropertySelectionChangeFP) + CALL_SET_EVENT_FP(setPropertyTextChangeFP, AccessBridge_PropertyTextChangeFP) + CALL_SET_EVENT_FP(setPropertyCaretChangeFP, AccessBridge_PropertyCaretChangeFP) + CALL_SET_EVENT_FP(setPropertyVisibleDataChangeFP, AccessBridge_PropertyVisibleDataChangeFP) + CALL_SET_EVENT_FP(setPropertyChildChangeFP, AccessBridge_PropertyChildChangeFP) + CALL_SET_EVENT_FP(setPropertyActiveDescendentChangeFP, AccessBridge_PropertyActiveDescendentChangeFP) + + CALL_SET_EVENT_FP(setPropertyTableModelChangeFP, AccessBridge_PropertyTableModelChangeFP) diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/jdk.accessibility/windows/native/libwindowsaccessbridge/WinAccessBridge.h Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2005, 2015, 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. + */ + +/* + * A DLL which is loaded by Windows executables to handle communication + * between Java VMs purposes of Accessbility. + */ + +#ifndef __WinAccessBridge_H__ +#define __WinAccessBridge_H__ + +#include +#include "AccessBridgePackages.h" +#include "AccessBridgeEventHandler.h" +#include "AccessBridgeJavaVMInstance.h" +#include "AccessBridgeMessageQueue.h" + + +extern "C" { + BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, + LPVOID lpvReserved); + void AppendToCallOutput(char *s); + BOOL CALLBACK AccessBridgeDialogProc(HWND hDlg, UINT message, + UINT wParam, LONG lParam); + HWND getTopLevelHWND(HWND descendent); +} + +LRESULT CALLBACK WinAccessBridgeWindowProc(HWND hWnd, UINT message, + UINT wParam, LONG lParam); + +BOOL CALLBACK DeleteItemProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam); + +/** + * The WinAccessBridge class. The core of the Windows AT AccessBridge dll + */ +class WinAccessBridge { + HINSTANCE windowsInstance; + HWND dialogWindow; + AccessBridgeJavaVMInstance *javaVMs; + AccessBridgeEventHandler *eventHandler; + AccessBridgeMessageQueue *messageQueue; + +public: + WinAccessBridge(HINSTANCE hInstance); + ~WinAccessBridge(); + BOOL initWindow(); + + HWND showWinAccessBridgeGUI(int showCommand); + + // IPC with the Java AccessBridge DLL + LRESULT rendezvousWithNewJavaDLL(HWND JavaBridgeDLLwindow, long vmID); + + void sendPackage(char *buffer, long bufsize, HWND destWindow); + BOOL sendMemoryPackage(char *buffer, long bufsize, HWND destWindow); + BOOL queuePackage(char *buffer, long bufsize); + BOOL receiveAQueuedPackage(); + void preProcessPackage(char *buffer, long bufsize); + void processPackage(char *buffer, long bufsize); + void JavaVMDestroyed(HWND VMBridgeDLLWindow); + + // Java VM object memory management + void releaseJavaObject(long vmID, JOBJECT64 object); + + // Version info + BOOL getVersionInfo(long vmID, AccessBridgeVersionInfo *info); + + // HWND management methods + HWND getNextJavaWindow(HWND previous); + BOOL isJavaWindow(HWND window); + BOOL getAccessibleContextFromHWND(HWND window, long *vmID, JOBJECT64 *AccessibleContext); + HWND getHWNDFromAccessibleContext(long vmID, JOBJECT64 accessibleContext); + + /* Additional utility methods */ + BOOL isSameObject(long vmID, JOBJECT64 obj1, JOBJECT64 obj2); + + BOOL setTextContents (const long vmID, const AccessibleContext accessibleContext, const wchar_t *text); + + AccessibleContext getParentWithRole (const long vmID, const AccessibleContext accessibleContext, + const wchar_t *role); + + AccessibleContext getTopLevelObject (const long vmID, const AccessibleContext accessibleContext); + + AccessibleContext getParentWithRoleElseRoot (const long vmID, const AccessibleContext accessibleContext, + const wchar_t *role); + + int getObjectDepth (const long vmID, const AccessibleContext accessibleContext); + + AccessibleContext getActiveDescendent (const long vmID, const AccessibleContext accessibleContext); + + + // Accessible Context methods + BOOL getAccessibleContextAt(long vmID, JOBJECT64 AccessibleContextParent, + jint x, jint y, JOBJECT64 *AccessibleContext); + BOOL getAccessibleContextWithFocus(HWND window, long *vmID, JOBJECT64 *AccessibleContext); + BOOL getAccessibleContextInfo(long vmID, JOBJECT64 AccessibleContext, AccessibleContextInfo *info); + JOBJECT64 getAccessibleChildFromContext(long vmID, JOBJECT64 AccessibleContext, jint childIndex); + JOBJECT64 getAccessibleParentFromContext(long vmID, JOBJECT64 AccessibleContext); + + /* begin AccessibleTable methods */ + BOOL getAccessibleTableInfo(long vmID, JOBJECT64 acParent, AccessibleTableInfo *tableInfo); + BOOL getAccessibleTableCellInfo(long vmID, JOBJECT64 accessibleTable, jint row, jint column, + AccessibleTableCellInfo *tableCellInfo); + + BOOL getAccessibleTableRowHeader(long vmID, JOBJECT64 acParent, AccessibleTableInfo *tableInfo); + BOOL getAccessibleTableColumnHeader(long vmID, JOBJECT64 acParent, AccessibleTableInfo *tableInfo); + + JOBJECT64 getAccessibleTableRowDescription(long vmID, JOBJECT64 acParent, jint row); + JOBJECT64 getAccessibleTableColumnDescription(long vmID, JOBJECT64 acParent, jint column); + + jint getAccessibleTableRowSelectionCount(long vmID, JOBJECT64 accessibleTable); + BOOL isAccessibleTableRowSelected(long vmID, JOBJECT64 accessibleTable, jint row); + BOOL getAccessibleTableRowSelections(long vmID, JOBJECT64 accessibleTable, jint count, + jint *selections); + + jint getAccessibleTableColumnSelectionCount(long vmID, JOBJECT64 accessibleTable); + BOOL isAccessibleTableColumnSelected(long vmID, JOBJECT64 accessibleTable, jint column); + BOOL getAccessibleTableColumnSelections(long vmID, JOBJECT64 accessibleTable, jint count, + jint *selections); + + jint getAccessibleTableRow(long vmID, JOBJECT64 accessibleTable, jint index); + jint getAccessibleTableColumn(long vmID, JOBJECT64 accessibleTable, jint index); + jint getAccessibleTableIndex(long vmID, JOBJECT64 accessibleTable, jint row, jint column); + + /* end AccessibleTable methods */ + + // --------- AccessibleRelationSet methods + BOOL getAccessibleRelationSet(long vmID, JOBJECT64 accessibleContext, AccessibleRelationSetInfo *relationSet); + + // --------- AccessibleHypertext methods + BOOL getAccessibleHypertext(long vmID, JOBJECT64 accessibleContext, AccessibleHypertextInfo *hypertextInfo); + BOOL activateAccessibleHyperlink(long vmID, JOBJECT64 accessibleContext, JOBJECT64 accessibleHyperlink); + + jint getAccessibleHyperlinkCount(const long vmID, + const AccessibleContext accessibleContext); + + BOOL getAccessibleHypertextExt(const long vmID, + const AccessibleContext accessibleContext, + const jint nStartIndex, + /* OUT */ AccessibleHypertextInfo *hypertextInfo); + + jint getAccessibleHypertextLinkIndex(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex); + + BOOL getAccessibleHyperlink(const long vmID, + const AccessibleHypertext hypertext, + const jint nIndex, + /* OUT */ AccessibleHyperlinkInfo *hyperlinkInfo); + + + /* Accessible KeyBindings, Icons and Actions */ + BOOL getAccessibleKeyBindings(long vmID, JOBJECT64 accessibleContext, + AccessibleKeyBindings *keyBindings); + + BOOL getAccessibleIcons(long vmID, JOBJECT64 accessibleContext, + AccessibleIcons *icons); + + BOOL getAccessibleActions(long vmID, JOBJECT64 accessibleContext, + AccessibleActions *actions); + + BOOL doAccessibleActions(long vmID, JOBJECT64 accessibleContext, + AccessibleActionsToDo *actionsToDo, jint *failure); + + + // Accessible Text methods + BOOL getAccessibleTextInfo(long vmID, JOBJECT64 AccessibleContext, AccessibleTextInfo *textInfo, jint x, jint y); + BOOL getAccessibleTextItems(long vmID, JOBJECT64 AccessibleContext, AccessibleTextItemsInfo *textItems, jint index); + BOOL getAccessibleTextSelectionInfo(long vmID, JOBJECT64 AccessibleContext, AccessibleTextSelectionInfo *selectionInfo); + BOOL getAccessibleTextAttributes(long vmID, JOBJECT64 AccessibleContext, jint index, AccessibleTextAttributesInfo *attributes); + BOOL getAccessibleTextRect(long vmID, JOBJECT64 AccessibleContext, AccessibleTextRectInfo *rectInfo, jint index); + BOOL getAccessibleTextLineBounds(long vmID, JOBJECT64 AccessibleContext, jint index, jint *startIndex, jint *endIndex); + BOOL getAccessibleTextRange(long vmID, JOBJECT64 AccessibleContext, jint start, jint end, wchar_t *text, short len); + + // Accessible Value methods + BOOL getCurrentAccessibleValueFromContext(long vmID, JOBJECT64 AccessibleContext, wchar_t *value, short len); + BOOL getMaximumAccessibleValueFromContext(long vmID, JOBJECT64 AccessibleContext, wchar_t *value, short len); + BOOL getMinimumAccessibleValueFromContext(long vmID, JOBJECT64 AccessibleContext, wchar_t *value, short len); + + // Accessible Selection methods + void addAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext, int i); + void clearAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext); + JOBJECT64 getAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext, int i); + int getAccessibleSelectionCountFromContext(long vmID, JOBJECT64 AccessibleContext); + BOOL isAccessibleChildSelectedFromContext(long vmID, JOBJECT64 AccessibleContext, int i); + void removeAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext, int i); + void selectAllAccessibleSelectionFromContext(long vmID, JOBJECT64 AccessibleContext); + + // Event handling methods + void addJavaEventNotification(jlong type); + void removeJavaEventNotification(jlong type); + void addAccessibilityEventNotification(jlong type); + void removeAccessibilityEventNotification(jlong type); + + void setPropertyChangeFP(AccessBridge_PropertyChangeFP fp); + void setJavaShutdownFP(AccessBridge_JavaShutdownFP fp); + void setFocusGainedFP(AccessBridge_FocusGainedFP fp); + void setFocusLostFP(AccessBridge_FocusLostFP fp); + void setCaretUpdateFP(AccessBridge_CaretUpdateFP fp); + void setMouseClickedFP(AccessBridge_MouseClickedFP fp); + void setMouseEnteredFP(AccessBridge_MouseEnteredFP fp); + void setMouseExitedFP(AccessBridge_MouseExitedFP fp); + void setMousePressedFP(AccessBridge_MousePressedFP fp); + void setMouseReleasedFP(AccessBridge_MouseReleasedFP fp); + void setMenuCanceledFP(AccessBridge_MenuCanceledFP fp); + void setMenuDeselectedFP(AccessBridge_MenuDeselectedFP fp); + void setMenuSelectedFP(AccessBridge_MenuSelectedFP fp); + void setPopupMenuCanceledFP(AccessBridge_PopupMenuCanceledFP fp); + void setPopupMenuWillBecomeInvisibleFP(AccessBridge_PopupMenuWillBecomeInvisibleFP fp); + void setPopupMenuWillBecomeVisibleFP(AccessBridge_PopupMenuWillBecomeVisibleFP fp); + + void setPropertyNameChangeFP(AccessBridge_PropertyNameChangeFP fp); + void setPropertyDescriptionChangeFP(AccessBridge_PropertyDescriptionChangeFP fp); + void setPropertyStateChangeFP(AccessBridge_PropertyStateChangeFP fp); + void setPropertyValueChangeFP(AccessBridge_PropertyValueChangeFP fp); + void setPropertySelectionChangeFP(AccessBridge_PropertySelectionChangeFP fp); + void setPropertyTextChangeFP(AccessBridge_PropertyTextChangeFP fp); + void setPropertyCaretChangeFP(AccessBridge_PropertyCaretChangeFP fp); + void setPropertyVisibleDataChangeFP(AccessBridge_PropertyVisibleDataChangeFP fp); + void setPropertyChildChangeFP(AccessBridge_PropertyChildChangeFP fp); + void setPropertyActiveDescendentChangeFP(AccessBridge_PropertyActiveDescendentChangeFP fp); + + void setPropertyTableModelChangeFP(AccessBridge_PropertyTableModelChangeFP fp); + + /** + * Additional methods for Teton + */ + + /** + * Gets the AccessibleName for a component based upon the JAWS algorithm. Returns + * whether successful. + * + * Bug ID 4916682 - Implement JAWS AccessibleName policy + */ + BOOL getVirtualAccessibleName(long vmID, AccessibleContext accessibleContext, wchar_t *name, int len); + + /** + * Request focus for a component. Returns whether successful; + * + * Bug ID 4944757 - requestFocus method needed + */ + BOOL requestFocus(long vmID, AccessibleContext accessibleContext); + + /** + * Selects text between two indices. Selection includes the text at the start index + * and the text at the end index. Returns whether successful; + * + * Bug ID 4944758 - selectTextRange method needed + */ + BOOL selectTextRange(long vmID, AccessibleContext accessibleContext, int startIndex, int endIndex); + + /** + * Get text attributes between two indices. The attribute list includes the text at the + * start index and the text at the end index. Returns whether successful; + * + * Bug ID 4944761 - getTextAttributes between two indices method needed + */ + BOOL getTextAttributesInRange(long vmID, AccessibleContext accessibleContext, int startIndex, int endIndex, + AccessibleTextAttributesInfo *attributes, short *len); + + /** + * Gets number of visible children of a component. Returns -1 on error. + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + int getVisibleChildrenCount(long vmID, AccessibleContext accessibleContext); + + /** + * Gets the visible children of an AccessibleContext. Returns whether successful; + * + * Bug ID 4944762- getVisibleChildren for list-like components needed + */ + BOOL getVisibleChildren(long vmID, AccessibleContext accessibleContext, int startIndex, + VisibleChildrenInfo *visibleChildrenInfo); + + /** + * Set the caret to a text position. Returns whether successful; + * + * Bug ID 4944770 - setCaretPosition method needed + */ + BOOL setCaretPosition(long vmID, AccessibleContext accessibleContext, int position); + + + /** + * Gets the text caret bounding rectangle + */ + BOOL getCaretLocation(long vmID, JOBJECT64 AccessibleContext, AccessibleTextRectInfo *rectInfo, jint index); + + /** + * Gets number of events waiting in the message queue + */ + int getEventsWaiting(); + +}; + +#endif diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java --- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java Fri Apr 17 10:24:46 2015 -0700 @@ -42,6 +42,7 @@ import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.TextOutputCallback; +import sun.misc.ManagedLocalsThread; import sun.security.util.Debug; import sun.security.util.ResourcesMgr; @@ -811,7 +812,7 @@ return; } TokenPoller poller = new TokenPoller(this); - Thread t = new Thread(poller, "Poller " + getName()); + Thread t = new ManagedLocalsThread(poller, "Poller " + getName()); t.setDaemon(true); t.setPriority(Thread.MIN_PRIORITY); t.start(); diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java --- a/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/jdk.httpserver/share/classes/sun/net/httpserver/ServerImpl.java Fri Apr 17 10:24:46 2015 -0700 @@ -36,6 +36,7 @@ import com.sun.net.httpserver.*; import java.security.AccessController; import java.security.PrivilegedAction; +import sun.misc.ManagedLocalsThread; import sun.net.httpserver.HttpConnection.State; /** @@ -142,7 +143,7 @@ if (executor == null) { executor = new DefaultExecutor(); } - dispatcherThread = new Thread (dispatcher); + dispatcherThread = new ManagedLocalsThread(dispatcher); started = true; dispatcherThread.start(); } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015, 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 @@ -74,8 +74,9 @@ * Mflag: DO NOT generate a manifest file (just ZIP) * iflag: generate jar index * nflag: Perform jar normalization at the end + * pflag: preserve/don't strip leading slash and .. component from file name */ - boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag; + boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag; static final String MANIFEST_DIR = "META-INF/"; static final String VERSION = "1.0"; @@ -187,6 +188,7 @@ addMainClass(manifest, ename); } } + expand(null, files, false); OutputStream out; if (fname != null) { out = new FileOutputStream(fname); @@ -208,7 +210,6 @@ tmpfile = createTemporaryFile(tmpbase, ".jar"); out = new FileOutputStream(tmpfile); } - expand(null, files, false); create(new BufferedOutputStream(out, 4096), manifest); if (in != null) { in.close(); @@ -424,6 +425,9 @@ case 'e': ename = args[count++]; break; + case 'P': + pflag = true; + break; default: error(formatMsg("error.illegal.option", String.valueOf(flags.charAt(i)))); @@ -713,6 +717,47 @@ return true; } + private static final boolean isWinDriveLetter(char c) { + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); + } + + private String safeName(String name) { + if (!pflag) { + int len = name.length(); + int i = name.lastIndexOf("../"); + if (i == -1) { + i = 0; + } else { + i += 3; // strip any dot-dot components + } + if (File.separatorChar == '\\') { + // the spec requests no drive letter. skip if + // the entry name has one. + while (i < len) { + int off = i; + if (i + 1 < len && + name.charAt(i + 1) == ':' && + isWinDriveLetter(name.charAt(i))) { + i += 2; + } + while (i < len && name.charAt(i) == '/') { + i++; + } + if (i == off) { + break; + } + } + } else { + while (i < len && name.charAt(i) == '/') { + i++; + } + } + if (i != 0) { + name = name.substring(i); + } + } + return name; + } private String entryName(String name) { name = name.replace(File.separatorChar, '/'); @@ -723,11 +768,10 @@ matchPath = path; } } - name = name.substring(matchPath.length()); - - if (name.startsWith("/")) { - name = name.substring(1); - } else if (name.startsWith("./")) { + name = safeName(name.substring(matchPath.length())); + // the old implementaton doesn't remove + // "./" if it was led by "/" (?) + if (name.startsWith("./")) { name = name.substring(2); } return name; @@ -927,8 +971,11 @@ for (ZipEntry ze : zes) { long lastModified = ze.getTime(); if (lastModified != -1) { - File f = new File(ze.getName().replace('/', File.separatorChar)); - f.setLastModified(lastModified); + String name = safeName(ze.getName().replace(File.separatorChar, '/')); + if (name.length() != 0) { + File f = new File(name.replace('/', File.separatorChar)); + f.setLastModified(lastModified); + } } } } @@ -1002,8 +1049,16 @@ */ ZipEntry extractFile(InputStream is, ZipEntry e) throws IOException { ZipEntry rc = null; - String name = e.getName(); - File f = new File(e.getName().replace('/', File.separatorChar)); + // The spec requres all slashes MUST be forward '/', it is possible + // an offending zip/jar entry may uses the backwards slash in its + // name. It might cause problem on Windows platform as it skips + // our "safe" check for leading slahs and dot-dot. So replace them + // with '/'. + String name = safeName(e.getName().replace(File.separatorChar, '/')); + if (name.length() == 0) { + return rc; // leading '/' or 'dot-dot' only path + } + File f = new File(name.replace('/', File.separatorChar)); if (e.isDirectory()) { if (f.exists()) { if (!f.isDirectory()) { diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties --- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties Fri Apr 17 10:24:46 2015 -0700 @@ -68,7 +68,7 @@ (in = {0}) (out= {1}) usage=\ -Usage: jar {ctxui}[vfmn0Me] [jar-file] [manifest-file] [entry-point] [-C dir] files ...\n\ +Usage: jar {ctxui}[vfmn0PMe] [jar-file] [manifest-file] [entry-point] [-C dir] files ...\n\ Options:\n\ \ \ -c create new archive\n\ \ \ -t list table of contents for archive\n\ @@ -81,6 +81,7 @@ \ \ -e specify application entry point for stand-alone application \n\ \ \ bundled into an executable jar file\n\ \ \ -0 store only; use no ZIP compression\n\ +\ \ -P preserve leading '/' (absolute path) and ".." (parent directory) components from file names\n\ \ \ -M do not create a manifest file for the entries\n\ \ \ -i generate index information for the specified jar files\n\ \ \ -C change to the specified directory and include the following file\n\ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest --- a/jdk/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/src/jdk.pack200/windows/native/unpack200/unpack200_proto.exe.manifest Fri Apr 17 10:24:46 2015 -0700 @@ -1,11 +1,12 @@ - - + + type="win32"/> - Java(TM) SE Runtime Environment unpack200 Process. + Java(TM) SE Runtime Environment unpack200 Process. diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/ProblemList.txt --- a/jdk/test/ProblemList.txt Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/test/ProblemList.txt Fri Apr 17 10:24:46 2015 -0700 @@ -164,9 +164,6 @@ # 6988950 demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java generic-all -# 8071968 -javax/xml/ws/8046817/GenerateEnumSchema.java windows-all - ############################################################################ # jdk_net diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/TEST.ROOT --- a/jdk/test/TEST.ROOT Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/test/TEST.ROOT Fri Apr 17 10:24:46 2015 -0700 @@ -8,7 +8,7 @@ othervm.dirs=java/awt java/beans javax/accessibility javax/imageio javax/sound javax/print javax/management com/sun/awt sun/awt sun/java2d sun/pisces javax/xml/jaxp/testng/validation # Tests that cannot run concurrently -exclusiveAccess.dirs=java/rmi/Naming java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi java/util/stream +exclusiveAccess.dirs=java/rmi/Naming java/util/prefs sun/management/jmxremote sun/tools/jstatd sun/security/mscapi java/util/stream javax/rmi # Group definitions groups=TEST.groups [closed/TEST.groups] diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/TEST.groups --- a/jdk/test/TEST.groups Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/test/TEST.groups Fri Apr 17 10:24:46 2015 -0700 @@ -138,7 +138,6 @@ jdk_rmi = \ java/rmi \ - javax/rmi/ssl \ sun/rmi jdk_security1 = \ @@ -237,6 +236,7 @@ jdk_other = \ java/sql \ javax/sql \ + javax/rmi \ javax/naming \ javax/script \ javax/smartcardio \ diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/java/awt/Checkbox/SetStateExcessEvent/SetStateExcessEvent.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/Checkbox/SetStateExcessEvent/SetStateExcessEvent.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Frame; +import java.awt.GridBagLayout; +import java.awt.Robot; + +/** + * @test + * @bug 8074500 + * @summary Checkbox.setState() call should not post ItemEvent + * @author Sergey Bylokhov + */ +public final class SetStateExcessEvent { + + private static boolean failed; + + public static void main(final String[] args) throws Exception { + final Robot robot = new Robot(); + final CheckboxGroup group = new CheckboxGroup(); + final Checkbox[] cbs = {new Checkbox("checkbox1", true, group), + new Checkbox("checkbox2", false, group), + new Checkbox("checkbox3", true, group), + + new Checkbox("checkbox4", true), + new Checkbox("checkbox5", false), + new Checkbox("checkbox6", true)}; + final Frame frame = new Frame(); + frame.setLayout(new GridBagLayout()); + try { + for (final Checkbox cb : cbs) { + cb.addItemListener(e -> { + failed = true; + }); + } + for (final Checkbox cb : cbs) { + frame.add(cb); + } + frame.pack(); + + for (final Checkbox cb : cbs) { + cb.setState(!cb.getState()); + } + + for (final Checkbox cb : cbs) { + group.setSelectedCheckbox(cb); + } + robot.waitForIdle(); + } finally { + frame.dispose(); + } + if (failed) { + throw new RuntimeException("Listener should not be called"); + } + System.out.println("Test passed"); + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/java/awt/TrayIcon/8072769/bug8072769.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/TrayIcon/8072769/bug8072769.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 8072769 + @summary System tray icon title freezes java + @author Semyon Sadetsky + @library ../../../../lib/testlibrary + @build jdk.testlibrary.OSInfo + */ + +import jdk.testlibrary.OSInfo; + +import javax.swing.*; +import java.awt.*; +import java.util.Arrays; + +public class bug8072769 { + + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() == OSInfo.OSType.WINDOWS) { + if (SystemTray.isSupported()) { + test(); + } else { + System.out.println("SystemTray not supported. " + + "Test is skipped."); + } + } else { + System.out.println("Test will only run on Windows platform. " + + "Test is skipped."); + } + System.out.println("ok"); + } + + private static void test() throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + final SystemTray tray = SystemTray.getSystemTray(); + final TrayIcon trayIcon = new TrayIcon(icon.getImage()); + try { + tray.add(trayIcon); + } catch (AWTException e) { + throw new RuntimeException( + "TrayIcon could not be added."); + } + + + try { + trayIcon.displayMessage(createString(63, 'A'), + createString(255, 'C'), TrayIcon.MessageType.ERROR); + + trayIcon.setToolTip(createString(127, 'B')); + + trayIcon.displayMessage(createString(64, 'A'), + createString(256, 'C'), TrayIcon.MessageType.ERROR); + + trayIcon.setToolTip(createString(128, 'B')); + + trayIcon.displayMessage(createString(65, 'A'), + createString(257, 'C'), TrayIcon.MessageType.ERROR); + + trayIcon.setToolTip(createString(129, 'B')); + } + finally { + tray.remove(trayIcon); + } + } + }); + } + + private static String createString(int len, char letter) { + char[] chars = new char[len]; + Arrays.fill(chars, letter); + chars[len - 2] = '='; + chars[len - 1] = '>'; + return new String(chars); + } + + private static ImageIcon icon = new ImageIcon( + new byte[]{71, 73, 70, 56, 57, 97, 32, 0, 35, 0, -43, 0, 0, -1, -1, + -1, -19, -101, 9, -18, -95, 24, -14, -76, 71, -4, -19, -46, + -3, -13, -31, -17, -88, 40, -12, -63, 102, -10, -51, -124, + -16, -82, 55, -11, -57, 117, -2, -7, -15, -7, -32, -77, -9, + -45, -108, -5, -26, -62, -13, -70, 86, -8, -39, -94, 83, + -126, -95, -8, -38, -93, -6, -26, -63, -9, -45, -109, -4, + -14, -32, -15, -76, 70, -12, -58, 116, -17, -89, 39, 77, + 121, -106, -3, -8, -17, 104, -111, -84, 126, -95, -72, 93, + -119, -90, -14, -70, 85, -13, -64, 101, -16, -83, 55, -109, + -80, -60, -7, -33, -78, -100, -84, -85, 94, -127, -104, -32, + -99, 39, 127, -120, -114, 83, 113, -124, -12, -9, -7, -16, + -16, -16, -115, 108, 45, 57, 89, 110, -50, -41, -35, 104, + -111, -83, 41, 65, 80, 72, 113, -116, 115, -103, -78, 88, + 106, 112, -82, -78, -82, -45, -38, -40, -5, -20, -48, -65, + -48, -36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, -7, 4, 0, 0, 0, + 0, 0, 44, 0, 0, 0, 0, 32, 0, 35, 0, 0, 6, -1, 64, -128, 112, + 72, 4, 16, 0, 14, -57, 2, 1, 96, 30, -117, -48, 40, -78, + -55, 96, 28, 28, -125, -62, 0, 96, 48, 74, -91, -116, 102, + 3, 97, 64, 4, 20, -25, -128, 68, -80, 16, 24, 11, 95, 98, + -29, -64, 72, 11, 2, 120, -68, 96, -64, 39, 116, -29, 0, 12, + 13, 5, 1, 3, 121, -121, -120, 9, 2, 7, 5, 15, 82, 11, 11, + 92, 15, 6, -120, -107, -121, 7, 2, 18, 0, 112, 80, 3, 8, + 104, -106, -95, 122, 88, 97, 68, 5, 11, 4, -95, 32, 8, 16, + 19, 16, 8, 22, -106, -114, 79, 66, 5, 2, 15, 9, -120, 22, + 19, 81, 21, 31, -120, 7, 6, 10, 67, 71, 4, 119, -121, 20, + -128, 16, -57, 120, 7, -101, -111, -58, 9, -108, 121, -55, + -128, 0, 16, 121, 123, -117, 67, 5, -71, 121, 30, -42, 67, + 23, -121, 13, 66, 14, 6, 3, -34, 120, 21, -31, 66, 26, -39, + 3, 6, -50, 11, -96, 120, 31, -19, 67, 30, 121, 9, 14, 0, 13, + 124, -121, 68, -32, 19, 98, 6, 15, 58, 71, 18, 12, -27, 97, + 55, 80, 68, 54, 5, 5, 24, 40, 80, 23, 96, -96, -112, 9, -39, + 30, 52, -112, 72, -47, 34, 0, 10, 25, -53, 37, 60, -60, 16, + -33, 56, 61, 16, -1, 41, -60, 83, 13, 31, -122, 60, 7, 1, + -48, 59, -124, 65, 3, 62, -116, 48, -5, 57, 72, -112, -18, + -48, 5, -103, 124, 32, -32, 37, 112, -74, -119, 98, 0, 8, + -31, 64, -110, 35, 38, 64, 26, 34, -92, 113, 42, 48, -45, + 70, -76, 24, -77, 60, 80, -91, -60, -70, -12, 76, -120, 49, + 92, -120, 4, -40, -116, -126, 51, 79, -80, 97, -36, 80, 89, + -6, 25, -91, 96, -98, 89, -99, 62, 33, -62, 32, -59, -83, 0, + 82, 80, 32, 1, -72, 53, 13, -113, -42, 102, -103, 54, -127, + 25, 84, 40, 15, -115, 40, 37, 20, 49, 34, 26, 103, 78, 29, + 52, 42, 88, 16, 65, 17, -94, -49, 31, 107, 97, 16, -116, 49, + 32, 35, -61, 6, 14, 33, 56, 68, -120, -80, -96, 11, 1, 78, + -31, -6, 33, 96, 48, -93, -61, -122, 21, 46, 50, -116, -10, + -30, -47, -117, -125, 24, 29, 94, -100, -112, 61, -94, 54, + -108, 20, 38, 90, -112, -128, 81, -61, 90, 16, 0, 59}, + "try icon"); + +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + @test + @bug 8071668 + @summary Check whether clipboard see changes from external process after taking ownership + @author Anton Nashatyrev: area=datatransfer + @library /lib/testlibrary + @build jdk.testlibrary.Utils + @run main ClipboardInterVMTest +*/ + +import jdk.testlibrary.Utils; + +import java.awt.*; +import java.awt.datatransfer.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.Reader; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class ClipboardInterVMTest { + + static CountDownLatch lostOwnershipMonitor = new CountDownLatch(1); + static CountDownLatch flavorChangedMonitor = new CountDownLatch(1); + static Process process; + + public static void main(String[] args) throws Throwable { + Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard(); + + if (args.length > 0) { + System.out.println("Changing clip..."); + clip.setContents(new StringSelection("pong"), null); + System.out.println("done"); + // keeping this process running for a while since on Mac the clipboard + // will be invalidated via NSApplicationDidBecomeActiveNotification + // callback in the main process after this child process finishes + Thread.sleep(60 * 1000); + return; + }; + + + clip.setContents(new CustomSelection(), new ClipboardOwner() { + @Override + public void lostOwnership(Clipboard clipboard, Transferable contents) { + System.out.println("ClipboardInterVMTest.lostOwnership"); + lostOwnershipMonitor.countDown(); + } + }); + + clip.addFlavorListener(new FlavorListener() { + @Override + public void flavorsChanged(FlavorEvent e) { + System.out.println("ClipboardInterVMTest.flavorsChanged"); + flavorChangedMonitor.countDown(); + } + }); + + System.out.println("Starting external clipborad modifier..."); + new Thread(() -> runTest(ClipboardInterVMTest.class.getCanonicalName(), "pong")).start(); + + String content = ""; + long startTime = System.currentTimeMillis(); + while (System.currentTimeMillis() - startTime < 30 * 1000) { + Transferable c = clip.getContents(null); + if (c.isDataFlavorSupported(DataFlavor.plainTextFlavor)) { + Reader reader = DataFlavor.plainTextFlavor.getReaderForText(c); + content = new BufferedReader(reader).readLine(); + System.out.println(content); + if (content.equals("pong")) { + break; + } + } + Thread.sleep(200); + } + + if (!lostOwnershipMonitor.await(10, TimeUnit.SECONDS)) { + throw new RuntimeException("No LostOwnership event received."); + }; + + if (!flavorChangedMonitor.await(10, TimeUnit.SECONDS)) { + throw new RuntimeException("No LostOwnership event received."); + }; + + if (!content.equals("pong")) { + throw new RuntimeException("Content was not passed."); + } + + process.destroy(); + + System.out.println("Passed."); + } + + private static void runTest(String main, String... args) { + + try { + List opts = new ArrayList<>(); + opts.add(getJavaExe()); + opts.addAll(Arrays.asList(Utils.getTestJavaOpts())); + opts.add("-cp"); + opts.add(System.getProperty("test.class.path", System.getProperty("java.class.path"))); + + opts.add(main); + opts.addAll(Arrays.asList(args)); + + ProcessBuilder pb = new ProcessBuilder(opts.toArray(new String[0])); + process = pb.start(); + } catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + } + + private static String getJavaExe() throws IOException { + File p = new File(System.getProperty("java.home"), "bin"); + File j = new File(p, "java"); + if (!j.canRead()) { + j = new File(p, "java.exe"); + } + if (!j.canRead()) { + throw new RuntimeException("Can't find java executable in " + p); + } + return j.getCanonicalPath(); + } + + static class CustomSelection implements Transferable { + private static final DataFlavor[] flavors = { DataFlavor.allHtmlFlavor }; + + public DataFlavor[] getTransferDataFlavors() { + return flavors; + } + + public boolean isDataFlavorSupported(DataFlavor flavor) { + return flavors[0].equals(flavor); + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException, java.io.IOException { + if (isDataFlavorSupported(flavor)) { + return "ping"; + } else { + throw new UnsupportedFlavorException(flavor); + } + } + } +} \ No newline at end of file diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/java/awt/geom/Path2D/Path2DCopyConstructor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/awt/geom/Path2D/Path2DCopyConstructor.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +import java.awt.Rectangle; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.IllegalPathStateException; +import java.awt.geom.Path2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +/** + * @test + * @bug 8076419 + * @summary Check Path2D copy constructor (trims arrays) + * and constructor with zero capacity + * @run main Path2DTrimCopy + */ +public class Path2DCopyConstructor { + + private final static float EPSILON = 5e-6f; + private final static float FLATNESS = 1e-2f; + + private final static AffineTransform at + = AffineTransform.getScaleInstance(1.3, 2.4); + + private final static Rectangle2D.Double rect2d + = new Rectangle2D.Double(3.2, 4.1, 5.0, 10.0); + + private final static Point2D.Double pt2d + = new Point2D.Double(2.0, 2.5); + + public static boolean verbose; + + static void log(String msg) { + if (verbose) { + System.out.println(msg); + } + } + + public static void main(String argv[]) { + verbose = (argv.length != 0); + + testEmptyDoublePaths(); + testDoublePaths(); + + testEmptyFloatPaths(); + testFloatPaths(); + + testEmptyGeneralPath(); + testGeneralPath(); + } + + static void testEmptyDoublePaths() { + log("\n - Test(Path2D.Double[0]) ---"); + test(() -> new Path2D.Double(Path2D.WIND_NON_ZERO, 0)); + } + + static void testDoublePaths() { + log("\n - Test(Path2D.Double) ---"); + test(() -> new Path2D.Double()); + } + + static void testEmptyFloatPaths() { + log("\n - Test(Path2D.Float[0]) ---"); + test(() -> new Path2D.Float(Path2D.WIND_NON_ZERO, 0)); + } + + static void testFloatPaths() { + log("\n - Test(Path2D.Float) ---"); + test(() -> new Path2D.Float()); + } + + static void testEmptyGeneralPath() { + log("\n - Test(GeneralPath[0]) ---"); + test(() -> new GeneralPath(Path2D.WIND_NON_ZERO, 0)); + } + + static void testGeneralPath() { + log("\n - Test(GeneralPath) ---"); + test(() -> new GeneralPath()); + } + + interface PathFactory { + Path2D makePath(); + } + + static void test(PathFactory pf) { + log("\n --- test: path(empty) ---"); + test(pf.makePath(), true); + log("\n\n --- test: path(addMove) ---"); + test(addMove(pf.makePath()), false); + log("\n\n --- test: path(addMoveAndLines) ---"); + test(addMoveAndLines(pf.makePath()), false); + log("\n\n --- test: path(addMoveAndQuads) ---"); + test(addMoveAndQuads(pf.makePath()), false); + log("\n\n --- test: path(addMoveAndCubics) ---"); + test(addMoveAndCubics(pf.makePath()), false); + log("\n\n --- test: path(addMoveAndClose) ---"); + test(addMoveAndClose(pf.makePath()), false); + } + + static Path2D addMove(Path2D p2d) { + p2d.moveTo(1.0, 0.5); + return p2d; + } + + static Path2D addMoveAndLines(Path2D p2d) { + addMove(p2d); + addLines(p2d); + return p2d; + } + + static Path2D addLines(Path2D p2d) { + for (int i = 0; i < 10; i++) { + p2d.lineTo(1.1 * i, 2.3 * i); + } + return p2d; + } + + static Path2D addMoveAndCubics(Path2D p2d) { + addMove(p2d); + addCubics(p2d); + return p2d; + } + + static Path2D addCubics(Path2D p2d) { + for (int i = 0; i < 10; i++) { + p2d.curveTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i, 1.5 * i, 1.6 * i); + } + return p2d; + } + + static Path2D addMoveAndQuads(Path2D p2d) { + addMove(p2d); + addQuads(p2d); + return p2d; + } + + static Path2D addQuads(Path2D p2d) { + for (int i = 0; i < 10; i++) { + p2d.quadTo(1.1 * i, 1.2 * i, 1.3 * i, 1.4 * i); + } + return p2d; + } + + static Path2D addMoveAndClose(Path2D p2d) { + addMove(p2d); + addClose(p2d); + return p2d; + } + + static Path2D addClose(Path2D p2d) { + p2d.closePath(); + return p2d; + } + + static void test(Path2D p2d, boolean isEmpty) { + testEqual(new Path2D.Float(p2d), p2d); + testEqual(new Path2D.Double(p2d), p2d); + testEqual(new GeneralPath(p2d), p2d); + + testIterator(new Path2D.Float(p2d), p2d); + testIterator(new Path2D.Double(p2d), p2d); + testIterator((Path2D) p2d.clone(), p2d); + + testFlattening(new Path2D.Float(p2d), p2d); + testFlattening(new Path2D.Double(p2d), p2d); + testFlattening((Path2D) p2d.clone(), p2d); + + testAddMove(new Path2D.Float(p2d)); + testAddMove(new Path2D.Double(p2d)); + testAddMove((Path2D) p2d.clone()); + + // These should expect exception if empty + testAddLine(new Path2D.Float(p2d), isEmpty); + testAddLine(new Path2D.Double(p2d), isEmpty); + testAddLine((Path2D) p2d.clone(), isEmpty); + + testAddQuad(new Path2D.Float(p2d), isEmpty); + testAddQuad(new Path2D.Double(p2d), isEmpty); + testAddQuad((Path2D) p2d.clone(), isEmpty); + + testAddCubic(new Path2D.Float(p2d), isEmpty); + testAddCubic(new Path2D.Double(p2d), isEmpty); + testAddCubic((Path2D) p2d.clone(), isEmpty); + + testAddClose(new Path2D.Float(p2d), isEmpty); + testAddClose(new Path2D.Double(p2d), isEmpty); + testAddClose((Path2D) p2d.clone(), isEmpty); + + testGetBounds(new Path2D.Float(p2d), p2d); + testGetBounds(new Path2D.Double(p2d), p2d); + testGetBounds((Path2D) p2d.clone(), p2d); + + testTransform(new Path2D.Float(p2d)); + testTransform(new Path2D.Double(p2d)); + testTransform((Path2D) p2d.clone()); + + testIntersect(new Path2D.Float(p2d), p2d); + testIntersect(new Path2D.Double(p2d), p2d); + testIntersect((Path2D) p2d.clone(), p2d); + + testContains(new Path2D.Float(p2d), p2d); + testContains(new Path2D.Double(p2d), p2d); + testContains((Path2D) p2d.clone(), p2d); + + testGetCurrentPoint(new Path2D.Float(p2d), p2d); + testGetCurrentPoint(new Path2D.Double(p2d), p2d); + testGetCurrentPoint((Path2D) p2d.clone(), p2d); + } + + static void testEqual(Path2D pathA, Path2D pathB) { + final PathIterator itA = pathA.getPathIterator(null); + final PathIterator itB = pathB.getPathIterator(null); + + float[] coordsA = new float[6]; + float[] coordsB = new float[6]; + + int n = 0; + for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) { + int typeA = itA.currentSegment(coordsA); + int typeB = itB.currentSegment(coordsB); + + if (typeA != typeB) { + throw new IllegalStateException("Path-segment[" + n + "] " + + " type are not equals [" + typeA + "|" + typeB + "] !"); + } + if (!equalsArray(coordsA, coordsB, getLength(typeA))) { + throw new IllegalStateException("Path-segment[" + n + "] coords" + + " are not equals [" + Arrays.toString(coordsA) + "|" + + Arrays.toString(coordsB) + "] !"); + } + } + if (!itA.isDone() || !itB.isDone()) { + throw new IllegalStateException("Paths do not have same lengths !"); + } + log("testEqual: " + n + " segments."); + } + + static void testIterator(Path2D pathA, Path2D pathB) { + final PathIterator itA = pathA.getPathIterator(at); + final PathIterator itB = pathB.getPathIterator(at); + + float[] coordsA = new float[6]; + float[] coordsB = new float[6]; + + int n = 0; + for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) { + int typeA = itA.currentSegment(coordsA); + int typeB = itB.currentSegment(coordsB); + + if (typeA != typeB) { + throw new IllegalStateException("Path-segment[" + n + "] " + + "type are not equals [" + typeA + "|" + typeB + "] !"); + } + // Take care of floating-point precision: + if (!equalsArrayEps(coordsA, coordsB, getLength(typeA))) { + throw new IllegalStateException("Path-segment[" + n + "] coords" + + " are not equals [" + Arrays.toString(coordsA) + "|" + + Arrays.toString(coordsB) + "] !"); + } + } + if (!itA.isDone() || !itB.isDone()) { + throw new IllegalStateException("Paths do not have same lengths !"); + } + log("testIterator: " + n + " segments."); + } + + static void testFlattening(Path2D pathA, Path2D pathB) { + final PathIterator itA = pathA.getPathIterator(at, FLATNESS); + final PathIterator itB = pathB.getPathIterator(at, FLATNESS); + + float[] coordsA = new float[6]; + float[] coordsB = new float[6]; + + int n = 0; + for (; !itA.isDone() && !itB.isDone(); itA.next(), itB.next(), n++) { + int typeA = itA.currentSegment(coordsA); + int typeB = itB.currentSegment(coordsB); + + if (typeA != typeB) { + throw new IllegalStateException("Path-segment[" + n + "] " + + "type are not equals [" + typeA + "|" + typeB + "] !"); + } + // Take care of floating-point precision: + if (!equalsArrayEps(coordsA, coordsB, getLength(typeA))) { + throw new IllegalStateException("Path-segment[" + n + "] coords" + + " are not equals [" + Arrays.toString(coordsA) + "|" + + Arrays.toString(coordsB) + "] !"); + } + } + if (!itA.isDone() || !itB.isDone()) { + throw new IllegalStateException("Paths do not have same lengths !"); + } + log("testFlattening: " + n + " segments."); + } + + static void testAddMove(Path2D pathA) { + addMove(pathA); + log("testAddMove: passed."); + } + + static void testAddLine(Path2D pathA, boolean isEmpty) { + try { + addLines(pathA); + } + catch (IllegalPathStateException ipse) { + if (isEmpty) { + log("testAddLine: passed " + + "(expected IllegalPathStateException catched)."); + return; + } else { + throw ipse; + } + } + if (isEmpty) { + throw new IllegalStateException("IllegalPathStateException not thrown !"); + } + log("testAddLine: passed."); + } + + static void testAddQuad(Path2D pathA, boolean isEmpty) { + try { + addQuads(pathA); + } + catch (IllegalPathStateException ipse) { + if (isEmpty) { + log("testAddQuad: passed " + + "(expected IllegalPathStateException catched)."); + return; + } else { + throw ipse; + } + } + if (isEmpty) { + throw new IllegalStateException("IllegalPathStateException not thrown !"); + } + log("testAddQuad: passed."); + } + + static void testAddCubic(Path2D pathA, boolean isEmpty) { + try { + addCubics(pathA); + } + catch (IllegalPathStateException ipse) { + if (isEmpty) { + log("testAddCubic: passed " + + "(expected IllegalPathStateException catched)."); + return; + } else { + throw ipse; + } + } + if (isEmpty) { + throw new IllegalStateException("IllegalPathStateException not thrown !"); + } + log("testAddCubic: passed."); + } + + static void testAddClose(Path2D pathA, boolean isEmpty) { + try { + addClose(pathA); + } + catch (IllegalPathStateException ipse) { + if (isEmpty) { + log("testAddClose: passed " + + "(expected IllegalPathStateException catched)."); + return; + } else { + throw ipse; + } + } + if (isEmpty) { + throw new IllegalStateException("IllegalPathStateException not thrown !"); + } + log("testAddClose: passed."); + } + + static void testGetBounds(Path2D pathA, Path2D pathB) { + final Rectangle rA = pathA.getBounds(); + final Rectangle rB = pathB.getBounds(); + + if (!rA.equals(rB)) { + throw new IllegalStateException("Bounds are not equals [" + rA + + "|" + rB + "] !"); + } + final Rectangle2D r2dA = pathA.getBounds2D(); + final Rectangle2D r2dB = pathB.getBounds2D(); + + if (!equalsRectangle2D(r2dA, r2dB)) { + throw new IllegalStateException("Bounds2D are not equals [" + + r2dA + "|" + r2dB + "] !"); + } + log("testGetBounds: passed."); + } + + static void testTransform(Path2D pathA) { + pathA.transform(at); + log("testTransform: passed."); + } + + static void testIntersect(Path2D pathA, Path2D pathB) { + boolean resA = pathA.intersects(rect2d); + boolean resB = pathB.intersects(rect2d); + if (resA != resB) { + throw new IllegalStateException("Intersects(rect2d) are not equals [" + + resA + "|" + resB + "] !"); + } + resA = pathA.intersects(1.0, 2.0, 13.0, 17.0); + resB = pathB.intersects(1.0, 2.0, 13.0, 17.0); + if (resA != resB) { + throw new IllegalStateException("Intersects(doubles) are not equals [" + + resA + "|" + resB + "] !"); + } + log("testIntersect: passed."); + } + + static void testContains(Path2D pathA, Path2D pathB) { + boolean resA = pathA.contains(pt2d); + boolean resB = pathB.contains(pt2d); + if (resA != resB) { + throw new IllegalStateException("Contains(pt) are not equals [" + + resA + "|" + resB + "] !"); + } + resA = pathA.contains(pt2d.getX(), pt2d.getY()); + resB = pathB.contains(pt2d.getX(), pt2d.getY()); + if (resA != resB) { + throw new IllegalStateException("Contains(x,y) are not equals [" + + resA + "|" + resB + "] !"); + } + resA = pathA.contains(rect2d); + resB = pathB.contains(rect2d); + if (resA != resB) { + throw new IllegalStateException("Contains(rect2d) are not equals [" + + resA + "|" + resB + "] !"); + } + resA = pathA.contains(1.0, 2.0, 13.0, 17.0); + resB = pathB.contains(1.0, 2.0, 13.0, 17.0); + if (resA != resB) { + throw new IllegalStateException("Contains(doubles) are not equals [" + + resA + "|" + resB + "] !"); + } + log("testContains: passed."); + } + + static void testGetCurrentPoint(Path2D pathA, Path2D pathB) { + final Point2D ptA = pathA.getCurrentPoint(); + final Point2D ptB = pathA.getCurrentPoint(); + if (((ptA == null) && (ptB != null)) + || ((ptA != null) && !ptA.equals(ptB))) + { + throw new IllegalStateException("getCurrentPoint() are not equals [" + + ptA + "|" + ptB + "] !"); + } + log("testGetCurrentPoint: passed."); + } + + static int getLength(int type) { + switch(type) { + case PathIterator.SEG_CUBICTO: + return 6; + case PathIterator.SEG_QUADTO: + return 4; + case PathIterator.SEG_LINETO: + case PathIterator.SEG_MOVETO: + return 2; + case PathIterator.SEG_CLOSE: + return 0; + default: + throw new IllegalStateException("Invalid type: " + type); + } + } + + + // Custom equals methods --- + + public static boolean equalsArray(float[] a, float[] a2, final int len) { + for (int i = 0; i < len; i++) { + if (Float.floatToIntBits(a[i]) != Float.floatToIntBits(a2[i])) { + return false; + } + } + return true; + } + + static boolean equalsArrayEps(float[] a, float[] a2, final int len) { + for (int i = 0; i < len; i++) { + if (!equalsEps(a[i], a2[i])) { + return false; + } + } + + return true; + } + + static boolean equalsRectangle2D(Rectangle2D a, Rectangle2D b) { + if (a == b) { + return true; + } + return equalsEps(a.getX(), b.getX()) + && equalsEps(a.getY(), b.getY()) + && equalsEps(a.getWidth(), b.getWidth()) + && equalsEps(a.getHeight(), b.getHeight()); + } + + static boolean equalsEps(float a, float b) { + return (Math.abs(a - b) <= EPSILON); + } + + static boolean equalsEps(double a, double b) { + return (Math.abs(a - b) <= EPSILON); + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/java/beans/SimpleBeanInfo/LoadingStandardIcons/LoadingStandardIcons.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/beans/SimpleBeanInfo/LoadingStandardIcons/LoadingStandardIcons.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Image; +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; + +import javax.swing.JButton; + +/** + * @test + * @bug 4141523 + * @run main/othervm/policy=java.policy -Djava.security.manager LoadingStandardIcons + */ +public final class LoadingStandardIcons { + + public static void main(final String[] args) { + final Object bi; + try { + bi = Introspector.getBeanInfo(JButton.class); + } catch (IntrospectionException e) { + throw new RuntimeException(e); + } + final Image m16 = ((BeanInfo) bi).getIcon(BeanInfo.ICON_MONO_16x16); + final Image m32 = ((BeanInfo) bi).getIcon(BeanInfo.ICON_MONO_32x32); + final Image c16 = ((BeanInfo) bi).getIcon(BeanInfo.ICON_COLOR_16x16); + final Image c32 = ((BeanInfo) bi).getIcon(BeanInfo.ICON_COLOR_32x32); + if (m16 == null || m32 == null || c16 == null || c32 == null) { + throw new RuntimeException("Image should not be null"); + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/java/beans/SimpleBeanInfo/LoadingStandardIcons/java.policy --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/beans/SimpleBeanInfo/LoadingStandardIcons/java.policy Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,1 @@ +; \ No newline at end of file diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/java/time/test/java/time/format/TestTextParser.java --- a/jdk/test/java/time/test/java/time/format/TestTextParser.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/test/java/time/test/java/time/format/TestTextParser.java Fri Apr 17 10:24:46 2015 -0700 @@ -68,10 +68,20 @@ import java.text.ParsePosition; import java.time.DayOfWeek; +import java.time.chrono.ChronoLocalDate; +import java.time.chrono.JapaneseChronology; +import java.time.chrono.HijrahDate; +import java.time.chrono.JapaneseDate; +import java.time.chrono.MinguoDate; +import java.time.chrono.ThaiBuddhistDate; import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; import java.time.format.TextStyle; +import java.time.format.SignStyle; import java.time.temporal.TemporalAccessor; import java.time.temporal.TemporalField; +import java.time.temporal.TemporalQueries; +import java.time.temporal.ChronoField; import java.util.Locale; import org.testng.annotations.DataProvider; @@ -243,6 +253,8 @@ }; } + + @Test(dataProvider="parseText") public void test_parseText(TemporalField field, TextStyle style, int value, String input) throws Exception { ParsePosition pos = new ParsePosition(0); @@ -433,4 +445,42 @@ assertEquals(pos.getIndex(), input.length()); } + //----------------------------------------------------------------------- + @DataProvider(name="parseChronoLocalDate") + Object[][] provider_chronoLocalDate() { + return new Object[][] { + { HijrahDate.now() }, + { JapaneseDate.now() }, + { MinguoDate.now() }, + { ThaiBuddhistDate.now() }}; + } + + private static final DateTimeFormatter fmt_chrono = + new DateTimeFormatterBuilder() + .optionalStart() + .appendChronologyId() + .appendLiteral(' ') + .optionalEnd() + .optionalStart() + .appendText(ChronoField.ERA, TextStyle.SHORT) + .appendLiteral(' ') + .optionalEnd() + .appendValue(ChronoField.YEAR_OF_ERA, 1, 9, SignStyle.NORMAL) + .appendLiteral('-') + .appendValue(ChronoField.MONTH_OF_YEAR, 1, 2, SignStyle.NEVER) + .appendLiteral('-') + .appendValue(ChronoField.DAY_OF_MONTH, 1, 2, SignStyle.NEVER) + .toFormatter(); + + @Test(dataProvider="parseChronoLocalDate") + public void test_chronoLocalDate(ChronoLocalDate date) throws Exception { + System.out.printf(" %s, [fmt=%s]%n", date, fmt_chrono.format(date)); + assertEquals(date, fmt_chrono.parse(fmt_chrono.format(date), ChronoLocalDate::from)); + + DateTimeFormatter fmt = DateTimeFormatter.ofPattern("[GGG ]yyy-MM-dd") + .withChronology(date.getChronology()); + System.out.printf(" %s, [fmt=%s]%n", date.toString(), fmt.format(date)); + assertEquals(date, fmt.parse(fmt.format(date), ChronoLocalDate::from)); + } + } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java --- a/jdk/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/test/java/util/PluggableLocale/TimeZoneNameProviderTest.java Fri Apr 17 10:24:46 2015 -0700 @@ -25,6 +25,7 @@ */ import java.text.*; +import java.time.format.TextStyle; import java.util.*; import sun.util.locale.provider.*; import sun.util.resources.*; @@ -42,6 +43,7 @@ test2(); test3(); aliasTest(); + genericFallbackTest(); } void test1() { @@ -169,9 +171,9 @@ for (int style : new int[] { TimeZone.LONG, TimeZone.SHORT }) { String osakaStd = tz.getDisplayName(false, style, OSAKA); if (osakaStd != null) { - // No API for getting generic time zone names - String generic = TimeZoneNameUtility.retrieveGenericDisplayName(tzname, - style, GENERIC); + String generic = tz.toZoneId().getDisplayName( + style == TimeZone.LONG ? TextStyle.FULL : TextStyle.SHORT, + GENERIC); String expected = "Generic " + osakaStd; if (!expected.equals(generic)) { throw new RuntimeException("Wrong generic name: got=\"" + generic @@ -230,4 +232,20 @@ throw new RuntimeException("Provider's localized name is not available for an alias ID: "+JAPAN+". result: "+japan+" expected: "+JST_IN_OSAKA); } } + + /* + * Tests whether generic names can be retrieved through fallback. + * The test assumes the provider impl for OSAKA locale does NOT + * provide generic names. + */ + final String PT = "PT"; // SHORT generic name for "America/Los_Angeles" + void genericFallbackTest() { + String generic = + TimeZone.getTimeZone(LATIME) + .toZoneId() + .getDisplayName(TextStyle.SHORT, OSAKA); + if (!PT.equals(generic)) { + throw new RuntimeException("Generic name fallback failed. got: "+generic); + } + } } diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/management/remote/mandatory/notif/NotSerializableNotifTest.java --- a/jdk/test/javax/management/remote/mandatory/notif/NotSerializableNotifTest.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/test/javax/management/remote/mandatory/notif/NotSerializableNotifTest.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2015, 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 @@ -34,37 +34,31 @@ // java imports // import java.net.MalformedURLException; -import java.util.Map; - -// JMX imports -// -import javax.management.* ; - -import javax.management.remote.*; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.MBeanServerFactory; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; public class NotSerializableNotifTest { private static final MBeanServer mbeanServer = MBeanServerFactory.createMBeanServer(); private static ObjectName emitter; - private static int port = 2468; private static String[] protocols; private static final int sentNotifs = 10; - private static double timeoutFactor = 1.0; - private static final double defaultTimeout = 10; - public static void main(String[] args) throws Exception { System.out.println(">>> Test to send a not serializable notification"); - String timeoutVal = System.getProperty("test.timeout.factor"); - if (timeoutVal != null) { - timeoutFactor = Double.parseDouble( - System.getProperty("test.timeout.factor") - ); - } - // IIOP fails on JDK1.4, see 5034318 final String v = System.getProperty("java.version"); float f = Float.parseFloat(v.substring(0, 3)); @@ -77,35 +71,18 @@ emitter = new ObjectName("Default:name=NotificationEmitter"); mbeanServer.registerMBean(new NotificationEmitter(), emitter); - boolean ok = true; for (int i = 0; i < protocols.length; i++) { - try { - if (!test(protocols[i])) { - System.out.println(">>> Test failed for " + protocols[i]); - ok = false; - } else { - System.out.println(">>> Test successed for " + protocols[i]); - } - } catch (Exception e) { - System.out.println(">>> Test failed for " + protocols[i]); - e.printStackTrace(System.out); - ok = false; - } + test(protocols[i]); } - if (ok) { - System.out.println(">>> Test passed"); - } else { - System.out.println(">>> TEST FAILED"); - System.exit(1); - } + System.out.println(">>> Test passed"); } - private static boolean test(String proto) throws Exception { + private static void test(String proto) throws Exception { System.out.println("\n>>> Test for protocol " + proto); - JMXServiceURL url = new JMXServiceURL(proto, null, port++); + JMXServiceURL url = new JMXServiceURL(proto, null, 0); System.out.println(">>> Create a server: "+url); @@ -115,7 +92,7 @@ } catch (MalformedURLException e) { System.out.println("System does not recognize URL: " + url + "; ignoring"); - return true; + return; } server.start(); @@ -146,25 +123,10 @@ // waiting ... synchronized (listener) { - int top = (int)Math.ceil(timeoutFactor * defaultTimeout); - for (int i=0; i commands = new ArrayList<>(); + commands.add(ConcurrentHashMapTest.JAVA); + commands.add("-Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory"); + commands.add("-Djava.naming.provider.url=iiop://localhost:1050"); + commands.add("-cp"); + commands.add(ConcurrentHashMapTest.CLASSPATH); + commands.add("HelloServer"); + + System.out.println("ConcurrentHashMapTest: Executing: " + commands); + ProcessBuilder pb = new ProcessBuilder(commands); + pb.redirectError(ProcessBuilder.Redirect.INHERIT); + rmiServerProcess = pb.start(); + } + + static boolean isResponseReceived() { + return HelloClient.isResponseReceived(); + } + + static void stopRmiIiopServer() throws Exception { + rmiServerProcess.destroy(); + rmiServerProcess.waitFor(); + //rmiServerProcess.waitFor(30, TimeUnit.SECONDS); + System.out.println("serverProcess exitCode:" + + rmiServerProcess.exitValue()); + } + + static void stopOrbd() throws Exception { + orbdProcess.destroy(); + orbdProcess.waitFor(); + //orbdProcess.waitFor(30, TimeUnit.SECONDS); + System.out.println("orbd exitCode:" + + orbdProcess.exitValue()); + } + + static void executeRmiIiopClient() throws Exception { + try { + HelloClient.executeRmiClientCall(); + } catch (Exception ex) { + clientException = ex; + exceptionInClient = true; + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/rmi/PortableRemoteObject/HelloClient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/rmi/PortableRemoteObject/HelloClient.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,98 @@ +import java.rmi.RemoteException; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.rmi.NotBoundException; +import java.util.HashMap; +import java.util.Vector; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +import javax.naming.NamingException; +import javax.naming.InitialContext; +import javax.naming.Context; +import javax.naming.NameNotFoundException; +import javax.naming.NamingException; +import javax.rmi.PortableRemoteObject; + +import org.omg.CORBA.Any; +import org.omg.CORBA.ORB; + +public class HelloClient implements Runnable { + static final int MAX_RETRY = 10; + static final int ONE_SECOND = 1000; + private static boolean responseReceived; + + public static void main(String args[]) throws Exception { + executeRmiClientCall(); + } + + @Override + public void run() { + try { + executeRmiClientCall(); + } catch (Exception e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } + + + public static boolean isResponseReceived () { + return responseReceived; + } + + public static void executeRmiClientCall() throws Exception { + Context ic; + Object objref; + HelloInterface helloSvc; + String response; + int retryCount = 0; + + Test test = new Test(); + System.out.println("HelloClient.main: enter ..."); + while (retryCount < MAX_RETRY) { + try { + ic = new InitialContext(); + System.out.println("HelloClient.main: HelloService lookup ..."); + // STEP 1: Get the Object reference from the Name Service + // using JNDI call. + objref = ic.lookup("HelloService"); + System.out.println("HelloClient: Obtained a ref. to Hello server."); + + // STEP 2: Narrow the object reference to the concrete type and + // invoke the method. + helloSvc = (HelloInterface) PortableRemoteObject.narrow(objref, + HelloInterface.class); + System.out.println("HelloClient: Invoking on remote server with ConcurrentHashMap parameter"); + ConcurrentHashMap testConcurrentHashMap = new ConcurrentHashMap(); + response = helloSvc.sayHelloWithHashMap(testConcurrentHashMap); + System.out.println("HelloClient: Server says: " + response); + if (!response.contains("Hello with hashMapSize ==")) { + System.out.println("HelloClient: expected response not received"); + throw new RuntimeException("Expected Response Hello with hashMapSize == 0 not received"); + } + responseReceived = true; + break; + } catch (NameNotFoundException nnfEx) { + System.err.println("NameNotFoundException Caught .... try again"); + retryCount++; + try { + Thread.sleep(ONE_SECOND); + } catch (InterruptedException e) { + e.printStackTrace(); + } + continue; + } catch (Exception e) { + System.err.println("Exception " + e + "Caught"); + e.printStackTrace(); + throw new RuntimeException(e); + } + } + System.err.println("HelloClient terminating "); + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/rmi/PortableRemoteObject/HelloImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/rmi/PortableRemoteObject/HelloImpl.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,60 @@ +import java.net.InetAddress; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +import javax.rmi.PortableRemoteObject; + +public class HelloImpl extends PortableRemoteObject implements HelloInterface { + public HelloImpl() throws java.rmi.RemoteException { + super(); // invoke rmi linking and remote object initialization + } + + public String sayHello(String from) throws java.rmi.RemoteException { + System.out.println("Hello from " + from + "!!"); + System.out.flush(); + String reply = "Hello from us to you " + from; + return reply; + } + + @Override + public String sayHelloToTest(Test test) throws RemoteException { + return "Test says Hello"; + } + + @Override + public String sayHelloWithInetAddress(InetAddress ipAddr) + throws RemoteException { + String response = "Hello with InetAddress " + ipAddr.toString(); + return response; + } + + @Override + public String sayHelloWithHashMap(ConcurrentHashMap receivedHashMap) + throws RemoteException { + int hashMapSize = 0; + + hashMapSize = receivedHashMap.size(); + String response = "Hello with hashMapSize == " + hashMapSize; + return response; + } + + @Override + public String sayHelloWithHashMap2(HashMap receivedHashMap) + throws RemoteException { + int hashMapSize = 0; + + hashMapSize = receivedHashMap.size(); + String response = "Hello with hashMapSize == " + hashMapSize; + return response; + } + + @Override + public String sayHelloWithReentrantLock(ReentrantLock receivedLock) + throws RemoteException { + + String response = "Hello with lock == " + receivedLock.isLocked(); + return response; + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/rmi/PortableRemoteObject/HelloInterface.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/rmi/PortableRemoteObject/HelloInterface.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,14 @@ +import java.net.InetAddress; +import java.rmi.Remote; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; + +public interface HelloInterface extends Remote { + public String sayHello( String from ) throws java.rmi.RemoteException; + public String sayHelloToTest( Test test ) throws java.rmi.RemoteException; + public String sayHelloWithInetAddress( InetAddress ipAddr ) throws java.rmi.RemoteException; + public String sayHelloWithHashMap(ConcurrentHashMap hashMap ) throws java.rmi.RemoteException; + public String sayHelloWithHashMap2(HashMap hashMap ) throws java.rmi.RemoteException; + public String sayHelloWithReentrantLock(ReentrantLock lock ) throws java.rmi.RemoteException; +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/rmi/PortableRemoteObject/HelloServer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/rmi/PortableRemoteObject/HelloServer.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,36 @@ +import javax.naming.InitialContext; +import javax.naming.Context; + +public class HelloServer { + + static final int MAX_RETRY = 10; + static final int ONE_SECOND = 1000; + + public static void main(String[] args) { + int retryCount = 0; + while (retryCount < MAX_RETRY) { + try { + //HelloServer.set("SETTING TEST ITL"); + // Step 1: Instantiate the Hello servant + HelloImpl helloRef = new HelloImpl(); + + // Step 2: Publish the reference in the Naming Service + // using JNDI API + Context initialNamingContext = new InitialContext(); + initialNamingContext.rebind("HelloService", helloRef); + + System.out.println("Hello Server: Ready..."); + break; + } catch (Exception e) { + System.out.println("Server initialization problem: " + e); + e.printStackTrace(); + retryCount++; + try { + Thread.sleep(ONE_SECOND); + } catch (InterruptedException e1) { + e1.printStackTrace(); + } + } + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/rmi/PortableRemoteObject/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/rmi/PortableRemoteObject/Test.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,6 @@ +import java.io.Serializable; + + +public class Test implements Serializable { + +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/rmi/PortableRemoteObject/_HelloImpl_Tie.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/rmi/PortableRemoteObject/_HelloImpl_Tie.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,128 @@ +// Tie class generated by rmic, do not edit. +// Contents subject to change without notice. + +import java.io.Serializable; +import java.net.InetAddress; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; +import javax.rmi.CORBA.Tie; +import javax.rmi.CORBA.Util; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ResponseHandler; +import org.omg.CORBA.portable.UnknownException; +import org.omg.CORBA_2_3.portable.ObjectImpl; + + +public class _HelloImpl_Tie extends ObjectImpl implements Tie { + + private HelloImpl target = null; + + private static final String[] _type_ids = { + "RMI:HelloInterface:0000000000000000" + }; + + public void setTarget(Remote target) { + this.target = (HelloImpl) target; + } + + public Remote getTarget() { + return target; + } + + public org.omg.CORBA.Object thisObject() { + return this; + } + + public void deactivate() { + _orb().disconnect(this); + _set_delegate(null); + target = null; + } + + public ORB orb() { + return _orb(); + } + + public void orb(ORB orb) { + orb.connect(this); + } + + public String[] _ids() { + return (String[]) _type_ids.clone(); + } + + public OutputStream _invoke(String method, InputStream _in, ResponseHandler reply) throws SystemException { + try { + org.omg.CORBA_2_3.portable.InputStream in = + (org.omg.CORBA_2_3.portable.InputStream) _in; + switch (method.length()) { + case 8: + if (method.equals("sayHello")) { + String arg0 = (String) in.read_value(String.class); + String result = target.sayHello(arg0); + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) reply.createReply(); + out.write_value(result,String.class); + return out; + } + case 14: + if (method.equals("sayHelloToTest")) { + Test arg0 = (Test) in.read_value(Test.class); + String result = target.sayHelloToTest(arg0); + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) reply.createReply(); + out.write_value(result,String.class); + return out; + } + case 19: + if (method.equals("sayHelloWithHashMap")) { + ConcurrentHashMap arg0 = (ConcurrentHashMap) in.read_value(ConcurrentHashMap.class); + String result = target.sayHelloWithHashMap(arg0); + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) reply.createReply(); + out.write_value(result,String.class); + return out; + } + case 20: + if (method.equals("sayHelloWithHashMap2")) { + HashMap arg0 = (HashMap) in.read_value(HashMap.class); + String result = target.sayHelloWithHashMap2(arg0); + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) reply.createReply(); + out.write_value(result,String.class); + return out; + } + case 23: + if (method.equals("sayHelloWithInetAddress")) { + InetAddress arg0 = (InetAddress) in.read_value(InetAddress.class); + String result = target.sayHelloWithInetAddress(arg0); + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) reply.createReply(); + out.write_value(result,String.class); + return out; + } + case 25: + if (method.equals("sayHelloWithReentrantLock")) { + ReentrantLock arg0 = (ReentrantLock) in.read_value(ReentrantLock.class); + String result = target.sayHelloWithReentrantLock(arg0); + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) reply.createReply(); + out.write_value(result,String.class); + return out; + } + } + throw new BAD_OPERATION(); + } catch (SystemException ex) { + throw ex; + } catch (Throwable ex) { + throw new UnknownException(ex); + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/rmi/PortableRemoteObject/_HelloInterface_Stub.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/rmi/PortableRemoteObject/_HelloInterface_Stub.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,272 @@ +// Stub class generated by rmic, do not edit. +// Contents subject to change without notice. + +import java.io.Serializable; +import java.net.InetAddress; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.UnexpectedException; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; +import javax.rmi.CORBA.Stub; +import javax.rmi.CORBA.Util; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.portable.ApplicationException; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.RemarshalException; +import org.omg.CORBA.portable.ResponseHandler; +import org.omg.CORBA.portable.ServantObject; + + +public class _HelloInterface_Stub extends Stub implements HelloInterface { + + private static final String[] _type_ids = { + "RMI:HelloInterface:0000000000000000" + }; + + public String[] _ids() { + return (String[]) _type_ids.clone(); + } + + public String sayHello(String arg0) throws java.rmi.RemoteException { + if (!Util.isLocal(this)) { + try { + org.omg.CORBA_2_3.portable.InputStream in = null; + try { + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) + _request("sayHello", true); + out.write_value(arg0,String.class); + in = (org.omg.CORBA_2_3.portable.InputStream)_invoke(out); + return (String) in.read_value(String.class); + } catch (ApplicationException ex) { + in = (org.omg.CORBA_2_3.portable.InputStream) ex.getInputStream(); + String $_id = in.read_string(); + throw new UnexpectedException($_id); + } catch (RemarshalException ex) { + return sayHello(arg0); + } finally { + _releaseReply(in); + } + } catch (SystemException ex) { + throw Util.mapSystemException(ex); + } + } else { + ServantObject so = _servant_preinvoke("sayHello",HelloInterface.class); + if (so == null) { + return sayHello(arg0); + } + try { + return ((HelloInterface)so.servant).sayHello(arg0); + } catch (Throwable ex) { + Throwable exCopy = (Throwable)Util.copyObject(ex,_orb()); + throw Util.wrapException(exCopy); + } finally { + _servant_postinvoke(so); + } + } + } + + public String sayHelloToTest(Test arg0) throws java.rmi.RemoteException { + if (!Util.isLocal(this)) { + try { + org.omg.CORBA_2_3.portable.InputStream in = null; + try { + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) + _request("sayHelloToTest", true); + out.write_value(arg0,Test.class); + in = (org.omg.CORBA_2_3.portable.InputStream)_invoke(out); + return (String) in.read_value(String.class); + } catch (ApplicationException ex) { + in = (org.omg.CORBA_2_3.portable.InputStream) ex.getInputStream(); + String $_id = in.read_string(); + throw new UnexpectedException($_id); + } catch (RemarshalException ex) { + return sayHelloToTest(arg0); + } finally { + _releaseReply(in); + } + } catch (SystemException ex) { + throw Util.mapSystemException(ex); + } + } else { + ServantObject so = _servant_preinvoke("sayHelloToTest",HelloInterface.class); + if (so == null) { + return sayHelloToTest(arg0); + } + try { + Test arg0Copy = (Test) Util.copyObject(arg0,_orb()); + return ((HelloInterface)so.servant).sayHelloToTest(arg0Copy); + } catch (Throwable ex) { + Throwable exCopy = (Throwable)Util.copyObject(ex,_orb()); + throw Util.wrapException(exCopy); + } finally { + _servant_postinvoke(so); + } + } + } + + public String sayHelloWithInetAddress(InetAddress arg0) throws java.rmi.RemoteException { + if (!Util.isLocal(this)) { + try { + org.omg.CORBA_2_3.portable.InputStream in = null; + try { + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) + _request("sayHelloWithInetAddress", true); + out.write_value(arg0,InetAddress.class); + in = (org.omg.CORBA_2_3.portable.InputStream)_invoke(out); + return (String) in.read_value(String.class); + } catch (ApplicationException ex) { + in = (org.omg.CORBA_2_3.portable.InputStream) ex.getInputStream(); + String $_id = in.read_string(); + throw new UnexpectedException($_id); + } catch (RemarshalException ex) { + return sayHelloWithInetAddress(arg0); + } finally { + _releaseReply(in); + } + } catch (SystemException ex) { + throw Util.mapSystemException(ex); + } + } else { + ServantObject so = _servant_preinvoke("sayHelloWithInetAddress",HelloInterface.class); + if (so == null) { + return sayHelloWithInetAddress(arg0); + } + try { + InetAddress arg0Copy = (InetAddress) Util.copyObject(arg0,_orb()); + return ((HelloInterface)so.servant).sayHelloWithInetAddress(arg0Copy); + } catch (Throwable ex) { + Throwable exCopy = (Throwable)Util.copyObject(ex,_orb()); + throw Util.wrapException(exCopy); + } finally { + _servant_postinvoke(so); + } + } + } + + public String sayHelloWithHashMap(ConcurrentHashMap arg0) throws java.rmi.RemoteException { + if (!Util.isLocal(this)) { + try { + org.omg.CORBA_2_3.portable.InputStream in = null; + try { + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) + _request("sayHelloWithHashMap", true); + out.write_value(arg0,ConcurrentHashMap.class); + in = (org.omg.CORBA_2_3.portable.InputStream)_invoke(out); + return (String) in.read_value(String.class); + } catch (ApplicationException ex) { + in = (org.omg.CORBA_2_3.portable.InputStream) ex.getInputStream(); + String $_id = in.read_string(); + throw new UnexpectedException($_id); + } catch (RemarshalException ex) { + return sayHelloWithHashMap(arg0); + } finally { + _releaseReply(in); + } + } catch (SystemException ex) { + throw Util.mapSystemException(ex); + } + } else { + ServantObject so = _servant_preinvoke("sayHelloWithHashMap",HelloInterface.class); + if (so == null) { + return sayHelloWithHashMap(arg0); + } + try { + ConcurrentHashMap arg0Copy = (ConcurrentHashMap) Util.copyObject(arg0,_orb()); + return ((HelloInterface)so.servant).sayHelloWithHashMap(arg0Copy); + } catch (Throwable ex) { + Throwable exCopy = (Throwable)Util.copyObject(ex,_orb()); + throw Util.wrapException(exCopy); + } finally { + _servant_postinvoke(so); + } + } + } + + public String sayHelloWithHashMap2(HashMap arg0) throws java.rmi.RemoteException { + if (!Util.isLocal(this)) { + try { + org.omg.CORBA_2_3.portable.InputStream in = null; + try { + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) + _request("sayHelloWithHashMap2", true); + out.write_value(arg0,HashMap.class); + in = (org.omg.CORBA_2_3.portable.InputStream)_invoke(out); + return (String) in.read_value(String.class); + } catch (ApplicationException ex) { + in = (org.omg.CORBA_2_3.portable.InputStream) ex.getInputStream(); + String $_id = in.read_string(); + throw new UnexpectedException($_id); + } catch (RemarshalException ex) { + return sayHelloWithHashMap2(arg0); + } finally { + _releaseReply(in); + } + } catch (SystemException ex) { + throw Util.mapSystemException(ex); + } + } else { + ServantObject so = _servant_preinvoke("sayHelloWithHashMap2",HelloInterface.class); + if (so == null) { + return sayHelloWithHashMap2(arg0); + } + try { + HashMap arg0Copy = (HashMap) Util.copyObject(arg0,_orb()); + return ((HelloInterface)so.servant).sayHelloWithHashMap2(arg0Copy); + } catch (Throwable ex) { + Throwable exCopy = (Throwable)Util.copyObject(ex,_orb()); + throw Util.wrapException(exCopy); + } finally { + _servant_postinvoke(so); + } + } + } + + public String sayHelloWithReentrantLock(ReentrantLock arg0) throws java.rmi.RemoteException { + if (!Util.isLocal(this)) { + try { + org.omg.CORBA_2_3.portable.InputStream in = null; + try { + org.omg.CORBA_2_3.portable.OutputStream out = + (org.omg.CORBA_2_3.portable.OutputStream) + _request("sayHelloWithReentrantLock", true); + out.write_value(arg0,ReentrantLock.class); + in = (org.omg.CORBA_2_3.portable.InputStream)_invoke(out); + return (String) in.read_value(String.class); + } catch (ApplicationException ex) { + in = (org.omg.CORBA_2_3.portable.InputStream) ex.getInputStream(); + String $_id = in.read_string(); + throw new UnexpectedException($_id); + } catch (RemarshalException ex) { + return sayHelloWithReentrantLock(arg0); + } finally { + _releaseReply(in); + } + } catch (SystemException ex) { + throw Util.mapSystemException(ex); + } + } else { + ServantObject so = _servant_preinvoke("sayHelloWithReentrantLock",HelloInterface.class); + if (so == null) { + return sayHelloWithReentrantLock(arg0); + } + try { + ReentrantLock arg0Copy = (ReentrantLock) Util.copyObject(arg0,_orb()); + return ((HelloInterface)so.servant).sayHelloWithReentrantLock(arg0Copy); + } catch (Throwable ex) { + Throwable exCopy = (Throwable)Util.copyObject(ex,_orb()); + throw Util.wrapException(exCopy); + } finally { + _servant_postinvoke(so); + } + } + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/swing/GroupLayout/8013566/bug8013566.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/GroupLayout/8013566/bug8013566.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 8013566 + @summary Failure of GroupLayout in combination of addPreferredGap and addGroup's + last row + @author Semyon Sadetsky +*/ + +import javax.swing.*; + +public class bug8013566 { + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + final JFrame frame = new JFrame(); + try { + frame.setUndecorated(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + test(frame); + + + } finally { + frame.dispose(); + } + } + }); + + System.out.println("ok"); + } + + static void test(JFrame frame) { + JComponent c1 = new JButton("Label1"); + JComponent c2 = new JButton("Label22"); + JComponent c3 = new JButton("Label333"); + + JPanel panel = new JPanel(); + GroupLayout layout = new GroupLayout(panel); + layout.setAutoCreateContainerGaps(true); + layout.setAutoCreateGaps(true); + panel.setLayout(layout); + + layout.setHorizontalGroup(layout.createSequentialGroup().addGroup( + layout.createParallelGroup().addGroup( + layout.createSequentialGroup().addComponent(c1) + .addPreferredGap( + LayoutStyle.ComponentPlacement.RELATED, + 50, 200)) + .addComponent(c2)).addComponent(c3)); + + layout.setVerticalGroup(layout.createSequentialGroup() + .addComponent(c1).addComponent(c2).addComponent(c3) + ); + + frame.setContentPane(panel); + frame.pack(); + frame.setVisible(true); + + if (c3.getX() != c1.getX() + c1.getWidth() + 50) { + throw new RuntimeException( + "Gap between 1st and 3rd component is wrong"); + } + + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/swing/JInternalFrame/8075314/bug8075314.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JInternalFrame/8075314/bug8075314.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 8075314 + @summary All the InternalFrames will be maximized after maximizing only one + of the InternalFrame with the special options "-client -Xmixed + -Dswing.defaultlaf=com.sun.java.swing.plaf.windows.WindowsLookAndFeel". + @author Semyon Sadetsky + */ + + +import javax.swing.*; +import java.beans.PropertyVetoException; + +public class bug8075314 { + + + private static JFrame frame; + private static JInternalFrame frame1; + private static JInternalFrame frame2; + + public static void main(String[] args) throws Exception { + for (UIManager.LookAndFeelInfo lookAndFeelInfo : UIManager + .getInstalledLookAndFeels()) { + UIManager.setLookAndFeel(lookAndFeelInfo.getClassName()); + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame = new JFrame(); + frame.setUndecorated(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setup(frame); + } + }); + + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + try { + frame1.setMaximum(true); + frame1.setClosed(true); + if (frame2.isMaximum()) { + throw new RuntimeException( + "Frame2 is maximized!"); + } + } catch (PropertyVetoException e) { + throw new RuntimeException(e); + } + + } + }); + } finally { + frame.dispose(); + } + } + System.out.println("ok"); + } + + private static void setup(JFrame frame) { + JDesktopPane desktop = new JDesktopPane(); + frame.setContentPane(desktop); + + frame1 = new JInternalFrame("1", true, true, true, true); + frame1.setBounds(40, 40, 300, 200); + frame1.setVisible(true); + desktop.add(frame1); + frame2 = new JInternalFrame("2", true, true, true, true); + frame2.setBounds(20, 20, 300, 200); + frame2.setVisible(true); + desktop.add(frame2); + + frame.setSize(500, 400); + frame.setVisible(true); + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/swing/JScrollPane/8033000/bug8033000.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JScrollPane/8033000/bug8033000.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +import java.awt.BorderLayout; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.KeyEvent; +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import jdk.testlibrary.OSInfo; + +/** + * @test + * @bug 8033000 + * @author Alexander Scherbatiy + * @summary No Horizontal Mouse Wheel Support In BasicScrollPaneUI + * @library ../../../../lib/testlibrary + * @build jdk.testlibrary.OSInfo + * @run main bug8033000 + */ +public class bug8033000 { + + private static JScrollPane scrollPane; + private static JTextArea textArea; + private static Point point; + private static final int delta; + + static { + delta = OSInfo.getOSType().equals(OSInfo.OSType.MACOSX) ? -30 : 30; + } + + public static void main(String[] args) throws Exception { + + Robot robot = new Robot(); + robot.setAutoDelay(50); + + SwingUtilities.invokeAndWait(bug8033000::createAndShowGUI); + robot.waitForIdle(); + + SwingUtilities.invokeAndWait(() -> { + Point locationOnScreen = scrollPane.getLocationOnScreen(); + point = new Point( + locationOnScreen.x + scrollPane.getWidth() / 2, + locationOnScreen.y + scrollPane.getHeight() / 2); + }); + + robot.mouseMove(point.x, point.y); + robot.waitForIdle(); + + // vertical scroll bar is enabled + initScrollPane(true, false); + robot.waitForIdle(); + robot.mouseWheel(delta); + robot.waitForIdle(); + checkScrollPane(true); + + // vertical scroll bar is enabled + shift + initScrollPane(true, false); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.mouseWheel(delta); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.waitForIdle(); + checkScrollPane(true); + + // horizontal scroll bar is enabled + initScrollPane(false, true); + robot.waitForIdle(); + robot.mouseWheel(delta); + robot.waitForIdle(); + checkScrollPane(false); + + // horizontal scroll bar is enabled + shift + initScrollPane(false, true); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.mouseWheel(delta); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.waitForIdle(); + checkScrollPane(false); + + // both scroll bars are enabled + initScrollPane(true, true); + robot.waitForIdle(); + robot.mouseWheel(delta); + robot.waitForIdle(); + checkScrollPane(true); + + // both scroll bars are enabled + shift + initScrollPane(true, true); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_SHIFT); + robot.mouseWheel(delta); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.waitForIdle(); + checkScrollPane(false); + } + + static void initScrollPane(boolean vVisible, boolean hVisible) throws Exception { + SwingUtilities.invokeAndWait(() -> { + scrollPane.getVerticalScrollBar().setValue(0); + scrollPane.getHorizontalScrollBar().setValue(0); + + textArea.setRows(vVisible ? 100 : 1); + textArea.setColumns(hVisible ? 100 : 1); + scrollPane.getVerticalScrollBar().setVisible(vVisible); + scrollPane.getHorizontalScrollBar().setVisible(hVisible); + }); + } + + static void checkScrollPane(boolean verticalScrolled) throws Exception { + SwingUtilities.invokeAndWait(() -> { + + if (verticalScrolled) { + if (scrollPane.getVerticalScrollBar().getValue() == 0 + || scrollPane.getHorizontalScrollBar().getValue() != 0) { + throw new RuntimeException("Wrong vertical scrolling!"); + } + } else { + if (scrollPane.getVerticalScrollBar().getValue() != 0 + || scrollPane.getHorizontalScrollBar().getValue() == 0) { + throw new RuntimeException("Wrong horizontal scrolling!"); + } + } + }); + } + + static void createAndShowGUI() { + JFrame frame = new JFrame(); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setSize(300, 300); + textArea = new JTextArea("Hello World!"); + scrollPane = new JScrollPane(textArea); + JPanel panel = new JPanel(new BorderLayout()); + panel.add(scrollPane, BorderLayout.CENTER); + frame.getContentPane().add(panel); + frame.setVisible(true); + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/swing/JTable/6894632/bug6894632.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/JTable/6894632/bug6894632.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 6894632 + @summary Removing rows from a DefaultTableModel with a RowSorter deselectes + last row + @author Semyon Sadetsky +*/ + +import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; +import java.util.ArrayList; +import java.util.List; + +public class bug6894632 { + private static JTable table; + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + + //init table with empty sort order + test(new ArrayList()); + + //init table as unsorted + List sortKeys = new ArrayList<>(); + sortKeys.add(0, new RowSorter.SortKey(0, SortOrder.UNSORTED)); + test(sortKeys); + } + }); + + System.out.println("ok"); + } + + static void test(final List sortKeys) { + final JFrame frame = new JFrame(); + try { + frame.setUndecorated(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + table = new JTable(); + DefaultTableModel tableModel = + new DefaultTableModel(10, 1) { + public Object getValueAt(int row, int column) { + return row == getRowCount() - 1 ? row + "==last" : + row; + } + }; + table.setModel(tableModel); + TableRowSorter sorter = + new TableRowSorter(tableModel); + sorter.setSortKeys(sortKeys); + table.setRowSorter(sorter); + + frame.setContentPane(table); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + + int lastRow = table.getRowCount() - 1; + + //select last row + table.setRowSelectionInterval(lastRow, lastRow); + + //remove row above the last + tableModel.removeRow(lastRow - 1); + lastRow = table.getRowCount() - 1; + if (lastRow != table.getSelectedRow()) { + throw new RuntimeException("last row must be still selected"); + } + + //sort table + sortKeys.clear(); + sortKeys.add(0, new RowSorter.SortKey(0, SortOrder.ASCENDING)); + sorter.setSortKeys(sortKeys); + //remove row above the last + lastRow = table.getRowCount() - 1; + tableModel.removeRow(lastRow - 1); + + if (!table.getValueAt(table.getSelectedRow(), 0).toString() + .endsWith("==last")) { + throw new RuntimeException( + "row ends with \"==last\" row must be still selected"); + } + + //make table unsorted again + sortKeys.clear(); + sortKeys.add(0, new RowSorter.SortKey(0, SortOrder.UNSORTED)); + sorter.setSortKeys(sortKeys); + //remove row above the last + lastRow = table.getRowCount() - 1; + tableModel.removeRow(lastRow - 1); + + lastRow = table.getRowCount() - 1; + if (lastRow != table.getSelectedRow()) { + throw new RuntimeException( + "last row must be still selected"); + } + } finally { + frame.dispose(); + } + } + + +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/swing/plaf/nimbus/8041642/bug8041642.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/plaf/nimbus/8041642/bug8041642.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 8041642 + @summary Incorrect paint of JProgressBar in Nimbus LF + @author Semyon Sadetsky +*/ + +import javax.swing.*; +import java.awt.*; + +public class bug8041642 { + + private static JFrame frame; + private static Point point; + private static JProgressBar bar; + + public static void main(String[] args) throws Exception { + for (UIManager.LookAndFeelInfo info : UIManager + .getInstalledLookAndFeels()) { + if ("Nimbus".equals(info.getName())) { + try { + UIManager.setLookAndFeel(info.getClassName()); + } catch (Exception ex) { + } + break; + } + } + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame = new JFrame(); + frame.setUndecorated(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setup(frame); + } + }); + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + point = bar.getLocationOnScreen(); + } + }); + final Robot robot = new Robot(); + Color color = robot.getPixelColor(point.x + 1, point.y + 7); + System.out.println(color); + if (color.getGreen() < 150 || color.getBlue() > 30 || + color.getRed() > 200) { + throw new RuntimeException("Bar padding color should be green"); + } + + } finally { + SwingUtilities.invokeAndWait(new Runnable() { + @Override + public void run() { + //frame.dispose(); + } + }); + } + + System.out.println("ok"); + } + + static void setup(JFrame frame) { + bar = new JProgressBar(); + bar.setBackground(Color.WHITE); + bar.setValue(2); + frame.getContentPane().add(bar, BorderLayout.NORTH); + frame.getContentPane().setBackground(Color.GREEN); + frame.setSize(200, 150); + frame.setLocation(100, 100); + frame.setVisible(true); + } +} diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/javax/swing/plaf/windows/6921687/bug6921687.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/swing/plaf/windows/6921687/bug6921687.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* @test + @bug 6921687 + @summary Mnemonic disappears after repeated attempts to open menu items using + mnemonics + @author Semyon Sadetsky + @library /lib/testlibrary + @build jdk.testlibrary.OSInfo + */ + + +import jdk.testlibrary.OSInfo; +import javax.swing.*; +import java.awt.*; +import java.awt.event.KeyEvent; + + +public class bug6921687 { + + private static Class lafClass; + private static JFrame frame; + + public static void main(String[] args) throws Exception { + if (OSInfo.getOSType() != OSInfo.OSType.WINDOWS) { + System.out.println("Only Windows platform test. Test is skipped."); + System.out.println("ok"); + return; + } + lafClass = Class.forName(UIManager.getSystemLookAndFeelClassName()); + UIManager.setLookAndFeel((LookAndFeel) lafClass.newInstance()); + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + frame = new JFrame(); + frame.setUndecorated(true); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setup(frame); + } + }); + + final Robot robot = new Robot(); + robot.setAutoDelay(20); + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_ALT); + robot.waitForIdle(); + checkMnemonics(); + + robot.keyPress(KeyEvent.VK_ALT); + robot.keyPress(KeyEvent.VK_S); + robot.keyRelease(KeyEvent.VK_S); + robot.keyRelease(KeyEvent.VK_ALT); + robot.waitForIdle(); + checkMnemonics(); + System.out.println("ok"); + } finally { + frame.dispose(); + } + + } + + private static void checkMnemonics() throws Exception { + if ((Boolean) lafClass.getMethod("isMnemonicHidden").invoke(lafClass)) { + throw new RuntimeException("Mnemonics are hidden"); + } + } + + private static void setup(JFrame frame) { + JMenuBar menuBar = new JMenuBar(); + frame.setJMenuBar(menuBar); + + // First Menu, F - Mnemonic + JMenu firstMenu = new JMenu("First Menu"); + firstMenu.setMnemonic(KeyEvent.VK_F); + firstMenu.add(new JMenuItem("One", KeyEvent.VK_O)); + firstMenu.add(new JMenuItem("Two", KeyEvent.VK_T)); + menuBar.add(firstMenu); + + // Second Menu, S - Mnemonic + JMenu secondMenu = new JMenu("Second Menu"); + secondMenu.setMnemonic(KeyEvent.VK_S); + secondMenu.add(new JMenuItem("A Menu Item", KeyEvent.VK_A)); + menuBar.add(secondMenu); + + frame.setSize(350, 250); + frame.setVisible(true); + + } +} \ No newline at end of file diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/sun/security/krb5/auto/SSL.java --- a/jdk/test/sun/security/krb5/auto/SSL.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/test/sun/security/krb5/auto/SSL.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2015, 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 @@ -39,11 +39,10 @@ * @run main/othervm SSL TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5 */ import java.io.*; -import java.net.InetAddress; -import java.security.AccessControlException; import java.security.Permission; import javax.net.ssl.*; import java.security.Principal; +import java.security.Security; import java.util.Date; import java.util.List; import java.util.ArrayList; @@ -82,6 +81,9 @@ } public static void main(String[] args) throws Exception { + // reset the security property to make sure that the algorithms + // and keys used in this test are not disabled. + Security.setProperty("jdk.tls.disabledAlgorithms", ""); krb5Cipher = args[0]; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/sun/security/ssl/ClientHandshaker/CipherSuiteOrder.java --- a/jdk/test/sun/security/ssl/ClientHandshaker/CipherSuiteOrder.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/test/sun/security/ssl/ClientHandshaker/CipherSuiteOrder.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2015, 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 @@ -34,7 +34,7 @@ */ import java.io.*; -import java.net.*; +import java.security.Security; import javax.net.ssl.*; public class CipherSuiteOrder { @@ -196,6 +196,10 @@ volatile Exception clientException = null; public static void main(String[] args) throws Exception { + // reset the security property to make sure that the algorithms + // and keys used in this test are not disabled. + Security.setProperty("jdk.tls.disabledAlgorithms", ""); + String keyFilename = System.getProperty("test.src", "./") + "/" + pathToStores + "/" + keyStoreFile; diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java --- a/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java Fri Apr 17 09:59:46 2015 -0700 +++ b/jdk/test/sun/security/ssl/DHKeyExchange/DHEKeySizing.java Fri Apr 17 10:24:46 2015 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2015, 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 @@ -102,10 +102,10 @@ import java.nio.*; import java.security.KeyStore; import java.security.KeyFactory; +import java.security.Security; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.*; import java.security.interfaces.*; import java.util.Base64; @@ -377,6 +377,10 @@ } public static void main(String args[]) throws Exception { + // reset the security property to make sure that the algorithms + // and keys used in this test are not disabled. + Security.setProperty("jdk.tls.disabledAlgorithms", ""); + if (args.length != 4) { System.out.println( "Usage: java DHEKeySizing cipher-suite " + diff -r 1bdcfecae7b4 -r d729bb3d4ba9 jdk/test/sun/security/validator/EndEntityExtensionCheck.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/sun/security/validator/EndEntityExtensionCheck.java Fri Apr 17 10:24:46 2015 -0700 @@ -0,0 +1,221 @@ +/* + * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8076117 + * @summary EndEntityChecker should not process custom extensions + * after PKIX validation + */ + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.security.KeyStore; +import java.security.cert.CertPathValidatorException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import sun.security.validator.KeyStores; +import sun.security.validator.Validator; + + +public class EndEntityExtensionCheck { + + /* + * Owner: CN=TestCA + * Issuer: CN=TestCA + */ + private static final String CA = + "-----BEGIN CERTIFICATE-----\n" + + "MIICgDCCAj2gAwIBAgIEC18hWjALBgcqhkjOOAQDBQAwETEPMA0GA1UEAxMGVGVz\n" + + "dENBMB4XDTE1MDQwNzIyMzUyMFoXDTI1MDQwNjIyMzUyMFowETEPMA0GA1UEAxMG\n" + + "VGVzdENBMIIBuDCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2\n" + + "EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdr\n" + + "mVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXz\n" + + "rith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+Gghdab\n" + + "Pd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6Ewo\n" + + "FhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhR\n" + + "kImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUAAoGBAJOWy2hVy4iNwsi/idWG\n" + + "oksr9IZxQIFR2YavoUmD+rIgfYUpiCihzftDLMMaNYqp9PPxuOyoIPGPbwmKpAs5\n" + + "nq6gLwH2lSsN+EwyV2SJ0J26PHiMuRNZWWfKR3cpEqbQVb0CmvqSpj8zYfamPzp7\n" + + "eXSWwahzgLCGJM3SgCfDFC0uoyEwHzAdBgNVHQ4EFgQU7tLD8FnWM+r6jBr+mCXs\n" + + "8G5yBpgwCwYHKoZIzjgEAwUAAzAAMC0CFQCHCtzC3S0ST0EZBucikVui4WXD8QIU\n" + + "L3Oxy6989/FhZlZWJlhqc1ungEQ=\n" + + "-----END CERTIFICATE-----"; + + /* + * Owner: CN=TestEE + * Issuer: CN=TestCA + * Contains a custom critical extension with OID 1.2.3.4: + * #1: ObjectId: 1.2.3.4 Criticality=true + * 0000: 00 00 + */ + private static final String EE = + "-----BEGIN CERTIFICATE-----\n" + + "MIICrTCCAmugAwIBAgIELjciKzALBgcqhkjOOAQDBQAwETEPMA0GA1UEAxMGVGVz\n" + + "dENBMB4XDTE1MDQwNzIzMDA1OFoXDTE1MDcwNjIzMDA1OFowETEPMA0GA1UEAxMG\n" + + "VGVzdEVFMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2\n" + + "EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdr\n" + + "mVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXz\n" + + "rith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+Gghdab\n" + + "Pd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6Ewo\n" + + "FhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhR\n" + + "kImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAN97otrAJEuUg/O97vScI\n" + + "01xs1jqTz5o0PGpKiDDJNB3tCCUbLqXoBQBvSefQ8vYL3mmlEJLxlwfbajRmJQp0\n" + + "tUy5SUCZHk3MdoKxSvrqYnVpYwJHFXKWs6lAawxfuWbkm9SREuepOWnVzy2ecf5z\n" + + "hvy9mgEBfi4E9Cy8Byq2TpyjUDBOMAwGAyoDBAEB/wQCAAAwHwYDVR0jBBgwFoAU\n" + + "7tLD8FnWM+r6jBr+mCXs8G5yBpgwHQYDVR0OBBYEFNRVqt5F+EAuJ5x1IZLDkoMs\n" + + "mDj4MAsGByqGSM44BAMFAAMvADAsAhQyNGhxIp5IshN1zqLs4pUY214IMAIUMmTL\n" + + "3ZMpMAjITbuHHlFNUqZ7A9s=\n" + + "-----END CERTIFICATE-----"; + + public static void main(String[] args) throws Exception { + X509Certificate[] chain = createChain(); + + /* Test 1: Test SimpleValidator + * SimpleValidator doesn't check for unsupported critical + * extensions in the end entity certificate, and leaves that up + * to EndEntityChecker, which should catch such extensions. + */ + KeyStore ks = KeyStore.getInstance("JKS"); + ks.load(null, null); + ks.setCertificateEntry("testca", chain[chain.length - 1]); + + Validator v = Validator.getInstance(Validator.TYPE_SIMPLE, + Validator.VAR_TLS_CLIENT, + KeyStores.getTrustedCerts(ks)); + try { + v.validate(chain); + throw new Exception("Chain should not have validated " + + "successfully."); + } catch (CertificateException ex) { + // EE cert has an unsupported critical extension that is not + // checked by SimpleValidator's extension checks, so this + // failure is expected + } + + /* Test 2: Test PKIXValidator without custom checker + * PKIXValidator accepts PKIXParameters that can contain + * custom PKIXCertPathCheckers, which would be run against + * each cert in the chain, including EE certs. + * Check that if PKIXValidator is not provided a custom + * PKIXCertPathChecker for an unknown critical extension in + * the EE cert, chain validation will fail. + */ + TrustAnchor ta = new TrustAnchor(chain[chain.length - 1], null); + Set tas = new HashSet<>(); + tas.add(ta); + PKIXBuilderParameters params = new PKIXBuilderParameters(tas, null); + params.setDate(new Date(115, 5, 1)); // 2015-05-01 + params.setRevocationEnabled(false); + + v = Validator.getInstance(Validator.TYPE_PKIX, + Validator.VAR_TLS_CLIENT, + params); + try { + v.validate(chain); + throw new Exception("Chain should not have validated " + + "successfully."); + } catch (CertificateException ex) { + // EE cert has an unsupported critical extension and + // PKIXValidator was not provided any custom checker + // for it, so this failure ie expected. + } + + /* Test 3: Test PKIXValidator with custom checker + * Check that PKIXValidator will successfully validate a chain + * containing an EE cert with a critical custom extension, given + * a corresponding PKIXCertPathChecker for the extension. + */ + params = new PKIXBuilderParameters(tas, null); + params.addCertPathChecker(new CustomChecker()); + params.setDate(new Date(115, 5, 1)); // 2015-05-01 + params.setRevocationEnabled(false); + + v = Validator.getInstance(Validator.TYPE_PKIX, + Validator.VAR_TLS_CLIENT, + params); + v.validate(chain); // This should validate successfully + + System.out.println("Tests passed."); + } + + public static X509Certificate[] createChain() throws Exception { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + X509Certificate ee = (X509Certificate) + cf.generateCertificate((new ByteArrayInputStream(EE.getBytes()))); + X509Certificate ca = (X509Certificate) + cf.generateCertificate((new ByteArrayInputStream(CA.getBytes()))); + + X509Certificate[] chain = {ee, ca}; + return chain; + } + + /* + * A custom PKIXCertPathChecker. Looks for a critical extension + * in an end entity certificate with the OID 1.2.3.4. + */ + static class CustomChecker extends PKIXCertPathChecker { + + @Override + public void init(boolean forward) throws CertPathValidatorException { + // nothing to do + } + + @Override + public boolean isForwardCheckingSupported() { + return false; + } + + @Override + public Set getSupportedExtensions() { + Set exts = new HashSet<>(); + exts.add("1.2.3.4"); + return exts; + } + + @Override + public void check(Certificate cert, + Collection unresolvedCritExts) + throws CertPathValidatorException { + X509Certificate currCert = (X509Certificate)cert; + // check that this is an EE cert + if (currCert.getBasicConstraints() == -1) { + if (unresolvedCritExts != null && + !unresolvedCritExts.isEmpty()) { + unresolvedCritExts.remove("1.2.3.4"); + } + } + } + + } +}