mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-26 03:09:41 +01:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2cbcbeeef | ||
|
|
aba2a258bb | ||
|
|
53c9198350 | ||
|
|
e27b2fbf84 | ||
|
|
a5c9a208ed | ||
|
|
86b93a57af | ||
|
|
c838f55dd9 | ||
|
|
8d188ad27f | ||
|
|
d87fc06c41 | ||
|
|
b17c748949 | ||
|
|
03783189d0 | ||
|
|
05fbf8507c | ||
|
|
80de7efe15 | ||
|
|
6d1add0393 | ||
|
|
f57241bcf8 | ||
|
|
3fca5bee90 | ||
|
|
60330c9b3e | ||
|
|
4a16c3b8c8 | ||
|
|
2ece56c057 | ||
|
|
c3a506172b | ||
|
|
c81d4030eb | ||
|
|
32fb930e85 | ||
|
|
0ef1d9a4a9 | ||
|
|
07ee0a2471 | ||
|
|
c4cb87ff06 | ||
|
|
6b36a9227d | ||
|
|
83ca27f8b2 | ||
|
|
c539ca4ddf | ||
|
|
51ec2c610e | ||
|
|
2b8ee942e0 | ||
|
|
9b17148ef4 | ||
|
|
02289f478f | ||
|
|
2f0eb2bba8 | ||
|
|
740bf2b3e5 | ||
|
|
88d7361bd9 | ||
|
|
87c6482c0e | ||
|
|
b2a9372d70 | ||
|
|
d0d8a63e0b | ||
|
|
09c200ccfd | ||
|
|
42a22e0cc4 | ||
|
|
71d54051d2 | ||
|
|
d4fc6bc380 | ||
|
|
1e1f71f907 | ||
|
|
6d26c9353f | ||
|
|
adabf8c677 | ||
|
|
5e0ec47ce9 | ||
|
|
9ec9457d8b | ||
|
|
e1a1b6814d | ||
|
|
944797005c | ||
|
|
507f4d716a | ||
|
|
67c24c9b88 | ||
|
|
2ef4de692d | ||
|
|
f20b2dca0f | ||
|
|
0b9397cf4c | ||
|
|
392cf1c31a | ||
|
|
b269750318 | ||
|
|
0676b50884 | ||
|
|
4df6fbd251 | ||
|
|
006cd74964 |
@@ -96,6 +96,7 @@
|
||||
<li><a href="#specific-build-issues">Specific Build Issues</a></li>
|
||||
<li><a href="#getting-help">Getting Help</a></li>
|
||||
</ul></li>
|
||||
<li><a href="#reproducible-builds">Reproducible Builds</a></li>
|
||||
<li><a href="#hints-and-suggestions-for-advanced-users">Hints and Suggestions for Advanced Users</a><ul>
|
||||
<li><a href="#bash-completion">Bash Completion</a></li>
|
||||
<li><a href="#using-multiple-configurations">Using Multiple Configurations</a></li>
|
||||
@@ -884,6 +885,32 @@ spawn failed</code></pre>
|
||||
<h3 id="getting-help">Getting Help</h3>
|
||||
<p>If none of the suggestions in this document helps you, or if you find what you believe is a bug in the build system, please contact the Build Group by sending a mail to <a href="mailto:build-dev@openjdk.java.net">build-dev@openjdk.java.net</a>. Please include the relevant parts of the configure and/or build log.</p>
|
||||
<p>If you need general help or advice about developing for the JDK, you can also contact the Adoption Group. See the section on <a href="#contributing-to-openjdk">Contributing to OpenJDK</a> for more information.</p>
|
||||
<h2 id="reproducible-builds">Reproducible Builds</h2>
|
||||
<p>Build reproducibility is the property of getting exactly the same bits out when building, every time, independent on who builds the product, or where. This is for many reasons a harder goal than it initially appears, but it is an important goal, for security reasons and others. Please see <a href="https://reproducible-builds.org">Reproducible Builds</a> for more information about the background and reasons for reproducible builds.</p>
|
||||
<p>Currently, it is not possible to build OpenJDK fully reproducibly, but getting there is an ongoing effort. There are some things you can do to minimize non-determinism and make a larger part of the build reproducible:</p>
|
||||
<ul>
|
||||
<li>Turn on build system support for reproducible builds</li>
|
||||
</ul>
|
||||
<p>Add the flag <code>--enable-reproducible-build</code> to your <code>configure</code> command line. This will turn on support for reproducible builds where it could otherwise be lacking.</p>
|
||||
<ul>
|
||||
<li>Do not rely on <code>configure</code>'s default adhoc version strings</li>
|
||||
</ul>
|
||||
<p>Default adhoc version strings OPT segment include user name, source directory and timestamp. You can either override just the OPT segment using <code>--with-version-opt=<any fixed string></code>, or you can specify the entire version string using <code>--with-version-string=<your version></code>.</p>
|
||||
<ul>
|
||||
<li>Specify how the build sets <code>SOURCE_DATE_EPOCH</code></li>
|
||||
</ul>
|
||||
<p>The JDK build system will set the <code>SOURCE_DATE_EPOCH</code> environment variable during building, depending on the value of the <code>--with-source-date</code> option for <code>configure</code>. The default value is <code>updated</code>, which means that <code>SOURCE_DATE_EPOCH</code> will be set to the current time each time you are running <code>make</code>.</p>
|
||||
<p>The <a href="https://reproducible-builds.org/docs/source-date-epoch/"><code>SOURCE_DATE_EPOCH</code> environment variable</a> is an industry standard, that many tools, such as gcc, recognize, and use in place of the current time when generating output.</p>
|
||||
<p>For reproducible builds, you need to set this to a fixed value. You can use the special value <code>version</code> which will use the nominal release date for the current JDK version, or a value describing a date, either an epoch based timestamp as an integer, or a valid ISO-8601 date.</p>
|
||||
<p><strong>Hint:</strong> If your build environment already sets <code>SOURCE_DATE_EPOCH</code>, you can propagate this using <code>--with-source-date=$SOURCE_DATE_EPOCH</code>.</p>
|
||||
<ul>
|
||||
<li>Specify a hotspot build time</li>
|
||||
</ul>
|
||||
<p>Set a fixed hotspot build time. This will be included in the hotspot library (<code>libjvm.so</code> or <code>jvm.dll</code>) and defaults to the current time when building hotspot. Use <code>--with-hotspot-build-time=<any fixed string></code> for reproducible builds. It's a string so you don't need to format it specifically, so e.g. <code>n/a</code> will do. Another solution is to use the <code>SOURCE_DATE_EPOCH</code> variable, e.g. <code>--with-hotspot-build-time=$(date --date=@$SOURCE_DATE_EPOCH)</code>.</p>
|
||||
<ul>
|
||||
<li>Copyright year</li>
|
||||
</ul>
|
||||
<p>The copyright year in some generated text files are normally set to the current year. This can be overridden by <code>--with-copyright-year=<year></code>. For fully reproducible builds, this needs to be set to a fixed value.</p>
|
||||
<h2 id="hints-and-suggestions-for-advanced-users">Hints and Suggestions for Advanced Users</h2>
|
||||
<h3 id="bash-completion">Bash Completion</h3>
|
||||
<p>The <code>configure</code> and <code>make</code> commands tries to play nice with bash command-line completion (using <code><tab></code> or <code><tab><tab></code>). To use this functionality, make sure you enable completion in your <code>~/.bashrc</code> (see instructions for bash in your operating system).</p>
|
||||
|
||||
@@ -1503,6 +1503,68 @@ If you need general help or advice about developing for the JDK, you can also
|
||||
contact the Adoption Group. See the section on [Contributing to OpenJDK](
|
||||
#contributing-to-openjdk) for more information.
|
||||
|
||||
## Reproducible Builds
|
||||
|
||||
Build reproducibility is the property of getting exactly the same bits out when
|
||||
building, every time, independent on who builds the product, or where. This is
|
||||
for many reasons a harder goal than it initially appears, but it is an important
|
||||
goal, for security reasons and others. Please see [Reproducible Builds](
|
||||
https://reproducible-builds.org) for more information about the background and
|
||||
reasons for reproducible builds.
|
||||
|
||||
Currently, it is not possible to build OpenJDK fully reproducibly, but getting
|
||||
there is an ongoing effort. There are some things you can do to minimize
|
||||
non-determinism and make a larger part of the build reproducible:
|
||||
|
||||
* Turn on build system support for reproducible builds
|
||||
|
||||
Add the flag `--enable-reproducible-build` to your `configure` command line.
|
||||
This will turn on support for reproducible builds where it could otherwise be
|
||||
lacking.
|
||||
|
||||
* Do not rely on `configure`'s default adhoc version strings
|
||||
|
||||
Default adhoc version strings OPT segment include user name, source directory
|
||||
and timestamp. You can either override just the OPT segment using
|
||||
`--with-version-opt=<any fixed string>`, or you can specify the entire version
|
||||
string using `--with-version-string=<your version>`.
|
||||
|
||||
* Specify how the build sets `SOURCE_DATE_EPOCH`
|
||||
|
||||
The JDK build system will set the `SOURCE_DATE_EPOCH` environment variable
|
||||
during building, depending on the value of the `--with-source-date` option for
|
||||
`configure`. The default value is `updated`, which means that
|
||||
`SOURCE_DATE_EPOCH` will be set to the current time each time you are running
|
||||
`make`.
|
||||
|
||||
The [`SOURCE_DATE_EPOCH` environment variable](
|
||||
https://reproducible-builds.org/docs/source-date-epoch/) is an industry
|
||||
standard, that many tools, such as gcc, recognize, and use in place of the
|
||||
current time when generating output.
|
||||
|
||||
For reproducible builds, you need to set this to a fixed value. You can use the
|
||||
special value `version` which will use the nominal release date for the current
|
||||
JDK version, or a value describing a date, either an epoch based timestamp as an
|
||||
integer, or a valid ISO-8601 date.
|
||||
|
||||
**Hint:** If your build environment already sets `SOURCE_DATE_EPOCH`, you can
|
||||
propagate this using `--with-source-date=$SOURCE_DATE_EPOCH`.
|
||||
|
||||
* Specify a hotspot build time
|
||||
|
||||
Set a fixed hotspot build time. This will be included in the hotspot library
|
||||
(`libjvm.so` or `jvm.dll`) and defaults to the current time when building
|
||||
hotspot. Use `--with-hotspot-build-time=<any fixed string>` for reproducible
|
||||
builds. It's a string so you don't need to format it specifically, so e.g. `n/a`
|
||||
will do. Another solution is to use the `SOURCE_DATE_EPOCH` variable, e.g.
|
||||
`--with-hotspot-build-time=$(date --date=@$SOURCE_DATE_EPOCH)`.
|
||||
|
||||
* Copyright year
|
||||
|
||||
The copyright year in some generated text files are normally set to the current
|
||||
year. This can be overridden by `--with-copyright-year=<year>`. For fully
|
||||
reproducible builds, this needs to be set to a fixed value.
|
||||
|
||||
## Hints and Suggestions for Advanced Users
|
||||
|
||||
### Bash Completion
|
||||
|
||||
47
jb/project/docker/Dockerfile.aarch64
Normal file
47
jb/project/docker/Dockerfile.aarch64
Normal file
@@ -0,0 +1,47 @@
|
||||
# NOTE: This Dockerfile is meant to be used from the mkdocker_aarch64.sh script.
|
||||
|
||||
# Pull a concrete version of Linux that does NOT recieve updates after it's
|
||||
# been created. This is so that the image is as stable as possible to make
|
||||
# image creation reproducible.
|
||||
# NB: this also means there may be no security-related fixes there, need to
|
||||
# move the version to the next manually.
|
||||
FROM arm64v8/ubuntu:focal-20211006
|
||||
|
||||
# Install the necessary build tools
|
||||
RUN export DEBIAN_FRONTEND=noninteractive \
|
||||
export DEBCONF_NONINTERACTIVE_SEEN=true && \
|
||||
echo 'tzdata tzdata/Areas select Etc' | debconf-set-selections; \
|
||||
echo 'tzdata tzdata/Zones/Etc select UTC' | debconf-set-selections; \
|
||||
apt-get update -qy && \
|
||||
apt-get install -qy \
|
||||
autoconf \
|
||||
build-essential \
|
||||
bzip2 \
|
||||
file \
|
||||
g++-10=10.3.0-1ubuntu1~20.04 \
|
||||
gcc-10=10.3.0-1ubuntu1~20.04 \
|
||||
git \
|
||||
libasound2-dev \
|
||||
libcups2-dev \
|
||||
libfontconfig1-dev \
|
||||
libx11-dev \
|
||||
libxext-dev \
|
||||
libxrandr-dev \
|
||||
libxrender-dev \
|
||||
libxt-dev \
|
||||
libxtst-dev \
|
||||
make \
|
||||
tar \
|
||||
unzip \
|
||||
zip && \
|
||||
update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-10 100 --slave /usr/bin/g++ g++ /usr/bin/g++-10 && \
|
||||
apt-get clean -qy && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
# Set up boot JDK for building
|
||||
COPY boot_jdk.tar.gz /jdk17/
|
||||
RUN cd /jdk17 && tar --strip-components=1 -xzf boot_jdk.tar.gz && rm /jdk17/boot_jdk.tar.gz
|
||||
ENV BOOT_JDK=/jdk17
|
||||
|
||||
RUN git config --global user.email "teamcity@jetbrains.com" && \
|
||||
git config --global user.name "builduser"
|
||||
26
jb/project/docker/mkdocker_aarch64.sh
Executable file
26
jb/project/docker/mkdocker_aarch64.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/bin/bash -x
|
||||
|
||||
# This script creates a Docker image suitable for building AArch64 variant
|
||||
# of the JetBrains Runtime version 17.
|
||||
|
||||
BOOT_JDK_REMOTE_FILE=zulu17.30.15-ca-jdk17.0.1-linux_aarch64.tar.gz
|
||||
BOOT_JDK_SHA=4d9c9116eb0cdd2d7fb220d6d27059f4bf1b7e95cc93d5512bd8ce3791af86c7
|
||||
BOOT_JDK_LOCAL_FILE=boot_jdk.tar.gz
|
||||
|
||||
if [ ! -f $BOOT_JDK_LOCAL_FILE ]; then
|
||||
# Obtain "boot JDK" from outside of the container.
|
||||
wget -nc https://cdn.azul.com/zulu/bin/${BOOT_JDK_REMOTE_FILE} -O $BOOT_JDK_LOCAL_FILE
|
||||
else
|
||||
echo "boot JDK \"$BOOT_JDK_LOCAL_FILE\" present, skipping download"
|
||||
fi
|
||||
|
||||
# Verify that what we've downloaded can be trusted.
|
||||
sha256sum -c - <<EOF
|
||||
$BOOT_JDK_SHA *$BOOT_JDK_LOCAL_FILE
|
||||
EOF
|
||||
|
||||
docker build -t jbr17buildenv -f Dockerfile.aarch64 .
|
||||
|
||||
# NB: the resulting container can (and should) be used without the network
|
||||
# connection (--network none) during build in order to reduce the chance
|
||||
# of build contamination.
|
||||
@@ -6,6 +6,38 @@ do_reset_changes=0
|
||||
do_reset_dcevm=0
|
||||
HEAD_REVISION=0
|
||||
|
||||
OS_NAME=$(uname -s)
|
||||
# Enable reproducible builds
|
||||
TZ=UTC
|
||||
export TZ
|
||||
SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)"
|
||||
export SOURCE_DATE_EPOCH
|
||||
USER=builduser
|
||||
export USER
|
||||
|
||||
case "$OS_NAME" in
|
||||
Linux)
|
||||
COPYRIGHT_YEAR="$(date --utc --date=@$SOURCE_DATE_EPOCH +%Y)"
|
||||
BUILD_TIME="$(date --utc --date=@$SOURCE_DATE_EPOCH +%F)"
|
||||
REPRODUCIBLE_TAR_OPTS="--mtime=@$SOURCE_DATE_EPOCH --owner=0 --group=0 --numeric-owner --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime"
|
||||
;;
|
||||
Darwin)
|
||||
COPYRIGHT_YEAR="$(date -u -r $SOURCE_DATE_EPOCH +%Y)"
|
||||
BUILD_TIME="$(date -u -r $SOURCE_DATE_EPOCH +%F)"
|
||||
TOUCH_TIME="$(date -u -r $SOURCE_DATE_EPOCH +%Y%m%d%H%M.%S)"
|
||||
REPRODUCIBLE_TAR_OPTS="--uid 0 --gid 0 --numeric-owner"
|
||||
;;
|
||||
*)
|
||||
# TODO: Windows
|
||||
;;
|
||||
esac
|
||||
|
||||
REPRODUCIBLE_BUILD_OPTS="--enable-reproducible-build
|
||||
--with-source-date=$SOURCE_DATE_EPOCH
|
||||
--with-hotspot-build-time=$BUILD_TIME
|
||||
--with-copyright-year=$COPYRIGHT_YEAR
|
||||
--with-native-debug-symbols=none"
|
||||
|
||||
function do_exit() {
|
||||
exit_code=$1
|
||||
[ $do_reset_changes -eq 1 ] && git checkout HEAD modules.list src/java.desktop/share/classes/module-info.java
|
||||
|
||||
@@ -24,8 +24,6 @@ source jb/project/tools/common/scripts/common.sh
|
||||
|
||||
JBRSDK_BASE_NAME=jbrsdk-${JBSDK_VERSION}
|
||||
|
||||
[ -z "$bundle_type" ] && (git apply -p0 < jb/project/tools/patches/exclude_jcef_module.patch || exit $?)
|
||||
|
||||
sh configure \
|
||||
--with-debug-level=release \
|
||||
--with-vendor-name="${VENDOR_NAME}" \
|
||||
@@ -35,7 +33,9 @@ sh configure \
|
||||
--with-version-build="${JDK_BUILD_NUMBER}" \
|
||||
--with-version-opt=b${build_number} \
|
||||
--with-boot-jdk=${BOOT_JDK} \
|
||||
--enable-cds=yes || exit $?
|
||||
--enable-cds=yes \
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
|| exit $?
|
||||
make clean CONF=linux-aarch64-server-release || exit $?
|
||||
make images CONF=linux-aarch64-server-release test-image || exit $?
|
||||
|
||||
@@ -54,9 +54,11 @@ echo Creating $JBSDK.tar.gz ...
|
||||
sed 's/JBR/JBRSDK/g' ${BASE_DIR}/${JBRSDK_BUNDLE}/release > release
|
||||
mv release ${BASE_DIR}/${JBRSDK_BUNDLE}/release
|
||||
|
||||
tar -pcf $JBSDK.tar \
|
||||
# NB: --sort=name requires tar1.28
|
||||
tar $REPRODUCIBLE_TAR_OPTS --sort=name -pcf $JBSDK.tar \
|
||||
--exclude=*.debuginfo --exclude=demo --exclude=sample --exclude=man \
|
||||
-C $BASE_DIR ${JBRSDK_BUNDLE} || exit $?
|
||||
touch -c -d @$SOURCE_DATE_EPOCH $JBRSDK.tar
|
||||
gzip $JBSDK.tar || exit $?
|
||||
|
||||
JBR_BUNDLE=jbr
|
||||
@@ -75,10 +77,11 @@ echo Modifying release info ...
|
||||
grep -v \"^JAVA_VERSION\" ${JSDK}/release | grep -v \"^MODULES\" >> ${BASE_DIR}/${JBR_BUNDLE}/release
|
||||
|
||||
echo Creating $JBR.tar.gz ...
|
||||
tar -pcf $JBR.tar -C $BASE_DIR ${JBR_BUNDLE} || exit $?
|
||||
tar $REPRODUCIBLE_TAR_OPTS --sort=name -pcf $JBR.tar -C $BASE_DIR ${JBR_BUNDLE} || exit $?
|
||||
touch -c -d @$SOURCE_DATE_EPOCH $JBR.tar
|
||||
gzip $JBR.tar || exit $?
|
||||
|
||||
JBRSDK_TEST=$JBRSDK_BASE_NAME-linux-test-aarch64-b$build_number
|
||||
echo Creating $JBRSDK_TEST.tar.gz ...
|
||||
tar -pcf $JBRSDK_TEST.tar -C $BASE_DIR --exclude='test/jdk/demos' test || exit $?
|
||||
gzip $JBRSDK_TEST.tar || exit $?
|
||||
gzip $JBRSDK_TEST.tar || exit $?
|
||||
|
||||
@@ -50,7 +50,9 @@ function do_configure {
|
||||
--with-version-build="$JDK_BUILD_NUMBER" \
|
||||
--with-version-opt=b"$build_number" \
|
||||
--with-boot-jdk="$BOOT_JDK" \
|
||||
--enable-cds=yes || do_exit $?
|
||||
--enable-cds=yes \
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
|| do_exit $?
|
||||
}
|
||||
|
||||
function create_image_bundle {
|
||||
@@ -79,8 +81,14 @@ function create_image_bundle {
|
||||
[ -f "$IMAGES_DIR"/"$__arch_name"/lib/jcef_helper ] && chmod a+x "$IMAGES_DIR"/"$__arch_name"/lib/jcef_helper
|
||||
|
||||
echo Creating "$JBR".tar.gz ...
|
||||
tar -pcf "$JBR".tar -C "$IMAGES_DIR" "$__arch_name" || do_exit $?
|
||||
|
||||
(cd "$IMAGES_DIR" &&
|
||||
find "$__arch_name" -print0 | LC_ALL=C sort -z | \
|
||||
tar $REPRODUCIBLE_TAR_OPTS \
|
||||
--no-recursion --null -T - -cf "$JBR".tar) || do_exit $?
|
||||
mv "$IMAGES_DIR"/"$JBR".tar ./"$JBR".tar
|
||||
[ -f "$JBR".tar.gz ] && rm "$JBR.tar.gz"
|
||||
touch -c -d "@$SOURCE_DATE_EPOCH" "$JBR".tar
|
||||
gzip "$JBR".tar || do_exit $?
|
||||
rm -rf "${IMAGES_DIR:?}"/"$__arch_name"
|
||||
}
|
||||
@@ -150,4 +158,4 @@ if [ -z "$bundle_type" ]; then
|
||||
gzip "$JBRSDK_TEST".tar || do_exit $?
|
||||
fi
|
||||
|
||||
do_exit 0
|
||||
do_exit 0
|
||||
|
||||
@@ -47,18 +47,14 @@ BOOT_JDK=${BOOT_JDK:=$(/usr/libexec/java_home -v 16)}
|
||||
|
||||
source jb/project/tools/common/scripts/common.sh
|
||||
|
||||
function copyJNF {
|
||||
__contents_dir=$1
|
||||
mkdir -p ${__contents_dir}/Frameworks
|
||||
cp -Rp Frameworks/JavaNativeFoundation.framework ${__contents_dir}/Frameworks
|
||||
}
|
||||
|
||||
function do_configure {
|
||||
if [[ "${architecture}" == *aarch64* ]]; then
|
||||
sh configure \
|
||||
$WITH_DEBUG_LEVEL \
|
||||
--with-vendor-name="${VENDOR_NAME}" \
|
||||
--with-vendor-version-string="${VENDOR_VERSION_STRING}" \
|
||||
--with-macosx-bundle-name-base=${VENDOR_VERSION_STRING} \
|
||||
--with-macosx-bundle-id-base="com.jetbrains.jbr" \
|
||||
--with-jvm-features=shenandoahgc \
|
||||
--with-version-pre= \
|
||||
--with-version-build="${JDK_BUILD_NUMBER}" \
|
||||
@@ -69,19 +65,25 @@ function do_configure {
|
||||
--enable-cds=no \
|
||||
--with-extra-cflags="-F$(pwd)/Frameworks" \
|
||||
--with-extra-cxxflags="-F$(pwd)/Frameworks" \
|
||||
--with-extra-ldflags="-F$(pwd)/Frameworks" || do_exit $?
|
||||
--with-extra-ldflags="-F$(pwd)/Frameworks" \
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
|| do_exit $?
|
||||
else
|
||||
sh configure \
|
||||
$WITH_DEBUG_LEVEL \
|
||||
--with-vendor-name="$VENDOR_NAME" \
|
||||
--with-vendor-version-string="$VENDOR_VERSION_STRING" \
|
||||
--with-macosx-bundle-name-base=${VENDOR_VERSION_STRING} \
|
||||
--with-macosx-bundle-id-base="com.jetbrains.jbr" \
|
||||
--with-jvm-features=shenandoahgc \
|
||||
--with-version-pre= \
|
||||
--with-version-build="$JDK_BUILD_NUMBER" \
|
||||
--with-version-opt=b"$build_number" \
|
||||
--with-boot-jdk="$BOOT_JDK" \
|
||||
--with-macosx-version-max="${MACOSX_VERSION_MAX:="10.12.00"}" \
|
||||
--enable-cds=yes || do_exit $?
|
||||
--enable-cds=yes \
|
||||
$REPRODUCIBLE_BUILD_OPTS \
|
||||
|| do_exit $?
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -115,16 +117,17 @@ function create_image_bundle {
|
||||
cp -R "$JSDK"/../MacOS "$JRE_CONTENTS"
|
||||
cp "$JSDK"/../Info.plist "$JRE_CONTENTS"
|
||||
|
||||
if [[ "${architecture}" == *aarch64* ]]; then
|
||||
# we can't notarize this library as usual framework (with headers and tbd-file)
|
||||
# but single library notarizes correctly
|
||||
copyJNF $JRE_CONTENTS
|
||||
fi
|
||||
|
||||
[ -n "$bundle_type" ] && (cp -a $JCEF_PATH/Frameworks "$JRE_CONTENTS" || do_exit $?)
|
||||
|
||||
echo Creating "$JBR".tar.gz ...
|
||||
COPYFILE_DISABLE=1 tar -pczf "$JBR".tar.gz --exclude='*.dSYM' --exclude='man' -C "$tmp" "$__arch_name" || do_exit $?
|
||||
# Normalize timestamp
|
||||
find "$tmp"/"$__arch_name" -print0 | xargs -0 touch -c -h -t "$TOUCH_TIME"
|
||||
|
||||
(cd "$tmp" &&
|
||||
find "$__arch_name" -print0 | LC_ALL=C sort -z | \
|
||||
COPYFILE_DISABLE=1 tar $REPRODUCIBLE_TAR_OPTS --no-recursion --null -T - \
|
||||
-czf "$JBR".tar.gz --exclude='*.dSYM' --exclude='man') || do_exit $?
|
||||
mv "$tmp"/"$JBR".tar.gz "$JBR".tar.gz
|
||||
rm -rf "$tmp"
|
||||
}
|
||||
|
||||
@@ -198,4 +201,4 @@ if [ -z "$bundle_type" ]; then
|
||||
COPYFILE_DISABLE=1 tar -pczf "$JBRSDK_TEST".tar.gz -C $IMAGES_DIR --exclude='test/jdk/demos' test || do_exit $?
|
||||
fi
|
||||
|
||||
do_exit 0
|
||||
do_exit 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/bin/bash -x
|
||||
|
||||
APP_DIRECTORY=$1
|
||||
APPL_USER=$2
|
||||
@@ -54,17 +54,15 @@ function altool-upload() {
|
||||
#immediately exit script with an error if a command fails
|
||||
set -euo pipefail
|
||||
|
||||
file="$APP_NAME.zip"
|
||||
#file="$APP_NAME.zip"
|
||||
|
||||
log "Zipping $file..."
|
||||
rm -rf "$file"
|
||||
ditto -c -k --sequesterRsrc --keepParent "$APP_DIRECTORY" "$file"
|
||||
#log "Zipping $file..."
|
||||
#rm -rf "$file"
|
||||
#ditto -c -k --sequesterRsrc --keepParent "$APP_DIRECTORY" "$file"
|
||||
|
||||
log "Notarizing $file..."
|
||||
log "Notarizing $APP_NAME..."
|
||||
rm -rf "altool.init.out" "altool.check.out"
|
||||
altool-upload "$file"
|
||||
|
||||
rm -rf "$file"
|
||||
altool-upload "$APP_NAME"
|
||||
|
||||
notarization_info="$(grep -e "RequestUUID" "altool.init.out" | grep -oE '([0-9a-f-]{36})')"
|
||||
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
#!/bin/bash
|
||||
#!/bin/bash -x
|
||||
|
||||
APP_DIRECTORY=$1
|
||||
JB_CERT=$2
|
||||
APPLICATION_PATH=$1
|
||||
APP_NAME=$2
|
||||
BUNDLE_ID=$3
|
||||
JB_DEVELOPER_CERT=$4
|
||||
JB_INSTALLER_CERT=$5
|
||||
|
||||
if [[ -z "$APP_DIRECTORY" ]] || [[ -z "$JB_CERT" ]]; then
|
||||
if [[ -z "$APPLICATION_PATH" ]] || [[ -z "$JB_DEVELOPER_CERT" ]]; then
|
||||
echo "Usage: $0 AppDirectory CertificateID"
|
||||
exit 1
|
||||
fi
|
||||
if [[ ! -d "$APP_DIRECTORY" ]]; then
|
||||
echo "AppDirectory '$APP_DIRECTORY' does not exist or not a directory"
|
||||
if [[ ! -d "$APPLICATION_PATH" ]]; then
|
||||
echo "AppDirectory '$APPLICATION_PATH' does not exist or not a directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -20,43 +23,30 @@ function log() {
|
||||
set -euo pipefail
|
||||
|
||||
# Cleanup files left from previous sign attempt (if any)
|
||||
find "$APP_DIRECTORY" -name '*.cstemp' -exec rm '{}' \;
|
||||
find "$APPLICATION_PATH" -name '*.cstemp' -exec rm '{}' \;
|
||||
|
||||
log "Signing libraries and executables..."
|
||||
# -perm +111 searches for executables
|
||||
for f in \
|
||||
"Contents/Home/bin" \
|
||||
"Contents/Home/lib"; do
|
||||
if [ -d "$APP_DIRECTORY/$f" ]; then
|
||||
find "$APP_DIRECTORY/$f" \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" -o -perm +111 \) \
|
||||
-exec codesign --timestamp --force \
|
||||
-v -s "$JB_CERT" --options=runtime \
|
||||
"Contents/Home/lib" "Contents/MacOS" \
|
||||
"Contents/Home/Frameworks" \
|
||||
"Contents/Frameworks"; do
|
||||
if [ -d "$APPLICATION_PATH/$f" ]; then
|
||||
find "$APPLICATION_PATH/$f" \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" -o -name "*.tbd" -o -name "*.node" -o -perm +111 \) \
|
||||
-exec codesign --timestamp \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime --force \
|
||||
--entitlements entitlements.xml {} \;
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -d "$APP_DIRECTORY/Contents/Frameworks" ]; then
|
||||
log "Signing frameworks..."
|
||||
for f in $APP_DIRECTORY/Contents/Frameworks/*; do
|
||||
find "$f" \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" \) \
|
||||
-exec codesign --timestamp --force \
|
||||
-v -s "$JB_CERT" \
|
||||
--entitlements entitlements.xml {} \;
|
||||
codesign --timestamp --force \
|
||||
-v -s "$JB_CERT" --options=runtime \
|
||||
--entitlements entitlements.xml "$f"
|
||||
done
|
||||
fi
|
||||
|
||||
log "Signing libraries in jars in $PWD"
|
||||
|
||||
# todo: add set -euo pipefail; into the inner sh -c
|
||||
# `-e` prevents `grep -q && printf` loginc
|
||||
# with `-o pipefail` there's no input for 'while' loop
|
||||
find "$APP_DIRECTORY" -name '*.jar' \
|
||||
-exec sh -c "set -u; unzip -l \"\$0\" | grep -q -e '\.dylib\$' -e '\.jnilib\$' -e '\.so\$' -e '^jattach\$' && printf \"\$0\0\" " {} \; |
|
||||
find "$APPLICATION_PATH" -name '*.jar' \
|
||||
-exec sh -c "set -u; unzip -l \"\$0\" | grep -q -e '\.dylib\$' -e '\.jnilib\$' -e '\.so\$' -e '\.tbd\$' -e '^jattach\$' && printf \"\$0\0\" " {} \; |
|
||||
while IFS= read -r -d $'\0' file; do
|
||||
log "Processing libraries in $file"
|
||||
|
||||
@@ -67,12 +57,13 @@ find "$APP_DIRECTORY" -name '*.jar' \
|
||||
cp "$file" jarfolder && (cd jarfolder && jar xf "$filename" && rm "$filename")
|
||||
|
||||
find jarfolder \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" -o -name "jattach" \) \
|
||||
-exec codesign --timestamp --force \
|
||||
-v -s "$JB_CERT" --options=runtime \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" -o -name "*.tbd" -o -name "jattach" \) \
|
||||
-exec codesign --timestamp \
|
||||
--force \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime \
|
||||
--entitlements entitlements.xml {} \;
|
||||
|
||||
(cd jarfolder; zip -q -r -o ../jar.jar .)
|
||||
(cd jarfolder; zip -q -r -o -0 ../jar.jar .)
|
||||
mv jar.jar "$file"
|
||||
done
|
||||
|
||||
@@ -80,28 +71,41 @@ rm -rf jarfolder jar.jar
|
||||
|
||||
log "Signing other files..."
|
||||
for f in \
|
||||
"Contents/MacOS"; do
|
||||
if [ -d "$APP_DIRECTORY/$f" ]; then
|
||||
find "$APP_DIRECTORY/$f" \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" -o -perm +111 \) \
|
||||
-exec codesign --timestamp --force \
|
||||
-v -s "$JB_CERT" --options=runtime \
|
||||
"Contents/Home/bin"; do
|
||||
if [ -d "$APPLICATION_PATH/$f" ]; then
|
||||
find "$APPLICATION_PATH/$f" \
|
||||
-type f \( -name "*.jnilib" -o -name "*.dylib" -o -name "*.so" -o -name "*.tbd" -o -perm +111 \) \
|
||||
-exec codesign --timestamp \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime --force \
|
||||
--entitlements entitlements.xml {} \;
|
||||
fi
|
||||
done
|
||||
|
||||
#log "Signing executable..."
|
||||
#codesign --timestamp \
|
||||
# -v -s "$JB_CERT" --options=runtime \
|
||||
# -v -s "$JB_DEVELOPER_CERT" --options=runtime \
|
||||
# --force \
|
||||
# --entitlements entitlements.xml "$APP_DIRECTORY/Contents/MacOS/idea"
|
||||
# --entitlements entitlements.xml "$APPLICATION_PATH/Contents/MacOS/idea"
|
||||
|
||||
log "Signing whole app..."
|
||||
codesign --timestamp \
|
||||
-v -s "$JB_CERT" --options=runtime \
|
||||
-v -s "$JB_DEVELOPER_CERT" --options=runtime \
|
||||
--force \
|
||||
--entitlements entitlements.xml "$APP_DIRECTORY"
|
||||
--entitlements entitlements.xml "$APPLICATION_PATH"
|
||||
|
||||
BUILD_NAME=$(echo $APPLICATION_PATH | awk -F"/" '{ print $2 }')
|
||||
|
||||
log "Creating $APP_NAME.pkg..."
|
||||
rm -rf "$APP_NAME.pkg"
|
||||
pkgbuild --identifier $BUNDLE_ID --sign "$JB_INSTALLER_CERT" --root $APPLICATION_PATH \
|
||||
--install-location /Library/Java/JavaVirtualMachines/${BUILD_NAME} ${APP_NAME}.pkg
|
||||
|
||||
#log "Signing whole app..."
|
||||
#codesign --timestamp \
|
||||
# -v -s "$JB_DEVELOPER_CERT" --options=runtime \
|
||||
# --force \
|
||||
# --entitlements entitlements.xml $APP_NAME.pkg
|
||||
|
||||
log "Verifying java is not broken"
|
||||
find "$APP_DIRECTORY" \
|
||||
find "$APPLICATION_PATH" \
|
||||
-type f -name 'java' -perm +111 -exec {} -version \;
|
||||
|
||||
@@ -12,8 +12,9 @@ BACKUP_JMODS=$2.backup
|
||||
USERNAME=$3
|
||||
PASSWORD=$4
|
||||
CODESIGN_STRING=$5
|
||||
NOTARIZE=$6
|
||||
BUNDLE_ID=$7
|
||||
JB_INSTALLER_CERT=$6
|
||||
NOTARIZE=$7
|
||||
BUNDLE_ID=$8
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
@@ -33,7 +34,7 @@ mkdir "$BACKUP_JMODS"
|
||||
log "Unzipping $INPUT_FILE to $EXPLODED ..."
|
||||
tar -xzvf "$INPUT_FILE" --directory $EXPLODED
|
||||
BUILD_NAME="$(ls "$EXPLODED")"
|
||||
sed -i '' s/BNDL/APPL/ $EXPLODED/$BUILD_NAME/Contents/Info.plist
|
||||
#sed -i '' s/BNDL/APPL/ $EXPLODED/$BUILD_NAME/Contents/Info.plist
|
||||
rm -f $EXPLODED/$BUILD_NAME/Contents/CodeResources
|
||||
rm "$INPUT_FILE"
|
||||
if test -d $EXPLODED/$BUILD_NAME/Contents/Home/jmods; then
|
||||
@@ -42,7 +43,9 @@ fi
|
||||
|
||||
log "$INPUT_FILE extracted and removed"
|
||||
|
||||
APPLICATION_PATH="$EXPLODED/$BUILD_NAME"
|
||||
APP_NAME=$(echo ${INPUT_FILE} | awk -F".tar" '{ print $1 }')
|
||||
APPLICATION_PATH=$(sed "s/osx-//" <<< "$EXPLODED/$APP_NAME")
|
||||
mv $EXPLODED/$BUILD_NAME $APPLICATION_PATH
|
||||
|
||||
find "$APPLICATION_PATH/Contents/Home/bin" \
|
||||
-maxdepth 1 -type f -name '*.jnilib' -print0 |
|
||||
@@ -79,7 +82,7 @@ limit=3
|
||||
set +e
|
||||
while [[ $attempt -le $limit ]]; do
|
||||
log "Signing (attempt $attempt) $APPLICATION_PATH ..."
|
||||
./sign.sh "$APPLICATION_PATH" "$CODESIGN_STRING"
|
||||
./sign.sh "$APPLICATION_PATH" "$APP_NAME" "$BUNDLE_ID" "$CODESIGN_STRING" "$JB_INSTALLER_CERT"
|
||||
ec=$?
|
||||
if [[ $ec -ne 0 ]]; then
|
||||
((attempt += 1))
|
||||
@@ -92,6 +95,7 @@ while [[ $attempt -le $limit ]]; do
|
||||
log "Signing done"
|
||||
codesign -v "$APPLICATION_PATH" -vvvvv
|
||||
log "Check sign done"
|
||||
spctl -a -v $APPLICATION_PATH
|
||||
((attempt += limit))
|
||||
fi
|
||||
done
|
||||
@@ -102,13 +106,12 @@ if [ "$NOTARIZE" = "yes" ]; then
|
||||
log "Notarizing..."
|
||||
# shellcheck disable=SC1090
|
||||
source "$HOME/.notarize_token"
|
||||
APP_NAME=$(echo ${INPUT_FILE} | awk -F"." '{ print $1 }')
|
||||
# Since notarization tool uses same file for upload token we have to trick it into using different folders, hence fake root
|
||||
# Also it leaves copy of zip file in TMPDIR, so notarize.sh overrides it and uses FAKE_ROOT as location for temp TMPDIR
|
||||
FAKE_ROOT="$(pwd)/fake-root"
|
||||
mkdir -p "$FAKE_ROOT"
|
||||
echo "Notarization will use fake root: $FAKE_ROOT"
|
||||
./notarize.sh "$APPLICATION_PATH" "$APPLE_USERNAME" "$APPLE_PASSWORD" "$APP_NAME" "$BUNDLE_ID" "$FAKE_ROOT"
|
||||
./notarize.sh "$APPLICATION_PATH" "$APPLE_USERNAME" "$APPLE_PASSWORD" "$APP_NAME.pkg" "$BUNDLE_ID" "$FAKE_ROOT"
|
||||
rm -rf "$FAKE_ROOT"
|
||||
|
||||
set +e
|
||||
@@ -124,10 +127,11 @@ log "Zipping $BUILD_NAME to $INPUT_FILE ..."
|
||||
#cd "$EXPLODED"
|
||||
#ditto -c -k --sequesterRsrc --keepParent "$BUILD_NAME" "../$INPUT_FILE"
|
||||
if test -d $BACKUP_JMODS/jmods; then
|
||||
mv $BACKUP_JMODS/jmods $EXPLODED/$BUILD_NAME/Contents/Home
|
||||
mv $BACKUP_JMODS/jmods $APPLICATION_PATH/Contents/Home
|
||||
fi
|
||||
mv $APPLICATION_PATH $EXPLODED/$BUILD_NAME
|
||||
|
||||
tar -pczvf $INPUT_FILE --exclude='*.dSYM' --exclude='man' -C $EXPLODED $BUILD_NAME
|
||||
tar -pczvf $INPUT_FILE --exclude='man' -C $EXPLODED $BUILD_NAME
|
||||
log "Finished zipping"
|
||||
)
|
||||
rm -rf "$EXPLODED"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2016, 2021, 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
|
||||
@@ -88,7 +88,10 @@ $(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXECUTABLE_SUFFIX) $(CLASSLIST
|
||||
$(CAT) $(LINK_OPT_DIR)/stderr $(JLI_TRACE_FILE) ; \
|
||||
exit $$exitcode \
|
||||
)
|
||||
$(GREP) -v HelloClasslist $@.raw.2 > $@
|
||||
$(GREP) -v HelloClasslist $@.raw.2 > $@.raw.3
|
||||
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java \
|
||||
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
||||
build.tools.classlist.SortClasslist $@.raw.3 > $@
|
||||
|
||||
# The jli trace is created by the same recipe as classlist. By declaring these
|
||||
# dependencies, make will correctly rebuild both jli trace and classlist
|
||||
|
||||
@@ -324,7 +324,7 @@ $(eval $(call SetupTarget, vscode-project-ccls, \
|
||||
# aren't built until after libjava and libjvm are available to link to.
|
||||
$(eval $(call SetupTarget, demos-jdk, \
|
||||
MAKEFILE := CompileDemos, \
|
||||
DEPS := java.base-libs exploded-image, \
|
||||
DEPS := java.base-libs exploded-image buildtools-jdk, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupTarget, test-image-demos-jdk, \
|
||||
@@ -383,12 +383,12 @@ bootcycle-images:
|
||||
|
||||
$(eval $(call SetupTarget, zip-security, \
|
||||
MAKEFILE := ZipSecurity, \
|
||||
DEPS := java.base-java java.security.jgss-java java.security.jgss-libs, \
|
||||
DEPS := buildtools-jdk java.base-java java.security.jgss-java java.security.jgss-libs, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupTarget, zip-source, \
|
||||
MAKEFILE := ZipSource, \
|
||||
DEPS := gensrc, \
|
||||
DEPS := buildtools-jdk gensrc, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupTarget, jrtfs-jar, \
|
||||
@@ -508,13 +508,13 @@ $(eval $(call SetupTarget, docs-jdk-index, \
|
||||
$(eval $(call SetupTarget, docs-zip, \
|
||||
MAKEFILE := Docs, \
|
||||
TARGET := docs-zip, \
|
||||
DEPS := docs-jdk, \
|
||||
DEPS := docs-jdk buildtools-jdk, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupTarget, docs-specs-zip, \
|
||||
MAKEFILE := Docs, \
|
||||
TARGET := docs-specs-zip, \
|
||||
DEPS := docs-jdk-specs, \
|
||||
DEPS := docs-jdk-specs buildtools-jdk, \
|
||||
))
|
||||
|
||||
$(eval $(call SetupTarget, update-build-docs, \
|
||||
|
||||
@@ -80,6 +80,8 @@ TOOL_GENERATECACERTS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_class
|
||||
TOOL_GENERATEEMOJIDATA = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
|
||||
build.tools.generateemojidata.GenerateEmojiData
|
||||
|
||||
TOOL_MAKEZIPREPRODUCIBLE = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
|
||||
build.tools.makezipreproducible.MakeZipReproducible
|
||||
|
||||
# TODO: There are references to the jdwpgen.jar in jdk/make/netbeans/jdwpgen/build.xml
|
||||
# and nbproject/project.properties in the same dir. Needs to be looked at.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2021, 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
|
||||
@@ -94,11 +94,6 @@ AC_DEFUN_ONCE([BASIC_SETUP_PATHS],
|
||||
|
||||
# Locate the directory of this script.
|
||||
AUTOCONF_DIR=$TOPDIR/make/autoconf
|
||||
|
||||
# Setup username (for use in adhoc version strings etc)
|
||||
# Outer [ ] to quote m4.
|
||||
[ USERNAME=`$ECHO "$USER" | $TR -d -c '[a-z][A-Z][0-9]'` ]
|
||||
AC_SUBST(USERNAME)
|
||||
])
|
||||
|
||||
###############################################################################
|
||||
|
||||
@@ -356,6 +356,14 @@ AC_DEFUN_ONCE([BASIC_SETUP_COMPLEX_TOOLS],
|
||||
fi
|
||||
AC_SUBST(IS_GNU_TIME)
|
||||
|
||||
# Check if it's GNU date
|
||||
check_date=`$DATE --version 2>&1 | $GREP GNU`
|
||||
if test "x$check_date" != x; then
|
||||
IS_GNU_DATE=yes
|
||||
else
|
||||
IS_GNU_DATE=no
|
||||
fi
|
||||
|
||||
if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then
|
||||
UTIL_REQUIRE_PROGS(DSYMUTIL, dsymutil)
|
||||
UTIL_REQUIRE_PROGS(MIG, mig)
|
||||
|
||||
@@ -199,6 +199,12 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_JDK_OPTIONS],
|
||||
AC_MSG_ERROR([Copyright year must have a value])
|
||||
elif test "x$with_copyright_year" != x; then
|
||||
COPYRIGHT_YEAR="$with_copyright_year"
|
||||
elif test "x$SOURCE_DATE_EPOCH" != x; then
|
||||
if test "x$IS_GNU_DATE" = xyes; then
|
||||
COPYRIGHT_YEAR=`date --date=@$SOURCE_DATE_EPOCH +%Y`
|
||||
else
|
||||
COPYRIGHT_YEAR=`date -j -f %s $SOURCE_DATE_EPOCH +%Y`
|
||||
fi
|
||||
else
|
||||
COPYRIGHT_YEAR=`$DATE +'%Y'`
|
||||
fi
|
||||
@@ -735,7 +741,7 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_REPRODUCIBLE_BUILD],
|
||||
if test "x$OPENJDK_BUILD_OS" = xwindows && \
|
||||
test "x$ALLOW_ABSOLUTE_PATHS_IN_OUTPUT" = xfalse && \
|
||||
test "x$ENABLE_REPRODUCIBLE_BUILD" = xfalse; then
|
||||
AC_MSG_NOTICE([On Windows it is not possible to combine --disable-reproducible-builds])
|
||||
AC_MSG_NOTICE([On Windows it is not possible to combine --disable-reproducible-build])
|
||||
AC_MSG_NOTICE([with --disable-absolute-paths-in-output.])
|
||||
AC_MSG_ERROR([Cannot continue])
|
||||
fi
|
||||
|
||||
@@ -69,6 +69,17 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
|
||||
AC_SUBST(JDK_RC_PLATFORM_NAME)
|
||||
AC_SUBST(HOTSPOT_VM_DISTRO)
|
||||
|
||||
# Setup username (for use in adhoc version strings etc)
|
||||
AC_ARG_WITH([build-user], [AS_HELP_STRING([--with-build-user],
|
||||
[build username to use in version strings])])
|
||||
if test "x$with_build_user" != x; then
|
||||
USERNAME="$with_build_user"
|
||||
else
|
||||
# Outer [ ] to quote m4.
|
||||
[ USERNAME=`$ECHO "$USER" | $TR -d -c '[a-z][A-Z][0-9]'` ]
|
||||
fi
|
||||
AC_SUBST(USERNAME)
|
||||
|
||||
# Set the JDK RC name
|
||||
AC_ARG_WITH(jdk-rc-name, [AS_HELP_STRING([--with-jdk-rc-name],
|
||||
[Set JDK RC name. This is used for FileDescription and ProductName properties
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@@ -26,6 +26,9 @@
|
||||
ifndef _ZIP_ARCHIVE_GMK
|
||||
_ZIP_ARCHIVE_GMK := 1
|
||||
|
||||
# Depends on build tools for MakeZipReproducible
|
||||
include ../ToolsJdk.gmk
|
||||
|
||||
ifeq (,$(_MAKEBASE_GMK))
|
||||
$(error You must include MakeBase.gmk prior to including ZipArchive.gmk)
|
||||
endif
|
||||
@@ -51,6 +54,8 @@ endif
|
||||
# FOLLOW_SYMLINKS - Set to explicitly follow symlinks. Affects performance of
|
||||
# finding files.
|
||||
# ZIP_OPTIONS extra options to pass to zip
|
||||
# REPRODUCIBLE override ENABLE_REPRODUCIBLE_BUILD (to make zip reproducible or not)
|
||||
|
||||
SetupZipArchive = $(NamedParamsMacroTemplate)
|
||||
define SetupZipArchiveBody
|
||||
|
||||
@@ -124,6 +129,10 @@ define SetupZipArchiveBody
|
||||
) \
|
||||
)
|
||||
|
||||
ifeq ($$($1_REPRODUCIBLE), )
|
||||
$1_REPRODUCIBLE := $$(ENABLE_REPRODUCIBLE_BUILD)
|
||||
endif
|
||||
|
||||
# Use a slightly shorter name for logging, but with enough path to identify this zip.
|
||||
$1_NAME:=$$(subst $$(OUTPUTDIR)/,,$$($1_ZIP))
|
||||
|
||||
@@ -134,6 +143,8 @@ define SetupZipArchiveBody
|
||||
# dir is very small.
|
||||
# If zip has nothing to do, it returns 12 and would fail the build. Check for 12
|
||||
# and only fail if it's not.
|
||||
# For reproducible builds set the zip access & modify times to SOURCE_DATE_EPOCH
|
||||
# by using a ziptmp folder to generate final zip from using MakeZipReproducible.
|
||||
$$($1_ZIP) : $$($1_ALL_SRCS) $$($1_EXTRA_DEPS)
|
||||
$$(call LogWarn, Updating $$($1_NAME))
|
||||
$$(call MakeTargetDir)
|
||||
@@ -163,7 +174,18 @@ define SetupZipArchiveBody
|
||||
$$($1_ZIP_EXCLUDES_$$s) \
|
||||
|| test "$$$$?" = "12" \
|
||||
))$$(NEWLINE) \
|
||||
) true \
|
||||
) true
|
||||
ifeq ($$($1_REPRODUCIBLE), true)
|
||||
$$(call ExecuteWithLog, \
|
||||
$$(SUPPORT_OUTPUTDIR)/makezipreproducible/$$(patsubst $$(OUTPUTDIR)/%,%, $$@), \
|
||||
($(RM) $$(SUPPORT_OUTPUTDIR)/ziptmp/$1/tmp.zip && \
|
||||
$(MKDIR) -p $$(SUPPORT_OUTPUTDIR)/ziptmp/$1 && \
|
||||
$(TOOL_MAKEZIPREPRODUCIBLE) -f $$(SUPPORT_OUTPUTDIR)/ziptmp/$1/tmp.zip \
|
||||
-t $(SOURCE_DATE_EPOCH) $$@ && \
|
||||
$(RM) $$@ && \
|
||||
$(MV) $$(SUPPORT_OUTPUTDIR)/ziptmp/$1/tmp.zip $$@ \
|
||||
))
|
||||
endif
|
||||
$(TOUCH) $$@
|
||||
|
||||
# Add zip to target list
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This application is meant to be run to create a classlist file representing
|
||||
* common use.
|
||||
*
|
||||
* The classlist is produced by adding -XX:DumpLoadedClassList=classlist
|
||||
*/
|
||||
package build.tools.classlist;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* The classlist generated by build.tools.classlist.HelloClasslist
|
||||
* may have non-deterministic contents, affected by Java thread execution order.
|
||||
* SortClasslist sorts the file to make the JDK image's contents more deterministic.
|
||||
*/
|
||||
public class SortClasslist {
|
||||
public static void main(String args[]) throws FileNotFoundException {
|
||||
ArrayList<String> classes = new ArrayList<>();
|
||||
ArrayList<String> lambdas = new ArrayList<>();
|
||||
|
||||
FileInputStream fis = new FileInputStream(args[0]);
|
||||
Scanner scanner = new Scanner(fis);
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
if (line.startsWith("#")) {
|
||||
// Comments -- print them first without sorting. These appear only at the top
|
||||
// of the file.
|
||||
System.out.println(line);
|
||||
} else if (line.startsWith("@")) {
|
||||
// @lambda-form-invoker, @lambda-proxy, etc.
|
||||
lambdas.add(line);
|
||||
} else {
|
||||
// We should find a pattern like this:
|
||||
//
|
||||
// <beginning of line>java/lang/Object<end of line>
|
||||
final String className = line;
|
||||
classes.add(className);
|
||||
}
|
||||
}
|
||||
|
||||
Collections.sort(classes);
|
||||
Collections.sort(lambdas);
|
||||
|
||||
for (String s : classes) {
|
||||
System.out.println(s);
|
||||
}
|
||||
for (String s : lambdas) {
|
||||
System.out.println(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,6 +114,7 @@ public class CLDRConverter {
|
||||
ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT);
|
||||
|
||||
private static Set<String> AVAILABLE_TZIDS;
|
||||
static int copyrightYear;
|
||||
private static String zoneNameTempFile;
|
||||
private static String tzDataDir;
|
||||
private static final Map<String, String> canonicalTZMap = new HashMap<>();
|
||||
@@ -217,6 +218,10 @@ public class CLDRConverter {
|
||||
verbose = true;
|
||||
break;
|
||||
|
||||
case "-year":
|
||||
copyrightYear = Integer.parseInt(args[++i]);
|
||||
break;
|
||||
|
||||
case "-zntempfile":
|
||||
zoneNameTempFile = args[++i];
|
||||
break;
|
||||
@@ -235,7 +240,7 @@ public class CLDRConverter {
|
||||
}
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
severe("unknown or imcomplete arg(s): " + currentArg);
|
||||
severe("unknown or incomplete arg(s): " + currentArg);
|
||||
usage();
|
||||
System.exit(1);
|
||||
}
|
||||
@@ -260,6 +265,10 @@ public class CLDRConverter {
|
||||
setupBaseLocales("en-US");
|
||||
}
|
||||
|
||||
if (copyrightYear == 0) {
|
||||
copyrightYear = ZonedDateTime.now(ZoneId.of("America/Los_Angeles")).getYear();
|
||||
}
|
||||
|
||||
bundleGenerator = new ResourceBundleGenerator();
|
||||
|
||||
// Parse data independent of locales
|
||||
@@ -292,6 +301,7 @@ public class CLDRConverter {
|
||||
+ "\t-basemodule generates bundles that go into java.base module%n"
|
||||
+ "\t-baselocales loc(,loc)* locales that go into the base module%n"
|
||||
+ "\t-o dir output directory (default: ./build/gensrc)%n"
|
||||
+ "\t-year year copyright year in output%n"
|
||||
+ "\t-zntempfile template file for java.time.format.ZoneName.java%n"
|
||||
+ "\t-tzdatadir tzdata directory for java.time.format.ZoneName.java%n"
|
||||
+ "\t-utf8 use UTF-8 rather than \\uxxxx (for debug)%n");
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
package build.tools.cldrconverter;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
@@ -131,8 +132,7 @@ class CopyrightHeaders {
|
||||
" * questions.\n" +
|
||||
" */\n";
|
||||
|
||||
static String getOracleCopyright() {
|
||||
int year = getYear();
|
||||
static String getOracleCopyright(int year) {
|
||||
return String.format(year > 2012 ? ORACLE_AFTER2012 : ORACLE2012, year);
|
||||
}
|
||||
|
||||
@@ -140,16 +140,10 @@ class CopyrightHeaders {
|
||||
return UNICODE;
|
||||
}
|
||||
|
||||
static String getOpenJDKCopyright() {
|
||||
int year = getYear();
|
||||
static String getOpenJDKCopyright(int year) {
|
||||
return String.format(year > 2012 ? OPENJDK_AFTER2012 : OPENJDK2012, year);
|
||||
}
|
||||
|
||||
private static int getYear() {
|
||||
return new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles"),
|
||||
Locale.US).get(Calendar.YEAR);
|
||||
}
|
||||
|
||||
// no instantiation
|
||||
private CopyrightHeaders() {
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ class ResourceBundleGenerator implements BundleGenerator {
|
||||
|
||||
try (PrintWriter out = new PrintWriter(file, encoding)) {
|
||||
// Output copyright headers
|
||||
out.println(CopyrightHeaders.getOpenJDKCopyright());
|
||||
out.println(CopyrightHeaders.getOpenJDKCopyright(CLDRConverter.copyrightYear));
|
||||
out.println(CopyrightHeaders.getUnicodeCopyright());
|
||||
|
||||
if (useJava) {
|
||||
@@ -266,7 +266,7 @@ class ResourceBundleGenerator implements BundleGenerator {
|
||||
CLDRConverter.info("Generating file " + file);
|
||||
|
||||
try (PrintWriter out = new PrintWriter(file, "us-ascii")) {
|
||||
out.printf(CopyrightHeaders.getOpenJDKCopyright());
|
||||
out.printf(CopyrightHeaders.getOpenJDKCopyright(CLDRConverter.copyrightYear));
|
||||
|
||||
out.printf((CLDRConverter.isBaseModule ? "package sun.util.cldr;\n\n" :
|
||||
"package sun.util.resources.cldr.provider;\n\n")
|
||||
|
||||
@@ -30,13 +30,15 @@ import java.io.IOException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -52,17 +54,19 @@ import java.util.stream.Collectors;
|
||||
public class EquivMapsGenerator {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (args.length != 2) {
|
||||
if (args.length != 3) {
|
||||
System.err.println("Usage: java EquivMapsGenerator"
|
||||
+ " language-subtag-registry.txt LocaleEquivalentMaps.java");
|
||||
+ " language-subtag-registry.txt LocaleEquivalentMaps.java copyrightYear");
|
||||
System.exit(1);
|
||||
}
|
||||
copyrightYear = Integer.parseInt(args[2]);
|
||||
readLSRfile(args[0]);
|
||||
generateEquivalentMap();
|
||||
generateSourceCode(args[1]);
|
||||
}
|
||||
|
||||
private static String LSRrevisionDate;
|
||||
private static int copyrightYear;
|
||||
private static Map<String, StringBuilder> initialLanguageMap =
|
||||
new TreeMap<>();
|
||||
private static Map<String, StringBuilder> initialRegionVariantMap =
|
||||
@@ -246,9 +250,7 @@ public class EquivMapsGenerator {
|
||||
+ "}";
|
||||
|
||||
private static String getOpenJDKCopyright() {
|
||||
int year = ZonedDateTime.now(ZoneId
|
||||
.of("America/Los_Angeles")).getYear();
|
||||
return String.format(Locale.US, COPYRIGHT, year);
|
||||
return String.format(Locale.US, COPYRIGHT, copyrightYear);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package build.tools.makezipreproducible;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.channels.Channels;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.*;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipException;
|
||||
import java.util.zip.ZipFile;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
/**
|
||||
* Generate a zip file in a "reproducible" manner from the input zip file.
|
||||
* Standard zip tools rely on OS file list querying whose ordering can vary
|
||||
* by platform architecture, this class ensures the zip entries are ordered
|
||||
* and also supports SOURCE_DATE_EPOCH timestamps.
|
||||
*/
|
||||
public class MakeZipReproducible {
|
||||
String input_file = null;
|
||||
String fname = null;
|
||||
String zname = "";
|
||||
long timestamp = -1L;
|
||||
boolean verbose = false;
|
||||
|
||||
// Keep a sorted Set of ZipEntrys to be processed, so that the zip is reproducible
|
||||
SortedMap<String, ZipEntry> entries = new TreeMap<String, ZipEntry>();
|
||||
|
||||
private boolean ok;
|
||||
|
||||
public MakeZipReproducible() {
|
||||
}
|
||||
|
||||
public synchronized boolean run(String args[]) {
|
||||
ok = true;
|
||||
if (!parseArgs(args)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
zname = fname.replace(File.separatorChar, '/');
|
||||
if (zname.startsWith("./")) {
|
||||
zname = zname.substring(2);
|
||||
}
|
||||
|
||||
if (verbose) System.out.println("Input zip file: " + input_file);
|
||||
|
||||
File inFile = new File(input_file);
|
||||
if (!inFile.exists()) {
|
||||
error("Input zip file does not exist");
|
||||
ok = false;
|
||||
} else {
|
||||
File zipFile = new File(fname);
|
||||
// Check archive to create does not exist
|
||||
if (!zipFile.exists()) {
|
||||
// Process input ZipEntries
|
||||
ok = processInputEntries(inFile);
|
||||
if (ok) {
|
||||
try (FileOutputStream out = new FileOutputStream(fname)) {
|
||||
ok = create(inFile, new BufferedOutputStream(out, 4096));
|
||||
}
|
||||
} else {
|
||||
}
|
||||
} else {
|
||||
error("Target zip file "+fname+" already exists.");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
fatalError(e);
|
||||
ok = false;
|
||||
} catch (Error ee) {
|
||||
ee.printStackTrace();
|
||||
ok = false;
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
ok = false;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
boolean parseArgs(String args[]) {
|
||||
try {
|
||||
boolean parsingIncludes = false;
|
||||
boolean parsingExcludes = false;
|
||||
int count = 0;
|
||||
while(count < args.length) {
|
||||
if (args[count].startsWith("-")) {
|
||||
String flag = args[count].substring(1);
|
||||
switch (flag.charAt(0)) {
|
||||
case 'f':
|
||||
fname = args[++count];
|
||||
break;
|
||||
case 't':
|
||||
// SOURCE_DATE_EPOCH timestamp specified
|
||||
timestamp = Long.parseLong(args[++count]) * 1000;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
break;
|
||||
default:
|
||||
error(String.format("Illegal option -%s", String.valueOf(flag.charAt(0))));
|
||||
usageError();
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// input zip file
|
||||
if (input_file != null) {
|
||||
error("Input zip file already specified");
|
||||
usageError();
|
||||
return false;
|
||||
}
|
||||
input_file = args[count];
|
||||
}
|
||||
count++;
|
||||
}
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
usageError();
|
||||
return false;
|
||||
} catch (NumberFormatException e) {
|
||||
usageError();
|
||||
return false;
|
||||
}
|
||||
if (fname == null) {
|
||||
error("-f <outputArchiveName> must be specified");
|
||||
usageError();
|
||||
return false;
|
||||
}
|
||||
// If no files specified then default to current directory
|
||||
if (input_file == null) {
|
||||
error("No input zip file specified");
|
||||
usageError();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Process input zip file and add to sorted entries set
|
||||
boolean processInputEntries(File inFile) throws IOException {
|
||||
ZipFile zipFile = new ZipFile(inFile);
|
||||
zipFile.stream().forEach(entry -> entries.put(entry.getName(), entry));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Create new zip from entries
|
||||
boolean create(File inFile, OutputStream out) throws IOException
|
||||
{
|
||||
try (ZipFile zipFile = new ZipFile(inFile);
|
||||
ZipOutputStream zos = new ZipOutputStream(out)) {
|
||||
for (Map.Entry<String, ZipEntry> entry : entries.entrySet()) {
|
||||
ZipEntry zipEntry = entry.getValue();
|
||||
if (zipEntry.getSize() > 0) {
|
||||
try (InputStream eis = zipFile.getInputStream(zipEntry)) {
|
||||
addEntry(zos, zipEntry, eis);
|
||||
}
|
||||
} else {
|
||||
addEntry(zos, zipEntry, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add Entry and data to Zip
|
||||
void addEntry(ZipOutputStream zos, ZipEntry entry, InputStream entryInputStream) throws IOException {
|
||||
if (verbose) {
|
||||
System.out.println("Adding: "+entry.getName());
|
||||
}
|
||||
|
||||
// Set to specified timestamp if set otherwise leave as original lastModified time
|
||||
if (timestamp != -1L) {
|
||||
entry.setTime(timestamp);
|
||||
}
|
||||
|
||||
zos.putNextEntry(entry);
|
||||
if (entry.getSize() > 0 && entryInputStream != null) {
|
||||
entryInputStream.transferTo(zos);
|
||||
}
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
void usageError() {
|
||||
error(
|
||||
"Usage: MakeZipReproducible [-v] [-t <SOURCE_DATE_EPOCH>] -f <output_zip_file> <input_zip_file>\n" +
|
||||
"Options:\n" +
|
||||
" -v verbose output\n" +
|
||||
" -f specify archive file name to create\n" +
|
||||
" -t specific SOURCE_DATE_EPOCH value to use for timestamps\n" +
|
||||
" input_zip_file re-written as a reproducible zip output_zip_file.\n");
|
||||
}
|
||||
|
||||
void fatalError(Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
protected void error(String s) {
|
||||
System.err.println(s);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
MakeZipReproducible z = new MakeZipReproducible();
|
||||
System.exit(z.run(args) ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \
|
||||
-baselocales "en-US" \
|
||||
-o $(GENSRC_DIR) \
|
||||
-basemodule \
|
||||
-year $(COPYRIGHT_YEAR) \
|
||||
-zntempfile $(ZONENAME_TEMPLATE) \
|
||||
-tzdatadir $(TZ_DATA_DIR))
|
||||
$(TOUCH) $@
|
||||
@@ -99,7 +100,7 @@ GENSRC_LSREQUIVMAPS := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/util/locale/Loc
|
||||
|
||||
$(GENSRC_LSREQUIVMAPS): $(TOPDIR)/make/data/lsrdata/language-subtag-registry.txt $(BUILD_TOOLS_JDK)
|
||||
$(call MakeDir, $(@D))
|
||||
$(TOOL_GENERATELSREQUIVMAPS) $< $@
|
||||
$(TOOL_GENERATELSREQUIVMAPS) $< $@ $(COPYRIGHT_YEAR)
|
||||
|
||||
TARGETS += $(GENSRC_LSREQUIVMAPS)
|
||||
|
||||
|
||||
@@ -72,7 +72,9 @@ $(JDK_JAVADOC_DIR)/_element_lists.marker: \
|
||||
$(MODULE_INFOS)
|
||||
$(call MakeTargetDir)
|
||||
$(call LogInfo, Creating javadoc element lists)
|
||||
$(RM) -r $(ELEMENT_LISTS_DIR)
|
||||
$(RM) $(ELEMENT_LISTS_DIR)/element-list-{$(call CommaList, \
|
||||
$(call sequence, $(GENERATE_SYMBOLS_FROM_JDK_VERSION), \
|
||||
$(JDK_SOURCE_TARGET_VERSION)))}.txt
|
||||
# Generate element-list files for JDK 11 to current-1
|
||||
$(call ExecuteWithLog, $@_historic, \
|
||||
$(JAVA_SMALL) $(INTERIM_LANGTOOLS_ARGS) \
|
||||
|
||||
@@ -46,6 +46,7 @@ $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \
|
||||
$(call ExecuteWithLog, $@, \
|
||||
$(TOOL_CLDRCONVERTER) -base $(CLDR_DATA_DIR) \
|
||||
-baselocales "en-US" \
|
||||
-year $(COPYRIGHT_YEAR) \
|
||||
-o $(GENSRC_DIR))
|
||||
$(TOUCH) $@
|
||||
|
||||
|
||||
@@ -356,8 +356,8 @@ compare_general_files() {
|
||||
"
|
||||
$CAT $OTHER_DIR/$f | eval "$SVG_FILTER" > $OTHER_FILE
|
||||
$CAT $THIS_DIR/$f | eval "$SVG_FILTER" > $THIS_FILE
|
||||
elif [[ "$f" = *"/lib/classlist" ]] || [ "$SUFFIX" = "jar_contents" ]; then
|
||||
# The classlist files may have some lines in random order
|
||||
elif [ "$SUFFIX" = "jar_contents" ]; then
|
||||
# The jar_contents files may have some lines in random order
|
||||
OTHER_FILE=$WORK_DIR/$f.other
|
||||
THIS_FILE=$WORK_DIR/$f.this
|
||||
$MKDIR -p $(dirname $OTHER_FILE) $(dirname $THIS_FILE)
|
||||
|
||||
@@ -1885,7 +1885,11 @@ int os::fork_and_exec(const char* cmd, bool prefer_vfork) {
|
||||
// Use always vfork on AIX, since its safe and helps with analyzing OOM situations.
|
||||
// Otherwise leave it up to the caller.
|
||||
AIX_ONLY(prefer_vfork = true;)
|
||||
#ifdef __APPLE__
|
||||
pid = ::fork();
|
||||
#else
|
||||
pid = prefer_vfork ? ::vfork() : ::fork();
|
||||
#endif
|
||||
|
||||
if (pid < 0) {
|
||||
// fork failed
|
||||
|
||||
@@ -113,10 +113,12 @@ class JfrNetworkInterfaceName : public JfrSerializer {
|
||||
void serialize(JfrCheckpointWriter& writer) {} // we write each constant lazily
|
||||
|
||||
void on_rotation() {
|
||||
for (int i = 0; i < _interfaces->length(); ++i) {
|
||||
const InterfaceEntry& entry = _interfaces->at(i);
|
||||
if (entry.written) {
|
||||
entry.written = false;
|
||||
if (_interfaces != NULL) {
|
||||
for (int i = 0; i < _interfaces->length(); ++i) {
|
||||
const InterfaceEntry &entry = _interfaces->at(i);
|
||||
if (entry.written) {
|
||||
entry.written = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,7 +327,7 @@ public class ModuleDescriptor
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = name.hashCode() * 43 + mods.hashCode();
|
||||
int hash = name.hashCode() * 43 + modsHashCode(mods);
|
||||
if (compiledVersion != null)
|
||||
hash = hash * 43 + compiledVersion.hashCode();
|
||||
if (rawCompiledVersion != null)
|
||||
@@ -505,7 +505,7 @@ public class ModuleDescriptor
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = mods.hashCode();
|
||||
int hash = modsHashCode(mods);
|
||||
hash = hash * 43 + source.hashCode();
|
||||
return hash * 43 + targets.hashCode();
|
||||
}
|
||||
@@ -708,7 +708,7 @@ public class ModuleDescriptor
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = mods.hashCode();
|
||||
int hash = modsHashCode(mods);
|
||||
hash = hash * 43 + source.hashCode();
|
||||
return hash * 43 + targets.hashCode();
|
||||
}
|
||||
@@ -2261,7 +2261,7 @@ public class ModuleDescriptor
|
||||
int hc = hash;
|
||||
if (hc == 0) {
|
||||
hc = name.hashCode();
|
||||
hc = hc * 43 + Objects.hashCode(modifiers);
|
||||
hc = hc * 43 + modsHashCode(modifiers);
|
||||
hc = hc * 43 + requires.hashCode();
|
||||
hc = hc * 43 + Objects.hashCode(packages);
|
||||
hc = hc * 43 + exports.hashCode();
|
||||
@@ -2546,6 +2546,18 @@ public class ModuleDescriptor
|
||||
.collect(Collectors.joining(" "));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and returns a hashcode for the enum instances. The returned hashcode
|
||||
* is a value based on the {@link Enum#name() name} of each enum instance.
|
||||
*/
|
||||
private static int modsHashCode(Iterable<? extends Enum<?>> enums) {
|
||||
int h = 0;
|
||||
for (Enum<?> e : enums) {
|
||||
h = h * 43 + Objects.hashCode(e.name());
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
private static <T extends Object & Comparable<? super T>>
|
||||
int compare(T obj1, T obj2) {
|
||||
if (obj1 != null) {
|
||||
|
||||
@@ -46,6 +46,7 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import jdk.internal.util.StaticProperty;
|
||||
import sun.nio.cs.ISO_8859_1;
|
||||
import sun.nio.cs.UTF_8;
|
||||
|
||||
@@ -807,17 +808,25 @@ public class Properties extends Hashtable<Object,Object> {
|
||||
* If the comments argument is not null, then an ASCII {@code #}
|
||||
* character, the comments string, and a line separator are first written
|
||||
* to the output stream. Thus, the {@code comments} can serve as an
|
||||
* identifying comment. Any one of a line feed ('\n'), a carriage
|
||||
* return ('\r'), or a carriage return followed immediately by a line feed
|
||||
* in comments is replaced by a line separator generated by the {@code Writer}
|
||||
* and if the next character in comments is not character {@code #} or
|
||||
* character {@code !} then an ASCII {@code #} is written out
|
||||
* after that line separator.
|
||||
* identifying comment. Any one of a line feed ({@code \n}), a carriage
|
||||
* return ({@code \r}), or a carriage return followed immediately by a line feed
|
||||
* ({@code \r\n}) in comments is replaced by a
|
||||
* {@link System#lineSeparator() line separator} and if the next
|
||||
* character in comments is not character {@code #} or character {@code !} then
|
||||
* an ASCII {@code #} is written out after that line separator.
|
||||
* <p>
|
||||
* Next, a comment line is always written, consisting of an ASCII
|
||||
* {@code #} character, the current date and time (as if produced
|
||||
* by the {@code toString} method of {@code Date} for the
|
||||
* current time), and a line separator as generated by the {@code Writer}.
|
||||
* If the {@systemProperty java.properties.date} is set on the command line
|
||||
* and is non-empty (as determined by {@link String#isEmpty() String.isEmpty}),
|
||||
* a comment line is written as follows.
|
||||
* First, a {@code #} character is written, followed by the contents
|
||||
* of the property, followed by a line separator. Any line terminator characters
|
||||
* in the value of the system property are treated the same way as noted above
|
||||
* for the comments argument.
|
||||
* If the system property is not set or is empty, a comment line is written
|
||||
* as follows.
|
||||
* First, a {@code #} character is written, followed by the current date and time
|
||||
* formatted as if by the {@link Date#toString() Date.toString} method,
|
||||
* followed by a line separator.
|
||||
* <p>
|
||||
* Then every entry in this {@code Properties} table is
|
||||
* written out, one per line. For each entry the key string is
|
||||
@@ -833,6 +842,10 @@ public class Properties extends Hashtable<Object,Object> {
|
||||
* After the entries have been written, the output stream is flushed.
|
||||
* The output stream remains open after this method returns.
|
||||
*
|
||||
* @implSpec The keys and elements are written in the natural sort order
|
||||
* of the keys in the {@code entrySet()} unless {@code entrySet()} is
|
||||
* overridden by a subclass to return a different value than {@code super.entrySet()}.
|
||||
*
|
||||
* @param writer an output character stream writer.
|
||||
* @param comments a description of the property list.
|
||||
* @throws IOException if writing this property list to the specified
|
||||
@@ -903,12 +916,25 @@ public class Properties extends Hashtable<Object,Object> {
|
||||
if (comments != null) {
|
||||
writeComments(bw, comments);
|
||||
}
|
||||
bw.write("#" + new Date().toString());
|
||||
bw.newLine();
|
||||
writeDateComment(bw);
|
||||
|
||||
synchronized (this) {
|
||||
for (Map.Entry<Object, Object> e : entrySet()) {
|
||||
String key = (String)e.getKey();
|
||||
String val = (String)e.getValue();
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Map.Entry<String, String>> entries = (Set<Map.Entry<String, String>>) (Set) entrySet();
|
||||
// entrySet() can be overridden by subclasses. Here we check to see if
|
||||
// the returned instance type is the one returned by the Properties.entrySet()
|
||||
// implementation. If yes, then we sort those entries in the natural order
|
||||
// of their key. Else, we consider that the subclassed implementation may
|
||||
// potentially have returned a differently ordered entries and so we just
|
||||
// use the iteration order of the returned instance.
|
||||
if (entries instanceof Collections.SynchronizedSet<?> ss
|
||||
&& ss.c instanceof EntrySet) {
|
||||
entries = new ArrayList<>(entries);
|
||||
((List<Map.Entry<String, String>>) entries).sort(Map.Entry.comparingByKey());
|
||||
}
|
||||
for (Map.Entry<String, String> e : entries) {
|
||||
String key = e.getKey();
|
||||
String val = e.getValue();
|
||||
key = saveConvert(key, true, escUnicode);
|
||||
/* No need to escape embedded and trailing spaces for value, hence
|
||||
* pass false to flag.
|
||||
@@ -921,6 +947,19 @@ public class Properties extends Hashtable<Object,Object> {
|
||||
bw.flush();
|
||||
}
|
||||
|
||||
private static void writeDateComment(BufferedWriter bw) throws IOException {
|
||||
// value of java.properties.date system property isn't sensitive
|
||||
// and so doesn't need any security manager checks to make the value accessible
|
||||
// to the callers
|
||||
String sysPropVal = StaticProperty.javaPropertiesDate();
|
||||
if (sysPropVal != null && !sysPropVal.isEmpty()) {
|
||||
writeComments(bw, sysPropVal);
|
||||
} else {
|
||||
bw.write("#" + new Date());
|
||||
bw.newLine();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all of the properties represented by the XML document on the
|
||||
* specified input stream into this properties table.
|
||||
|
||||
@@ -50,6 +50,7 @@ public final class StaticProperty {
|
||||
private static final String JDK_SERIAL_FILTER_FACTORY;
|
||||
private static final String JAVA_IO_TMPDIR;
|
||||
private static final String NATIVE_ENCODING;
|
||||
private static final String JAVA_PROPERTIES_DATE;
|
||||
|
||||
private StaticProperty() {}
|
||||
|
||||
@@ -65,6 +66,7 @@ public final class StaticProperty {
|
||||
JDK_SERIAL_FILTER = getProperty(props, "jdk.serialFilter", null);
|
||||
JDK_SERIAL_FILTER_FACTORY = getProperty(props, "jdk.serialFilterFactory", null);
|
||||
NATIVE_ENCODING = getProperty(props, "native.encoding");
|
||||
JAVA_PROPERTIES_DATE = getProperty(props, "java.properties.date", null);
|
||||
}
|
||||
|
||||
private static String getProperty(Properties props, String key) {
|
||||
@@ -212,4 +214,16 @@ public final class StaticProperty {
|
||||
public static String nativeEncoding() {
|
||||
return NATIVE_ENCODING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@code java.properties.date} system property.
|
||||
*
|
||||
* <strong>{@link SecurityManager#checkPropertyAccess} is NOT checked
|
||||
* in this method.</strong>
|
||||
*
|
||||
* @return the {@code java.properties.date} system property
|
||||
*/
|
||||
public static String javaPropertiesDate() {
|
||||
return JAVA_PROPERTIES_DATE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,6 +139,8 @@ class UnixDomainSockets {
|
||||
return UnixDomainSocketAddress.of(path);
|
||||
} catch (InvalidPathException e) {
|
||||
throw new BindException("Invalid temporary directory");
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new UnsupportedOperationException("Unix Domain Sockets not supported on non-default file system");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -444,7 +444,8 @@ static int copystrings(char *buf, int offset, const char * const *arg) {
|
||||
__attribute_noinline__
|
||||
#endif
|
||||
|
||||
/* vfork(2) is deprecated on Solaris */
|
||||
/* vfork(2) is deprecated on Darwin */
|
||||
#ifndef __APPLE__
|
||||
static pid_t
|
||||
vforkChild(ChildStuff *c) {
|
||||
volatile pid_t resultPid;
|
||||
@@ -463,6 +464,7 @@ vforkChild(ChildStuff *c) {
|
||||
assert(resultPid != 0); /* childProcess never returns */
|
||||
return resultPid;
|
||||
}
|
||||
#endif
|
||||
|
||||
static pid_t
|
||||
forkChild(ChildStuff *c) {
|
||||
@@ -573,9 +575,11 @@ spawnChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath)
|
||||
static pid_t
|
||||
startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
|
||||
switch (c->mode) {
|
||||
/* vfork(2) is deprecated on Solaris */
|
||||
/* vfork(2) is deprecated on Darwin*/
|
||||
#ifndef __APPLE__
|
||||
case MODE_VFORK:
|
||||
return vforkChild(c);
|
||||
#endif
|
||||
case MODE_FORK:
|
||||
return forkChild(c);
|
||||
case MODE_POSIX_SPAWN:
|
||||
|
||||
@@ -43,6 +43,7 @@ final class GestureHandler {
|
||||
@Native static final int ROTATE = 2;
|
||||
@Native static final int MAGNIFY = 3;
|
||||
@Native static final int SWIPE = 4;
|
||||
@Native static final int PRESSURE = 5;
|
||||
|
||||
// installs a private instance of GestureHandler, if necessary
|
||||
static void addGestureListenerTo(final JComponent component, final GestureListener listener) {
|
||||
@@ -97,6 +98,9 @@ final class GestureHandler {
|
||||
case SWIPE:
|
||||
firstNotifier.recursivelyHandleSwipe(a, b, new SwipeEvent());
|
||||
return;
|
||||
case PRESSURE:
|
||||
firstNotifier.recursivelyHandlePressure(new PressureEvent(a,b));
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -107,6 +111,7 @@ final class GestureHandler {
|
||||
final List<RotationListener> rotaters = new LinkedList<RotationListener>();
|
||||
final List<MagnificationListener> magnifiers = new LinkedList<MagnificationListener>();
|
||||
final List<SwipeListener> swipers = new LinkedList<SwipeListener>();
|
||||
final List<PressureListener> pressures = new LinkedList<PressureListener>();
|
||||
|
||||
GestureHandler() { }
|
||||
|
||||
@@ -115,6 +120,7 @@ final class GestureHandler {
|
||||
if (listener instanceof RotationListener) rotaters.add((RotationListener)listener);
|
||||
if (listener instanceof MagnificationListener) magnifiers.add((MagnificationListener)listener);
|
||||
if (listener instanceof SwipeListener) swipers.add((SwipeListener)listener);
|
||||
if (listener instanceof PressureListener) pressures.add((PressureListener)listener);
|
||||
}
|
||||
|
||||
void removeListener(final GestureListener listener) {
|
||||
@@ -169,6 +175,16 @@ final class GestureHandler {
|
||||
if (next != null) next.recursivelyHandleMagnify(e);
|
||||
}
|
||||
|
||||
void recursivelyHandlePressure(final PressureEvent e) {
|
||||
for (final PressureListener listener : handler.pressures) {
|
||||
listener.pressure(e);
|
||||
if (e.isConsumed()) return;
|
||||
}
|
||||
|
||||
final PerComponentNotifier next = getNextNotifierForComponent(component.getParent());
|
||||
if (next != null) next.recursivelyHandlePressure(e);
|
||||
}
|
||||
|
||||
void recursivelyHandleSwipe(final double x, final double y, final SwipeEvent e) {
|
||||
for (final SwipeListener listener : handler.swipers) {
|
||||
if (x < 0) listener.swipedLeft(e);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, 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.apple.eawt.event;
|
||||
|
||||
/**
|
||||
* Event indicating a swipe was performed by the user.
|
||||
*
|
||||
* @see PressureListener
|
||||
*
|
||||
* @since Java for Mac OS X 10.10 Update 3, JDK 8
|
||||
*/
|
||||
public class PressureEvent extends GestureEvent {
|
||||
|
||||
public double getPressure() {
|
||||
return pressure;
|
||||
}
|
||||
|
||||
public double getStage() {
|
||||
return stage;
|
||||
}
|
||||
|
||||
private double pressure;
|
||||
private double stage;
|
||||
|
||||
PressureEvent(double pressure, double stage) {
|
||||
this.pressure = pressure;
|
||||
this.stage = stage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, 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.apple.eawt.event;
|
||||
|
||||
/**
|
||||
* Listener interface for receiving pressure events.
|
||||
*
|
||||
* @see PressureEvent
|
||||
* @see GestureUtilities
|
||||
*
|
||||
* @since Java for Mac OS X 10.5 Update 7, Java for Mac OS X 10.6 Update 2
|
||||
*/
|
||||
public interface PressureListener extends GestureListener {
|
||||
public void pressure(final PressureEvent e);
|
||||
}
|
||||
@@ -128,12 +128,8 @@ public class CCharToGlyphMapper extends CharToGlyphMapper {
|
||||
};
|
||||
}
|
||||
|
||||
// This mapper returns either the glyph code, or if the character can be
|
||||
// replaced on-the-fly using CoreText substitution; the negative unicode
|
||||
// value. If this "glyph code int" is treated as an opaque code, it will
|
||||
// strike and measure exactly as a real glyph code - whether the character
|
||||
// is present or not. Missing characters for any font on the system will
|
||||
// be returned as 0, as the getMissingGlyphCode() function above indicates.
|
||||
// Missing characters for any font on the system will be returned as 0,
|
||||
// as the getMissingGlyphCode() function above indicates.
|
||||
private static native void nativeCharsToGlyphs(final long nativeFontPtr,
|
||||
int count, char[] unicodes,
|
||||
int[] glyphs);
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sun.font;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class CCompositeFont extends CompositeFont {
|
||||
private final List<CFont> fallbackFonts = new ArrayList<>();
|
||||
|
||||
public CCompositeFont(CFont font) {
|
||||
super(new PhysicalFont[]{font});
|
||||
mapper = new CCompositeGlyphMapper(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getNumSlots() {
|
||||
return super.getNumSlots();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFont getSlotFont(int slot) {
|
||||
if (slot == 0) return (CFont) super.getSlotFont(0);
|
||||
synchronized (this) {
|
||||
return fallbackFonts.get(slot - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
|
||||
return super.getStrike(desc, copy);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized int getValidatedGlyphCode(int glyphCode) {
|
||||
return super.getValidatedGlyphCode(glyphCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSupplementaryChars() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAAForPtSize(int ptsize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized int findSlot(String fontName) {
|
||||
for (int slot = 0; slot < numSlots; slot++) {
|
||||
CFont slotFont = getSlotFont(slot);
|
||||
if (fontName.equals(slotFont.getNativeFontName())) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public synchronized int addSlot(CFont font) {
|
||||
int slot = findSlot(font.getNativeFontName());
|
||||
if (slot >= 0) return slot;
|
||||
fallbackFonts.add(font);
|
||||
lastFontStrike = new SoftReference<>(null);
|
||||
strikeCache.clear();
|
||||
return numSlots++;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.font;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public final class CCompositeGlyphMapper extends CompositeGlyphMapper {
|
||||
public CCompositeGlyphMapper(CCompositeFont compFont) {
|
||||
super(compFont);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int convertToGlyph(int unicode) {
|
||||
CCompositeFont compositeFont = (CCompositeFont) font;
|
||||
CFont mainFont = (CFont) font.getSlotFont(0);
|
||||
String[] fallbackFontInfo = new String[2];
|
||||
int glyphCode = nativeCodePointToGlyph(mainFont.getNativeFontPtr(), unicode, fallbackFontInfo);
|
||||
if (glyphCode == missingGlyph) {
|
||||
setCachedGlyphCode(unicode, missingGlyph);
|
||||
return missingGlyph;
|
||||
}
|
||||
String fallbackFontName = fallbackFontInfo[0];
|
||||
String fallbackFontFamilyName = fallbackFontInfo[1];
|
||||
if (fallbackFontName == null || fallbackFontFamilyName == null) {
|
||||
int result = compositeGlyphCode(0, glyphCode);
|
||||
setCachedGlyphCode(unicode, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int slot = compositeFont.findSlot(fallbackFontName);
|
||||
|
||||
if (slot < 0) {
|
||||
Font2D fallbackFont = FontManagerFactory.getInstance().findFont2D(fallbackFontName,
|
||||
Font.PLAIN, FontManager.NO_FALLBACK);
|
||||
if (!(fallbackFont instanceof CFont) ||
|
||||
!fallbackFontName.equals(((CFont) fallbackFont).getNativeFontName())) {
|
||||
// Native font fallback mechanism can return "hidden" fonts - their names start with dot,
|
||||
// and they are not returned in a list of fonts available in system, but they can still be used
|
||||
// if requested explicitly.
|
||||
fallbackFont = new CFont(fallbackFontName, fallbackFontFamilyName, null);
|
||||
}
|
||||
|
||||
if (mainFont.isFakeItalic()) fallbackFont = ((CFont)fallbackFont).createItalicVariant(false);
|
||||
|
||||
slot = compositeFont.addSlot((CFont) fallbackFont);
|
||||
}
|
||||
|
||||
int result = compositeGlyphCode(slot, glyphCode);
|
||||
setCachedGlyphCode(unicode, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// This invokes native font fallback mechanism, returning information about font (its Postscript and family names)
|
||||
// able to display a given character, and corresponding glyph code
|
||||
private static native int nativeCodePointToGlyph(long nativeFontPtr, int codePoint, String[] result);
|
||||
}
|
||||
@@ -31,6 +31,9 @@ import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
// Right now this class is final to avoid a problem with native code.
|
||||
// For some reason the JNI IsInstanceOf was not working correctly
|
||||
@@ -175,14 +178,12 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
isFakeItalic = other.isFakeItalic;
|
||||
}
|
||||
|
||||
public CFont createItalicVariant(boolean updateStyle) {
|
||||
public CFont createItalicVariant() {
|
||||
CFont font = new CFont(this, familyName);
|
||||
font.nativeFontName = fullName;
|
||||
font.fullName =
|
||||
fullName + (style == Font.BOLD ? "" : "-") + "Italic-Derived";
|
||||
if (updateStyle) {
|
||||
font.style |= Font.ITALIC;
|
||||
}
|
||||
font.style |= Font.ITALIC;
|
||||
font.isFakeItalic = true;
|
||||
return font;
|
||||
}
|
||||
@@ -204,11 +205,51 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
return getCGFontPtrNative(getNativeFontPtr());
|
||||
}
|
||||
|
||||
static native void getCascadeList(long nativeFontPtr, ArrayList<String> listOfString);
|
||||
|
||||
private CompositeFont createCompositeFont() {
|
||||
ArrayList<String> listOfString = new ArrayList<String>();
|
||||
getCascadeList(getNativeFontPtr(), listOfString);
|
||||
|
||||
Set<String> components = new LinkedHashSet<>(listOfString);
|
||||
// In some italic cases the standard Mac cascade list is missing Arabic.
|
||||
components.add("GeezaPro");
|
||||
CFontManager fm = (CFontManager) FontManagerFactory.getInstance();
|
||||
components.addAll(fm.getAdditionalFallbackVariants());
|
||||
int numFonts = 1 + components.size();
|
||||
PhysicalFont[] fonts = new PhysicalFont[numFonts];
|
||||
fonts[0] = this;
|
||||
int idx = 1;
|
||||
if (FontUtilities.isLogging()) {
|
||||
FontUtilities.logInfo("Cascading list for " + this + " :");
|
||||
}
|
||||
for (String s : components) {
|
||||
if (FontUtilities.isLogging()) {
|
||||
FontUtilities.logInfo("Fallback:" + s);
|
||||
}
|
||||
if (s.equals(".AppleSymbolsFB")) {
|
||||
// Don't know why we get the weird name above .. replace.
|
||||
s = "AppleSymbols";
|
||||
}
|
||||
Font2D f2d = fm.getOrCreateFallbackFont(s);
|
||||
if (f2d == null || f2d == this) {
|
||||
continue;
|
||||
}
|
||||
fonts[idx++] = (PhysicalFont)f2d;
|
||||
}
|
||||
if (idx < fonts.length) {
|
||||
PhysicalFont[] orig = fonts;
|
||||
fonts = new PhysicalFont[idx];
|
||||
System.arraycopy(orig, 0, fonts, 0, idx);
|
||||
}
|
||||
return new CompositeFont(fonts);
|
||||
}
|
||||
|
||||
private CompositeFont compFont;
|
||||
|
||||
public CompositeFont getCompositeFont2D() {
|
||||
if (compFont == null) {
|
||||
compFont = new CCompositeFont(this);
|
||||
compFont = createCompositeFont();
|
||||
}
|
||||
return compFont;
|
||||
}
|
||||
@@ -236,14 +277,6 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
return new CStrike(this, desc);
|
||||
}
|
||||
|
||||
boolean isFakeItalic() {
|
||||
return isFakeItalic;
|
||||
}
|
||||
|
||||
String getNativeFontName() {
|
||||
return nativeFontName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypographicSubfamilyName() {
|
||||
return faceName == null ? super.getTypographicSubfamilyName() : faceName;
|
||||
@@ -276,8 +309,4 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
", familyName: " + familyName + ", style: " + style +
|
||||
" } aka: " + super.toString();
|
||||
}
|
||||
|
||||
public Font2D createItalic() {
|
||||
return this.createItalicVariant(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,20 +30,27 @@ import java.io.File;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
|
||||
import sun.awt.FontConfiguration;
|
||||
import sun.awt.HeadlessToolkit;
|
||||
import sun.lwawt.macosx.*;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
public final class CFontManager extends SunFontManager {
|
||||
private static Hashtable<String, Font2D> genericFonts = new Hashtable<String, Font2D>();
|
||||
private final Map<String, Font2D> fallbackFonts = new ConcurrentHashMap<>();
|
||||
private final List<String> extFallbackVariants = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected FontConfiguration createFontConfiguration() {
|
||||
@@ -230,6 +237,7 @@ public final class CFontManager extends SunFontManager {
|
||||
public Object run() {
|
||||
if (!loadedAllFonts) {
|
||||
loadNativeFonts();
|
||||
collectAdditionalFallbackVariants();
|
||||
loadedAllFonts = true;
|
||||
}
|
||||
return null;
|
||||
@@ -337,4 +345,40 @@ public final class CFontManager extends SunFontManager {
|
||||
@Override
|
||||
protected void populateFontFileNameMap(HashMap<String, String> fontToFileMap, HashMap<String, String> fontToFamilyNameMap,
|
||||
HashMap<String, ArrayList<String>> familyToFontListMap, Locale locale) {}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private void collectAdditionalFallbackVariants() {
|
||||
if (AccessController.doPrivileged(new GetBooleanAction("mac.ext.font.fallback"))) {
|
||||
for (String fontName : genericFonts.keySet()) {
|
||||
boolean accept = false;
|
||||
if (fontName.equals("ArialUnicodeMS")) {
|
||||
accept = true;
|
||||
} else if (fontName.startsWith("NotoSans")) {
|
||||
int pos = fontName.indexOf('-');
|
||||
accept = pos == -1 || fontName.substring(pos + 1).equals("Regular");
|
||||
}
|
||||
if (accept) {
|
||||
extFallbackVariants.add(fontName);
|
||||
}
|
||||
}
|
||||
Collections.sort(extFallbackVariants); // ensure predictable order
|
||||
}
|
||||
}
|
||||
|
||||
List<String> getAdditionalFallbackVariants() {
|
||||
return extFallbackVariants;
|
||||
}
|
||||
|
||||
Font2D getOrCreateFallbackFont(String fontName) {
|
||||
Font2D font2D = findFont2D(fontName, Font.PLAIN, FontManager.NO_FALLBACK);
|
||||
if (font2D != null || fontName.startsWith(".")) {
|
||||
return font2D;
|
||||
} else {
|
||||
// macOS doesn't list some system fonts in [NSFontManager availableFontFamilies] output,
|
||||
// so they are not registered in font manager as part of 'loadNativeFonts'.
|
||||
// These fonts are present in [NSFontManager availableFonts] output though,
|
||||
// and can be accessed in the same way as other system fonts.
|
||||
return fallbackFonts.computeIfAbsent(fontName, name -> new CFont(name, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,18 +358,14 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
}
|
||||
|
||||
// This class stores glyph pointers, and is indexed based on glyph codes,
|
||||
// and negative unicode values. See the comments in
|
||||
// CCharToGlyphMapper for more details on our glyph code strategy.
|
||||
// This class stores glyph pointers, and is indexed based on glyph codes.
|
||||
private static class GlyphInfoCache extends CStrikeDisposer {
|
||||
private static final int FIRST_LAYER_SIZE = 256;
|
||||
private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
|
||||
|
||||
// rdar://problem/5204197
|
||||
private final AtomicBoolean disposed = new AtomicBoolean(false);
|
||||
|
||||
private final long[] firstLayerCache;
|
||||
private SparseBitShiftingTwoLayerArray secondLayerCache;
|
||||
private HashMap<Integer, Long> generalCache;
|
||||
|
||||
GlyphInfoCache(final Font2D nativeFont, final FontStrikeDesc desc) {
|
||||
@@ -378,19 +374,9 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
|
||||
public synchronized long get(final int index) {
|
||||
if (index < 0) {
|
||||
if (-index < SECOND_LAYER_SIZE) {
|
||||
// catch common unicodes
|
||||
if (secondLayerCache == null) {
|
||||
return 0L;
|
||||
}
|
||||
return secondLayerCache.get(-index);
|
||||
}
|
||||
} else {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[index];
|
||||
}
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[index];
|
||||
}
|
||||
|
||||
if (generalCache == null) {
|
||||
@@ -404,21 +390,10 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
|
||||
public synchronized void put(final int index, final long value) {
|
||||
if (index < 0) {
|
||||
if (-index < SECOND_LAYER_SIZE) {
|
||||
// catch common unicodes
|
||||
if (secondLayerCache == null) {
|
||||
secondLayerCache = new SparseBitShiftingTwoLayerArray(SECOND_LAYER_SIZE, 7); // 128x128
|
||||
}
|
||||
secondLayerCache.put(-index, value);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
}
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (generalCache == null) {
|
||||
@@ -441,14 +416,6 @@ public final class CStrike extends PhysicalStrike {
|
||||
// clean out the first array
|
||||
disposeLongArray(firstLayerCache);
|
||||
|
||||
// clean out the two layer arrays
|
||||
if (secondLayerCache != null) {
|
||||
final long[][] secondLayerLongArrayArray = secondLayerCache.cache;
|
||||
for (final long[] longArray : secondLayerLongArrayArray) {
|
||||
if (longArray != null) disposeLongArray(longArray);
|
||||
}
|
||||
}
|
||||
|
||||
// clean up everyone else
|
||||
if (generalCache != null) {
|
||||
for (Long aLong : generalCache.values()) {
|
||||
@@ -485,56 +452,18 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SparseBitShiftingTwoLayerArray {
|
||||
final long[][] cache;
|
||||
final int shift;
|
||||
final int secondLayerLength;
|
||||
|
||||
SparseBitShiftingTwoLayerArray(final int size, final int shift) {
|
||||
this.shift = shift;
|
||||
this.cache = new long[1 << shift][];
|
||||
this.secondLayerLength = size >> shift;
|
||||
}
|
||||
|
||||
public long get(final int index) {
|
||||
final int firstIndex = index >> shift;
|
||||
final long[] firstLayerRow = cache[firstIndex];
|
||||
if (firstLayerRow == null) return 0L;
|
||||
return firstLayerRow[index - (firstIndex * (1 << shift))];
|
||||
}
|
||||
|
||||
public void put(final int index, final long value) {
|
||||
final int firstIndex = index >> shift;
|
||||
long[] firstLayerRow = cache[firstIndex];
|
||||
if (firstLayerRow == null) {
|
||||
cache[firstIndex] = firstLayerRow = new long[secondLayerLength];
|
||||
}
|
||||
firstLayerRow[index - (firstIndex * (1 << shift))] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class GlyphAdvanceCache {
|
||||
private static final int FIRST_LAYER_SIZE = 256;
|
||||
private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
|
||||
|
||||
private final float[] firstLayerCache = new float[FIRST_LAYER_SIZE];
|
||||
private SparseBitShiftingTwoLayerArray secondLayerCache;
|
||||
private HashMap<Integer, Float> generalCache;
|
||||
|
||||
public synchronized float get(final int index) {
|
||||
if (index < 0) {
|
||||
if (-index < SECOND_LAYER_SIZE) {
|
||||
// catch common unicodes
|
||||
if (secondLayerCache == null) return 0;
|
||||
return secondLayerCache.get(-index);
|
||||
}
|
||||
} else {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[index];
|
||||
}
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[index];
|
||||
}
|
||||
|
||||
if (generalCache == null) return 0;
|
||||
@@ -544,21 +473,10 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
|
||||
public synchronized void put(final int index, final float value) {
|
||||
if (index < 0) {
|
||||
if (-index < SECOND_LAYER_SIZE) {
|
||||
// catch common unicodes
|
||||
if (secondLayerCache == null) {
|
||||
secondLayerCache = new SparseBitShiftingTwoLayerArray(SECOND_LAYER_SIZE, 7); // 128x128
|
||||
}
|
||||
secondLayerCache.put(-index, value);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
}
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (generalCache == null) {
|
||||
@@ -567,34 +485,5 @@ public final class CStrike extends PhysicalStrike {
|
||||
|
||||
generalCache.put(Integer.valueOf(index), Float.valueOf(value));
|
||||
}
|
||||
|
||||
private static class SparseBitShiftingTwoLayerArray {
|
||||
final float[][] cache;
|
||||
final int shift;
|
||||
final int secondLayerLength;
|
||||
|
||||
SparseBitShiftingTwoLayerArray(final int size, final int shift) {
|
||||
this.shift = shift;
|
||||
this.cache = new float[1 << shift][];
|
||||
this.secondLayerLength = size >> shift;
|
||||
}
|
||||
|
||||
public float get(final int index) {
|
||||
final int firstIndex = index >> shift;
|
||||
final float[] firstLayerRow = cache[firstIndex];
|
||||
if (firstLayerRow == null) return 0L;
|
||||
return firstLayerRow[index - (firstIndex * (1 << shift))];
|
||||
}
|
||||
|
||||
public void put(final int index, final float value) {
|
||||
final int firstIndex = index >> shift;
|
||||
float[] firstLayerRow = cache[firstIndex];
|
||||
if (firstLayerRow == null) {
|
||||
cache[firstIndex] = firstLayerRow =
|
||||
new float[secondLayerLength];
|
||||
}
|
||||
firstLayerRow[index - (firstIndex * (1 << shift))] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,13 +25,14 @@
|
||||
|
||||
package sun.lwawt.macosx;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import javax.accessibility.Accessible;
|
||||
import javax.accessibility.AccessibleContext;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.*;
|
||||
|
||||
import static javax.accessibility.AccessibleContext.ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY;
|
||||
import static javax.accessibility.AccessibleContext.ACCESSIBLE_CARET_PROPERTY;
|
||||
@@ -48,6 +49,20 @@ import sun.awt.AWTAccessor;
|
||||
|
||||
|
||||
class CAccessible extends CFRetainedResource implements Accessible {
|
||||
private static Timer timer = null;
|
||||
private final static int SELECTED_CHILDREN_MILLISECONDS_DEFAULT = 100;
|
||||
private static int SELECTED_CHILDREN_MILLISECONDS;
|
||||
|
||||
static {
|
||||
@SuppressWarnings("removal") int scms = java.security.AccessController.doPrivileged(new PrivilegedAction<Integer>() {
|
||||
@Override
|
||||
public Integer run() {
|
||||
return Integer.getInteger("sun.lwawt.macosx.CAccessible.selectedChildrenMilliSeconds",
|
||||
SELECTED_CHILDREN_MILLISECONDS_DEFAULT);
|
||||
}
|
||||
});
|
||||
SELECTED_CHILDREN_MILLISECONDS = scms >= 0 ? scms : SELECTED_CHILDREN_MILLISECONDS_DEFAULT;
|
||||
}
|
||||
|
||||
public static CAccessible getCAccessible(final Accessible a) {
|
||||
if (a == null) return null;
|
||||
@@ -112,19 +127,25 @@ class CAccessible extends CFRetainedResource implements Accessible {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent e) {
|
||||
assert EventQueue.isDispatchThread();
|
||||
String name = e.getPropertyName();
|
||||
if ( ptr != 0 ) {
|
||||
Object newValue = e.getNewValue();
|
||||
Object oldValue = e.getOldValue();
|
||||
if (name.compareTo(ACCESSIBLE_CARET_PROPERTY) == 0) {
|
||||
selectedTextChanged(ptr);
|
||||
} else if (name.compareTo(ACCESSIBLE_TEXT_PROPERTY) == 0) {
|
||||
valueChanged(ptr);
|
||||
} else if (name.compareTo(ACCESSIBLE_SELECTION_PROPERTY) == 0) {
|
||||
selectionChanged(ptr);
|
||||
} else if (name.compareTo(ACCESSIBLE_TABLE_MODEL_CHANGED) == 0) {
|
||||
valueChanged(ptr);
|
||||
} else if (name.compareTo(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY) == 0 ) {
|
||||
if (name.equals(ACCESSIBLE_CARET_PROPERTY)) {
|
||||
execute(ptr -> selectedTextChanged(ptr));
|
||||
} else if (name.equals(ACCESSIBLE_TEXT_PROPERTY)) {
|
||||
execute(ptr -> valueChanged(ptr));
|
||||
} else if (name.equals(ACCESSIBLE_SELECTION_PROPERTY)) {
|
||||
if (timer != null) {
|
||||
timer.stop();
|
||||
}
|
||||
timer = new Timer(SELECTED_CHILDREN_MILLISECONDS, actionEvent -> execute(ptr -> selectionChanged(ptr)));
|
||||
timer.setRepeats(false);
|
||||
timer.start();
|
||||
} else if (name.equals(ACCESSIBLE_TABLE_MODEL_CHANGED)) {
|
||||
execute(ptr -> valueChanged(ptr));
|
||||
} else if (name.equals(ACCESSIBLE_ACTIVE_DESCENDANT_PROPERTY)) {
|
||||
if (newValue == null || newValue instanceof AccessibleContext) {
|
||||
activeDescendant = (AccessibleContext)newValue;
|
||||
if (newValue instanceof Accessible) {
|
||||
@@ -135,7 +156,7 @@ class CAccessible extends CFRetainedResource implements Accessible {
|
||||
if (p != null) {
|
||||
AccessibleContext pac = p.getAccessibleContext();
|
||||
if ((pac != null) && (pac.getAccessibleRole() == AccessibleRole.TABLE)) {
|
||||
selectedCellsChanged(ptr);
|
||||
execute(ptr -> selectedCellsChanged(ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,9 +172,9 @@ class CAccessible extends CFRetainedResource implements Accessible {
|
||||
}
|
||||
|
||||
if (newValue == AccessibleState.EXPANDED) {
|
||||
treeNodeExpanded(ptr);
|
||||
execute(ptr -> treeNodeExpanded(ptr));
|
||||
} else if (newValue == AccessibleState.COLLAPSED) {
|
||||
treeNodeCollapsed(ptr);
|
||||
execute(ptr -> treeNodeCollapsed(ptr));
|
||||
}
|
||||
|
||||
// At least for now don't handle combo box menu state changes.
|
||||
@@ -161,41 +182,44 @@ class CAccessible extends CFRetainedResource implements Accessible {
|
||||
// exist for combo boxes, but for now the following is only
|
||||
// for JPopupMenus, not for combobox menus.
|
||||
if (thisRole == AccessibleRole.COMBO_BOX) {
|
||||
selectionChanged(ptr);
|
||||
if (timer != null) {
|
||||
timer.stop();
|
||||
}
|
||||
timer = new Timer(SELECTED_CHILDREN_MILLISECONDS, actionEvent -> execute(ptr -> selectionChanged(ptr)));
|
||||
timer.setRepeats(false);
|
||||
timer.start();
|
||||
}
|
||||
|
||||
// if (parentRole != AccessibleRole.COMBO_BOX) {
|
||||
if (thisRole == AccessibleRole.POPUP_MENU) {
|
||||
if ( newValue != null &&
|
||||
((AccessibleState)newValue) == AccessibleState.VISIBLE ) {
|
||||
menuOpened(ptr);
|
||||
} else if ( oldValue != null &&
|
||||
((AccessibleState)oldValue) == AccessibleState.VISIBLE ) {
|
||||
menuClosed(ptr);
|
||||
}
|
||||
} else if (thisRole == AccessibleRole.MENU_ITEM) {
|
||||
if ( newValue != null &&
|
||||
((AccessibleState)newValue) == AccessibleState.FOCUSED ) {
|
||||
menuItemSelected(ptr);
|
||||
}
|
||||
// }
|
||||
if (thisRole == AccessibleRole.POPUP_MENU) {
|
||||
if (newValue != null &&
|
||||
((AccessibleState) newValue) == AccessibleState.VISIBLE) {
|
||||
execute(ptr -> menuOpened(ptr));
|
||||
} else if (oldValue != null &&
|
||||
((AccessibleState) oldValue) == AccessibleState.VISIBLE) {
|
||||
execute(ptr -> menuClosed(ptr));
|
||||
}
|
||||
} else if (thisRole == AccessibleRole.MENU_ITEM) {
|
||||
if (newValue != null &&
|
||||
((AccessibleState) newValue) == AccessibleState.FOCUSED) {
|
||||
execute(ptr -> menuItemSelected(ptr));
|
||||
}
|
||||
}
|
||||
|
||||
// Do send check box state changes to native side
|
||||
if (thisRole == AccessibleRole.CHECK_BOX) {
|
||||
valueChanged(ptr);
|
||||
execute(ptr -> valueChanged(ptr));
|
||||
}
|
||||
} else if (name.compareTo(ACCESSIBLE_NAME_PROPERTY) == 0) {
|
||||
//for now trigger only for JTabbedPane.
|
||||
if (e.getSource() instanceof JTabbedPane) {
|
||||
titleChanged(ptr);
|
||||
execute(ptr -> titleChanged(ptr));
|
||||
}
|
||||
} else if (name.compareTo(ACCESSIBLE_VALUE_PROPERTY) == 0) {
|
||||
AccessibleRole thisRole = accessible.getAccessibleContext()
|
||||
.getAccessibleRole();
|
||||
if (thisRole == AccessibleRole.SLIDER ||
|
||||
thisRole == AccessibleRole.PROGRESS_BAR) {
|
||||
valueChanged(ptr);
|
||||
execute(ptr -> valueChanged(ptr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,6 +231,15 @@ AWT_NS_WINDOW_IMPLEMENTATION
|
||||
b:[event deltaY]];
|
||||
}
|
||||
|
||||
- (void)pressureChangeWithEvent:(NSEvent *)event {
|
||||
float pressure = event.pressure;
|
||||
[self postGesture:event
|
||||
as:com_apple_eawt_event_GestureHandler_PRESSURE
|
||||
a:pressure
|
||||
b:(([event respondsToSelector:@selector(stage)]) ? ((NSInteger)[event stage]) : -1)
|
||||
];
|
||||
}
|
||||
|
||||
- (void)moveTabToNewWindow:(id)sender {
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
|
||||
@@ -125,11 +125,35 @@ canChooseDirectories:(BOOL)inChooseDirectories
|
||||
}
|
||||
|
||||
[thePanel setDelegate:self];
|
||||
|
||||
NSMenuItem *editMenuItem = nil;
|
||||
NSMenu *menu = [NSApp mainMenu];
|
||||
if (menu != nil) {
|
||||
if (menu.numberOfItems > 0) {
|
||||
NSMenu *submenu = [[menu itemAtIndex:0] submenu];
|
||||
if (submenu != nil) {
|
||||
menu = submenu;
|
||||
}
|
||||
}
|
||||
|
||||
editMenuItem = [self createEditMenu];
|
||||
if (menu.numberOfItems > 0) {
|
||||
[menu insertItem:editMenuItem atIndex:0];
|
||||
} else {
|
||||
[menu addItem:editMenuItem];
|
||||
}
|
||||
[editMenuItem release];
|
||||
}
|
||||
|
||||
fPanelResult = [thePanel runModalForDirectory:fDirectory file:fFile];
|
||||
[thePanel setDelegate:nil];
|
||||
CMenuBar *menuBar = [[ApplicationDelegate sharedDelegate] defaultMenuBar];
|
||||
[CMenuBar activate:menuBar modallyDisabled:NO];
|
||||
|
||||
if (editMenuItem != nil) {
|
||||
[menu removeItem:editMenuItem];
|
||||
}
|
||||
|
||||
if ([self userClickedOK]) {
|
||||
if (fMode == java_awt_FileDialog_LOAD) {
|
||||
NSOpenPanel *openPanel = (NSOpenPanel *)thePanel;
|
||||
@@ -144,6 +168,33 @@ canChooseDirectories:(BOOL)inChooseDirectories
|
||||
[self disposer];
|
||||
}
|
||||
|
||||
- (NSMenuItem *) createEditMenu {
|
||||
NSMenu *editMenu = [[NSMenu alloc] initWithTitle:@"Edit"];
|
||||
|
||||
NSMenuItem *cutItem = [[NSMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"];
|
||||
[editMenu addItem:cutItem];
|
||||
[cutItem release];
|
||||
|
||||
NSMenuItem *copyItem = [[NSMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"];
|
||||
[editMenu addItem:copyItem];
|
||||
[copyItem release];
|
||||
|
||||
NSMenuItem *pasteItem = [[NSMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"];
|
||||
[editMenu addItem:pasteItem];
|
||||
[pasteItem release];
|
||||
|
||||
NSMenuItem *selectAllItem = [[NSMenuItem alloc] initWithTitle:@"Select All" action:@selector(selectAll:) keyEquivalent:@"a"];
|
||||
[editMenu addItem:selectAllItem];
|
||||
[selectAllItem release];
|
||||
|
||||
NSMenuItem *editMenuItem = [NSMenuItem new];
|
||||
[editMenuItem setTitle:@"Edit"];
|
||||
[editMenuItem setSubmenu:editMenu];
|
||||
[editMenu release];
|
||||
|
||||
return editMenuItem;
|
||||
}
|
||||
|
||||
- (BOOL) askFilenameFilter:(NSString *)filename {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jstring jString = NormalizedPathJavaStringFromNSString(env, filename);
|
||||
|
||||
@@ -41,51 +41,6 @@ static const CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
|
||||
#pragma mark --- CoreText Support ---
|
||||
|
||||
|
||||
// Translates a Unicode into a CGGlyph/CTFontRef pair
|
||||
// Returns the substituted font, and places the appropriate glyph into "glyphRef"
|
||||
CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForUnicode
|
||||
(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {
|
||||
CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, charRef, count);
|
||||
if (fallback == NULL)
|
||||
{
|
||||
// use the original font if we somehow got duped into trying to fallback something we can't
|
||||
fallback = (CTFontRef)font->fFont;
|
||||
CFRetain(fallback);
|
||||
}
|
||||
|
||||
CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
|
||||
// Returns the substituted font, and places the appropriate glyph into "glyph"
|
||||
CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForJavaGlyphCode
|
||||
(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef)
|
||||
{
|
||||
// negative glyph codes are really unicodes, which were placed there by the mapper
|
||||
// to indicate we should use CoreText to substitute the character
|
||||
if (glyphCode >= 0)
|
||||
{
|
||||
*glyphRef = glyphCode;
|
||||
CFRetain(font->fFont);
|
||||
return (CTFontRef)font->fFont;
|
||||
}
|
||||
|
||||
UTF16Char character = -glyphCode;
|
||||
return JavaCT_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
|
||||
}
|
||||
|
||||
// Breakup a 32 bit unicode value into the component surrogate pairs
|
||||
void JavaCT_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) {
|
||||
int value = uniChar - 0x10000;
|
||||
UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START;
|
||||
UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START;
|
||||
charRef[0] = high_surrogate;
|
||||
charRef[1] = low_surrogate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Callback for CoreText which uses the CoreTextProviderStruct to feed CT UniChars
|
||||
* We only use it for one-off lines, and don't attempt to fragment our strings
|
||||
@@ -129,7 +84,7 @@ static NSDictionary* ctsDictionaryFor(const NSFont *font, BOOL useFractionalMetr
|
||||
// Itterates though each glyph, and if a transform is present for that glyph, apply it to the CGContext, and strike the glyph.
|
||||
// If there is no per-glyph transform, just strike the glyph. Advances must also be transformed on-the-spot as well.
|
||||
void JavaCT_DrawGlyphVector
|
||||
(const QuartzSDOps *qsdo, const AWTStrike *strike, const BOOL useSubstituion, const int uniChars[], const CGGlyph glyphs[], CGSize advances[], const jint g_gvTXIndicesAsInts[], const jdouble g_gvTransformsAsDoubles[], const CFIndex length)
|
||||
(const QuartzSDOps *qsdo, const AWTStrike *strike, const CGGlyph glyphs[], CGSize advances[], const jint g_gvTXIndicesAsInts[], const jdouble g_gvTransformsAsDoubles[], const CFIndex length)
|
||||
{
|
||||
CGPoint pt = { 0, 0 };
|
||||
|
||||
@@ -137,49 +92,12 @@ void JavaCT_DrawGlyphVector
|
||||
CGContextRef cgRef = qsdo->cgRef;
|
||||
CGAffineTransform ctmText = CGContextGetTextMatrix(cgRef);
|
||||
|
||||
BOOL saved = false;
|
||||
|
||||
CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx);
|
||||
|
||||
NSInteger i;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
CGGlyph glyph = glyphs[i];
|
||||
int uniChar = uniChars[i];
|
||||
// if we found a unichar instead of a glyph code, get the fallback font,
|
||||
// find the glyph code for the fallback font, and set the font on the current context
|
||||
if (uniChar != 0)
|
||||
{
|
||||
CTFontRef fallback;
|
||||
if (uniChar > 0xFFFF) {
|
||||
UTF16Char charRef[2];
|
||||
JavaCT_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
|
||||
CGGlyph glyphTmp[2];
|
||||
fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
|
||||
glyph = glyphTmp[0];
|
||||
} else {
|
||||
const UTF16Char u = uniChar;
|
||||
fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, &u, (CGGlyph *)&glyph, 1);
|
||||
}
|
||||
if (fallback) {
|
||||
const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
|
||||
CFRelease(fallback);
|
||||
|
||||
if (cgFallback) {
|
||||
if (!saved) {
|
||||
CGContextSaveGState(cgRef);
|
||||
saved = true;
|
||||
}
|
||||
CGContextSetFont(cgRef, cgFallback);
|
||||
CFRelease(cgFallback);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (saved) {
|
||||
CGContextRestoreGState(cgRef);
|
||||
saved = false;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have per-glyph transformations
|
||||
int tin = (g_gvTXIndicesAsInts == NULL) ? -1 : (g_gvTXIndicesAsInts[i] - 1) * 6;
|
||||
@@ -214,10 +132,6 @@ void JavaCT_DrawGlyphVector
|
||||
pt.y += advances[i].height;
|
||||
|
||||
}
|
||||
// reset the font on the context after striking a unicode with CoreText
|
||||
if (saved) {
|
||||
CGContextRestoreGState(cgRef);
|
||||
}
|
||||
}
|
||||
|
||||
// Using the Quartz Surface Data context, draw a hot-substituted character run
|
||||
@@ -327,24 +241,16 @@ static jclass jc_StandardGlyphVector = NULL;
|
||||
// Checks the GlyphVector Java object for any transforms that were applied to individual characters. If none are present,
|
||||
// strike the glyphs immediately in Core Graphics. Otherwise, obtain the arrays, and defer to above.
|
||||
static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, BOOL useSubstituion, int *uniChars, CGGlyph *glyphs, CGSize *advances, size_t length)
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, CGSize *advances, size_t length)
|
||||
{
|
||||
// if we have no character substitution, and no per-glyph transformations - strike now!
|
||||
// if we have no per-glyph transformations - strike now!
|
||||
GET_SGV_CLASS();
|
||||
DECLARE_FIELD(jm_StandardGlyphVector_gti, jc_StandardGlyphVector, "gti", "Lsun/font/StandardGlyphVector$GlyphTransformInfo;");
|
||||
jobject gti = (*env)->GetObjectField(env, gVector, jm_StandardGlyphVector_gti);
|
||||
if (gti == 0)
|
||||
{
|
||||
if (useSubstituion)
|
||||
{
|
||||
// quasi-simple case, substitution, but no per-glyph transforms
|
||||
JavaCT_DrawGlyphVector(qsdo, strike, TRUE, uniChars, glyphs, advances, NULL, NULL, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fast path, straight to CG without per-glyph transforms
|
||||
CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
|
||||
}
|
||||
// fast path, straight to CG without per-glyph transforms
|
||||
CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -369,8 +275,8 @@ static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
|
||||
(*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
|
||||
return;
|
||||
}
|
||||
// slowest case, we have per-glyph transforms, and possibly glyph substitution as well
|
||||
JavaCT_DrawGlyphVector(qsdo, strike, useSubstituion, uniChars, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
|
||||
// slowest case, we have per-glyph transforms
|
||||
JavaCT_DrawGlyphVector(qsdo, strike, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
|
||||
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, g_gtiTXIndicesArray, g_gvTXIndicesAsInts, JNI_ABORT);
|
||||
@@ -379,35 +285,11 @@ static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
|
||||
(*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
|
||||
}
|
||||
|
||||
// Retrieves advances for translated unicodes
|
||||
// Uses "glyphs" as a temporary buffer for the glyph-to-unicode translation
|
||||
void JavaCT_GetAdvancesForUnichars
|
||||
(const NSFont *font, const int uniChars[], CGGlyph glyphs[], const size_t length, CGSize advances[])
|
||||
{
|
||||
// cycle over each spot, and if we discovered a unicode to substitute, we have to calculate the advance for it
|
||||
size_t i;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
UniChar uniChar = uniChars[i];
|
||||
if (uniChar == 0) continue;
|
||||
|
||||
CGGlyph glyph = 0;
|
||||
const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font, &uniChar, 1);
|
||||
if (fallback) {
|
||||
CTFontGetGlyphsForCharacters(fallback, &uniChar, &glyph, 1);
|
||||
CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &(advances[i]), 1);
|
||||
CFRelease(fallback);
|
||||
}
|
||||
|
||||
glyphs[i] = glyph;
|
||||
}
|
||||
}
|
||||
|
||||
// Fills the glyph buffer with glyphs from the GlyphVector object. Also checks to see if the glyph's positions have been
|
||||
// already caculated from GlyphVector, or we simply ask Core Graphics to make some advances for us. Pre-calculated positions
|
||||
// are translated into advances, since CG only understands advances.
|
||||
static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, int *uniChars, CGSize *advances, size_t length, jintArray glyphsArray)
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, CGSize *advances, size_t length, jintArray glyphsArray)
|
||||
{
|
||||
// fill the glyph buffer
|
||||
jint *glyphsAsInts = (*env)->GetPrimitiveArrayCritical(env, glyphsArray, NULL);
|
||||
@@ -415,24 +297,10 @@ static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
|
||||
return;
|
||||
}
|
||||
|
||||
// if a glyph code from Java is negative, that means it is really a unicode value
|
||||
// which we can use in CoreText to strike the character in another font
|
||||
size_t i;
|
||||
BOOL complex = NO;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
jint code = glyphsAsInts[i];
|
||||
if (code < 0)
|
||||
{
|
||||
complex = YES;
|
||||
uniChars[i] = -code;
|
||||
glyphs[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uniChars[i] = 0;
|
||||
glyphs[i] = code;
|
||||
}
|
||||
glyphs[i] = glyphsAsInts[i];
|
||||
}
|
||||
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, glyphsArray, glyphsAsInts, JNI_ABORT);
|
||||
@@ -483,15 +351,10 @@ static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
|
||||
// there were no pre-calculated positions from the glyph buffer on the Java side
|
||||
AWTFont *awtFont = strike->fAWTFont;
|
||||
CTFontGetAdvancesForGlyphs((CTFontRef)awtFont->fFont, kCTFontDefaultOrientation, glyphs, advances, length);
|
||||
|
||||
if (complex)
|
||||
{
|
||||
JavaCT_GetAdvancesForUnichars(awtFont->fFont, uniChars, glyphs, length, advances);
|
||||
}
|
||||
}
|
||||
|
||||
// continue on to the next stage of the pipe
|
||||
doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, complex, uniChars, glyphs, advances, length);
|
||||
doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, glyphs, advances, length);
|
||||
}
|
||||
|
||||
// Obtains the glyph array to determine the number of glyphs we are dealing with. If we are dealing a large number of glyphs,
|
||||
@@ -515,18 +378,16 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
|
||||
{
|
||||
// if we are small enough, fit everything onto the stack
|
||||
CGGlyph glyphs[length];
|
||||
int uniChars[length];
|
||||
CGSize advances[length];
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, advances, length, glyphsArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, we should malloc and free buffers for this large run
|
||||
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);
|
||||
int *uniChars = (int *)malloc(sizeof(int) * length);
|
||||
CGSize *advances = (CGSize *)malloc(sizeof(CGSize) * length);
|
||||
|
||||
if (glyphs == NULL || uniChars == NULL || advances == NULL)
|
||||
if (glyphs == NULL || advances == NULL)
|
||||
{
|
||||
(*env)->DeleteLocalRef(env, glyphsArray);
|
||||
[NSException raise:NSMallocException format:@"%s-%s:%d", __FILE__, __FUNCTION__, __LINE__];
|
||||
@@ -534,10 +395,6 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
|
||||
{
|
||||
free(glyphs);
|
||||
}
|
||||
if (uniChars)
|
||||
{
|
||||
free(uniChars);
|
||||
}
|
||||
if (advances)
|
||||
{
|
||||
free(advances);
|
||||
@@ -545,10 +402,9 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
|
||||
return;
|
||||
}
|
||||
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, advances, length, glyphsArray);
|
||||
|
||||
free(glyphs);
|
||||
free(uniChars);
|
||||
free(advances);
|
||||
}
|
||||
|
||||
|
||||
@@ -1008,7 +1008,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
point.y += size.height;
|
||||
|
||||
// Now make it into Cocoa screen coords.
|
||||
point.y = [[[[self view] window] screen] frame].size.height - point.y;
|
||||
point.y = [[NSScreen screens][0] frame].size.height - point.y;
|
||||
|
||||
return [NSValue valueWithPoint:point];
|
||||
}
|
||||
@@ -1385,7 +1385,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
"(Ljava/awt/Container;FF)Ljavax/accessibility/Accessible;", nil);
|
||||
|
||||
// Make it into java screen coords
|
||||
point.y = [[[[self view] window] screen] frame].size.height - point.y;
|
||||
point.y = [[NSScreen screens][0] frame].size.height - point.y;
|
||||
|
||||
jobject jparent = fComponent;
|
||||
|
||||
|
||||
@@ -83,10 +83,11 @@ static NSString* uiBoldName = nil;
|
||||
(uiBoldName != nil && [name isEqualTo:uiBoldName])) {
|
||||
if (style & java_awt_Font_BOLD) {
|
||||
nsFont = [NSFont boldSystemFontOfSize:1.0];
|
||||
nsFallbackBase = [NSFont fontWithName:@"LucidaGrande-Bold" size:1.0];
|
||||
} else {
|
||||
nsFont = [NSFont systemFontOfSize:1.0];
|
||||
nsFallbackBase = [NSFont fontWithName:@"LucidaGrande" size:1.0];
|
||||
}
|
||||
nsFallbackBase = [NSFont fontWithName:@"Lucida Grande" size:1.0];
|
||||
#ifdef DEBUG
|
||||
NSLog(@"nsFont-name is : %@", nsFont.familyName);
|
||||
NSLog(@"nsFont-family is : %@", nsFont.fontName);
|
||||
@@ -3341,6 +3342,64 @@ Java_sun_awt_FontDescriptor_initIDs
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Class: sun_font_CFont
|
||||
* Method: getCascadeList
|
||||
* Signature: (JLjava/util/ArrayList;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_font_CFont_getCascadeList
|
||||
(JNIEnv *env, jclass cls, jlong awtFontPtr, jobject arrayListOfString)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
jclass alc = (*env)->FindClass(env, "java/util/ArrayList");
|
||||
if (alc == NULL) return;
|
||||
jmethodID addMID = (*env)->GetMethodID(env, alc, "add", "(Ljava/lang/Object;)Z");
|
||||
if (addMID == NULL) return;
|
||||
|
||||
CFIndex i;
|
||||
AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
|
||||
NSFont* nsFont = awtFont->fFont;
|
||||
#ifdef DEBUG
|
||||
CFStringRef base = CTFontCopyFullName((CTFontRef)nsFont);
|
||||
NSLog(@"BaseFont is : %@", (NSString*)base);
|
||||
CFRelease(base);
|
||||
#endif
|
||||
bool anotherBaseFont = false;
|
||||
if (awtFont->fFallbackBase != nil) {
|
||||
nsFont = awtFont->fFallbackBase;
|
||||
anotherBaseFont = true;
|
||||
}
|
||||
CTFontRef font = (CTFontRef)nsFont;
|
||||
CFArrayRef codes = CFLocaleCopyISOLanguageCodes();
|
||||
|
||||
CFArrayRef fds = CTFontCopyDefaultCascadeListForLanguages(font, codes);
|
||||
CFRelease(codes);
|
||||
CFIndex cnt = CFArrayGetCount(fds);
|
||||
for (i= anotherBaseFont ? -1 : 0; i<cnt; i++) {
|
||||
CFStringRef fontname;
|
||||
if (i < 0) {
|
||||
fontname = CTFontCopyPostScriptName(font);
|
||||
} else {
|
||||
CTFontDescriptorRef ref = CFArrayGetValueAtIndex(fds, i);
|
||||
fontname = CTFontDescriptorCopyAttribute(ref, kCTFontNameAttribute);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
NSLog(@"Font is : %@", (NSString*)fontname);
|
||||
#endif
|
||||
jstring jFontName = (jstring)NSStringToJavaString(env, fontname);
|
||||
CFRelease(fontname);
|
||||
(*env)->CallBooleanMethod(env, arrayListOfString, addMID, jFontName);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
CFRelease(fds);
|
||||
return;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, jFontName);
|
||||
}
|
||||
CFRelease(fds);
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
static CFStringRef EMOJI_FONT_NAME = CFSTR("Apple Color Emoji");
|
||||
|
||||
bool IsEmojiFont(CTFontRef font)
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#import "sun_font_CStrikeDisposer.h"
|
||||
#import "CGGlyphImages.h"
|
||||
#import "CGGlyphOutlines.h"
|
||||
#import "CoreTextSupport.h"
|
||||
#import "JNIUtilities.h"
|
||||
#include "fontscalerdefs.h"
|
||||
#import "LWCToolkit.h"
|
||||
@@ -160,12 +159,8 @@ JNI_COCOA_ENTER(env);
|
||||
AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
|
||||
AWTFont *awtFont = awtStrike->fAWTFont;
|
||||
|
||||
// negative glyph codes are really unicodes, which were placed there by the mapper
|
||||
// to indicate we should use CoreText to substitute the character
|
||||
CGGlyph glyph;
|
||||
const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &awtStrike->fAltTx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, NULL, &advance, IS_OSX_GT10_14);
|
||||
CFRelease(fallback);
|
||||
CGGlyph glyph = glyphCode;
|
||||
CGGlyphImages_GetGlyphMetrics((CTFontRef)awtFont->fFont, &awtStrike->fAltTx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, NULL, &advance, IS_OSX_GT10_14);
|
||||
advance = CGSizeApplyAffineTransform(advance, awtStrike->fFontTx);
|
||||
if (!JRSFontStyleUsesFractionalMetrics(awtStrike->fStyle)) {
|
||||
advance.width = round(advance.width);
|
||||
@@ -195,14 +190,9 @@ JNI_COCOA_ENTER(env);
|
||||
tx.tx += x;
|
||||
tx.ty += y;
|
||||
|
||||
// negative glyph codes are really unicodes, which were placed there by the mapper
|
||||
// to indicate we should use CoreText to substitute the character
|
||||
CGGlyph glyph;
|
||||
const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
|
||||
|
||||
CGGlyph glyph = glyphCode;
|
||||
CGRect bbox;
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &tx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, &bbox, NULL, IS_OSX_GT10_14);
|
||||
CFRelease(fallback);
|
||||
CGGlyphImages_GetGlyphMetrics((CTFontRef)awtFont->fFont, &tx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, &bbox, NULL, IS_OSX_GT10_14);
|
||||
|
||||
// the origin of this bounding box is relative to the bottom-left corner baseline
|
||||
CGFloat decender = -bbox.origin.y;
|
||||
@@ -251,14 +241,12 @@ AWT_FONT_CLEANUP_CHECK(awtfont);
|
||||
tx.tx += xPos;
|
||||
tx.ty += yPos;
|
||||
|
||||
// get the right font and glyph for this "Java GlyphCode"
|
||||
|
||||
CGGlyph glyph;
|
||||
const CTFontRef font = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtfont, glyphCode, &glyph);
|
||||
CGGlyph glyph = glyphCode;
|
||||
NSFont *font = awtfont->fFont;
|
||||
|
||||
// get the advance of this glyph
|
||||
CGSize advance;
|
||||
CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, &glyph, &advance, 1);
|
||||
CTFontGetAdvancesForGlyphs((CTFontRef)font, kCTFontDefaultOrientation, &glyph, &advance, 1);
|
||||
|
||||
// Create AWTPath
|
||||
path = AWTPathCreate(CGSizeMake(xPos, yPos));
|
||||
@@ -267,8 +255,7 @@ AWT_FONT_CLEANUP_CHECK(path);
|
||||
// Get the paths
|
||||
tx = awtStrike->fTx;
|
||||
tx = CGAffineTransformConcat(tx, sInverseTX);
|
||||
AWTGetGlyphOutline(&glyph, (NSFont *)font, &advance, &tx, 0, 1, &path);
|
||||
CFRelease(font);
|
||||
AWTGetGlyphOutline(&glyph, font, &advance, &tx, 0, 1, &path);
|
||||
|
||||
pointCoords = (*env)->NewFloatArray(env, path->fNumberOfDataElements);
|
||||
AWT_FONT_CLEANUP_CHECK(pointCoords);
|
||||
@@ -322,19 +309,14 @@ JNIEXPORT void JNICALL Java_sun_font_CStrike_getNativeGlyphOutlineBounds
|
||||
AWT_FONT_CLEANUP_SETUP;
|
||||
AWT_FONT_CLEANUP_CHECK(awtfont);
|
||||
|
||||
// get the right font and glyph for this "Java GlyphCode"
|
||||
CGGlyph glyph;
|
||||
const CTFontRef font = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(
|
||||
awtfont, glyphCode, &glyph);
|
||||
|
||||
CGGlyph glyph = glyphCode;
|
||||
CGRect bbox = CTFontGetBoundingRectsForGlyphs(
|
||||
font, kCTFontOrientationDefault, &glyph, NULL, 1);
|
||||
(CTFontRef)awtfont->fFont, kCTFontOrientationDefault, &glyph, NULL, 1);
|
||||
|
||||
CGAffineTransform tx = CGAffineTransformConcat(awtStrike->fTx,
|
||||
sInverseTX);
|
||||
|
||||
bbox = CGRectApplyAffineTransform (bbox, tx);
|
||||
CFRelease(font);
|
||||
jfloat *rawRectData =
|
||||
(*env)->GetPrimitiveArrayCritical(env, rectData, NULL);
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#import "CoreTextSupport.h"
|
||||
|
||||
#import "sun_font_CCharToGlyphMapper.h"
|
||||
#import "sun_font_CCompositeGlyphMapper.h"
|
||||
|
||||
/*
|
||||
* Class: sun_font_CCharToGlyphMapper
|
||||
@@ -114,28 +113,3 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_font_CCompositeGlyphMapper
|
||||
* Method: nativeCodePointToGlyph
|
||||
* Signature: (JI[Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_font_CCompositeGlyphMapper_nativeCodePointToGlyph
|
||||
(JNIEnv *env, jclass clazz, jlong awtFontPtr, jint codePoint, jobjectArray resultArray)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
|
||||
CFStringRef fontNames[] = {NULL, NULL};
|
||||
CGGlyph glyph = CTS_CopyGlyphAndFontNamesForCodePoint(awtFont, (UnicodeScalarValue)codePoint, fontNames);
|
||||
if (glyph > 0) {
|
||||
jstring fontName = NSStringToJavaString(env, (NSString *)fontNames[0]);
|
||||
(*env)->SetObjectArrayElement(env, resultArray, 0, fontName);
|
||||
jstring fontFamilyName = NSStringToJavaString(env, (NSString *)fontNames[1]);
|
||||
(*env)->SetObjectArrayElement(env, resultArray, 1, fontFamilyName);
|
||||
}
|
||||
if (fontNames[0]) CFRelease(fontNames[0]);
|
||||
if (fontNames[1]) CFRelease(fontNames[1]);
|
||||
return glyph;
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#import "JNIUtilities.h"
|
||||
#import "CGGlyphImages.h"
|
||||
#import "CoreTextSupport.h"
|
||||
#import "fontscalerdefs.h" // contains the definition of GlyphInfo struct
|
||||
|
||||
#import "sun_awt_SunHints.h"
|
||||
@@ -739,78 +738,6 @@ CGGI_CreateImageForGlyph
|
||||
/*
|
||||
* CoreText path...
|
||||
*/
|
||||
static inline GlyphInfo *
|
||||
CGGI_CreateImageForUnicode
|
||||
(CGGI_GlyphCanvas *canvas, const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode, const UnicodeScalarValue uniChar,
|
||||
const bool isCatalinaOrAbove)
|
||||
{
|
||||
// save the graphics state
|
||||
CGContextSaveGState(canvas->context);
|
||||
// text matrix is not considered part of graphics state
|
||||
CGAffineTransform originalTx = CGContextGetTextMatrix(canvas->context);
|
||||
|
||||
// get the glyph, measure it using CG
|
||||
CGGlyph glyph;
|
||||
CTFontRef fallback;
|
||||
if (uniChar > 0xFFFF) {
|
||||
UTF16Char charRef[2];
|
||||
CTS_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
|
||||
CGGlyph glyphTmp[2];
|
||||
fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
|
||||
glyph = glyphTmp[0];
|
||||
} else {
|
||||
UTF16Char charRef;
|
||||
charRef = (UTF16Char) uniChar; // truncate.
|
||||
fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, &glyph, 1);
|
||||
}
|
||||
|
||||
JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
|
||||
|
||||
CGGI_GlyphInfoDescriptor *glyphDescriptor = CGGI_GetGlyphInfoDescriptor(mode, fallback);
|
||||
|
||||
bool subpixelResolution = mode->subpixelResolution && glyphDescriptor == &grey;
|
||||
|
||||
CGRect bbox;
|
||||
CGSize advance;
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &strike->fTx, strike->fSize, style, &glyph, 1, &bbox, &advance, isCatalinaOrAbove);
|
||||
|
||||
|
||||
// create the Sun2D GlyphInfo we are going to strike into
|
||||
GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, glyphDescriptor, subpixelResolution);
|
||||
|
||||
// fix the context size, just in case the substituted character is unexpectedly large
|
||||
CGGI_SizeCanvas(canvas, info->width * info->subpixelResolutionX, info->height * info->subpixelResolutionY, mode);
|
||||
|
||||
// align the transform for the real CoreText strike
|
||||
CGContextSetTextMatrix(canvas->context, strike->fAltTx);
|
||||
|
||||
const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
|
||||
CGContextSetFont(canvas->context, cgFallback);
|
||||
CFRelease(cgFallback);
|
||||
|
||||
// clean the canvas - align, strike, and copy the glyph from the canvas into the info
|
||||
CGGI_CreateImageForGlyph(canvas, glyph, info, glyphDescriptor, strike, fallback, isCatalinaOrAbove);
|
||||
|
||||
// restore graphics state
|
||||
CGContextRestoreGState(canvas->context);
|
||||
CGContextSetTextMatrix(canvas->context, originalTx);
|
||||
|
||||
CFRelease(fallback);
|
||||
#ifdef CGGI_DEBUG
|
||||
DUMP_GLYPHINFO(info);
|
||||
#endif
|
||||
|
||||
#ifdef CGGI_DEBUG_DUMP
|
||||
DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
|
||||
#if 0
|
||||
PRINT_CGSTATES_INFO(NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark --- GlyphInfo Filling and Canvas Managment ---
|
||||
|
||||
@@ -825,7 +752,6 @@ CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
|
||||
const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
jlong glyphInfos[],
|
||||
const UnicodeScalarValue uniChars[],
|
||||
const CGGlyph glyphs[],
|
||||
const CFIndex len)
|
||||
{
|
||||
@@ -838,13 +764,8 @@ CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
|
||||
CFIndex i;
|
||||
for (i = 0; i < len; i++) {
|
||||
GlyphInfo *info = (GlyphInfo *)jlong_to_ptr(glyphInfos[i]);
|
||||
if (info != NULL) {
|
||||
CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode->mainFontDescriptor,
|
||||
strike, (CTFontRef)strike->fAWTFont->fFont, isMojaveOrAbove);
|
||||
} else {
|
||||
info = CGGI_CreateImageForUnicode(canvas, strike, mode, uniChars[i], isMojaveOrAbove);
|
||||
glyphInfos[i] = ptr_to_jlong(info);
|
||||
}
|
||||
CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode->mainFontDescriptor,
|
||||
strike, (CTFontRef)strike->fAWTFont->fFont, isMojaveOrAbove);
|
||||
#ifdef CGGI_DEBUG
|
||||
DUMP_GLYPHINFO(info);
|
||||
#endif
|
||||
@@ -879,7 +800,7 @@ static NSString *threadLocalLCDCanvasKey =
|
||||
static inline void
|
||||
CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
|
||||
const CGGlyph glyphs[],
|
||||
const size_t maxWidth, const size_t maxHeight,
|
||||
const CFIndex len)
|
||||
{
|
||||
@@ -889,8 +810,7 @@ CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
|
||||
CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode);
|
||||
CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
|
||||
mode, glyphInfos, uniChars,
|
||||
glyphs, len);
|
||||
mode, glyphInfos, glyphs, len);
|
||||
CGGI_FreeCanvas(tmpCanvas);
|
||||
|
||||
[tmpCanvas release];
|
||||
@@ -910,7 +830,7 @@ CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
|
||||
CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
|
||||
CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
|
||||
glyphInfos, uniChars, glyphs, len);
|
||||
glyphInfos, glyphs, len);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -926,7 +846,7 @@ CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
static inline void
|
||||
CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
|
||||
const CGGlyph glyphs[],
|
||||
CGSize advances[], CGRect bboxes[], const CFIndex len)
|
||||
{
|
||||
AWTFont *font = strike->fAWTFont;
|
||||
@@ -941,12 +861,6 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
CFIndex i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (uniChars[i] != 0)
|
||||
{
|
||||
glyphInfos[i] = 0L;
|
||||
continue; // will be handled later
|
||||
}
|
||||
|
||||
CGSize advance = advances[i];
|
||||
CGRect bbox = bboxes[i];
|
||||
|
||||
@@ -963,41 +877,29 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
glyphInfos[i] = ptr_to_jlong(glyphInfo);
|
||||
}
|
||||
|
||||
CGGI_FillImagesForGlyphs(glyphInfos, strike, mode, uniChars,
|
||||
CGGI_FillImagesForGlyphs(glyphInfos, strike, mode,
|
||||
glyphs, maxWidth, maxHeight, len);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark --- Temporary Buffer Allocations and Initialization ---
|
||||
|
||||
/*
|
||||
* This stage separates the already valid glyph codes from the unicode values
|
||||
* that need special handling - the rawGlyphCodes array is no longer used
|
||||
* after this stage.
|
||||
*/
|
||||
static void
|
||||
CGGI_CreateGlyphsAndScanForComplexities(jlong *glyphInfos,
|
||||
const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
jint rawGlyphCodes[],
|
||||
UnicodeScalarValue uniChars[], CGGlyph glyphs[],
|
||||
CGSize advances[], CGRect bboxes[],
|
||||
const CFIndex len)
|
||||
CGGI_CreateGlyphs(jlong *glyphInfos,
|
||||
const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
jint rawGlyphCodes[],
|
||||
CGGlyph glyphs[],
|
||||
CGSize advances[], CGRect bboxes[],
|
||||
const CFIndex len)
|
||||
{
|
||||
CFIndex i;
|
||||
for (i = 0; i < len; i++) {
|
||||
jint code = rawGlyphCodes[i];
|
||||
if (code < 0) {
|
||||
glyphs[i] = 0;
|
||||
uniChars[i] = -code;
|
||||
} else {
|
||||
glyphs[i] = code;
|
||||
uniChars[i] = 0;
|
||||
}
|
||||
glyphs[i] = rawGlyphCodes[i];
|
||||
}
|
||||
|
||||
CGGI_CreateGlyphInfos(glyphInfos, strike, mode,
|
||||
uniChars, glyphs, advances, bboxes, len);
|
||||
glyphs, advances, bboxes, len);
|
||||
|
||||
#ifdef CGGI_DEBUG_HIT_COUNT
|
||||
static size_t hitCount = 0;
|
||||
@@ -1023,31 +925,29 @@ CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
|
||||
CGRect bboxes[len];
|
||||
CGSize advances[len];
|
||||
CGGlyph glyphs[len];
|
||||
UnicodeScalarValue uniChars[len];
|
||||
|
||||
CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, uniChars, glyphs,
|
||||
advances, bboxes, len);
|
||||
CGGI_CreateGlyphs(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, glyphs,
|
||||
advances, bboxes, len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// just do one malloc, and carve it up for all the buffers
|
||||
void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
|
||||
sizeof(CGGlyph) * sizeof(UnicodeScalarValue) * len);
|
||||
void *buffer = malloc((sizeof(CGRect) + sizeof(CGSize) + sizeof(CGGlyph)) *
|
||||
len);
|
||||
if (buffer == NULL) {
|
||||
[[NSException exceptionWithName:NSMallocException
|
||||
reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
|
||||
}
|
||||
|
||||
CGRect *bboxes = (CGRect *)(buffer);
|
||||
CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
|
||||
CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
|
||||
UnicodeScalarValue *uniChars = (UnicodeScalarValue *)(glyphs + sizeof(UnicodeScalarValue) * len);
|
||||
CGSize *advances = (CGSize *)(bboxes + len);
|
||||
CGGlyph *glyphs = (CGGlyph *)(advances + len);
|
||||
|
||||
CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, uniChars, glyphs,
|
||||
advances, bboxes, len);
|
||||
CGGI_CreateGlyphs(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, glyphs,
|
||||
advances, bboxes, len);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
@@ -31,37 +31,13 @@
|
||||
|
||||
#pragma mark --- CoreText Support ---
|
||||
|
||||
#define HI_SURROGATE_START 0xD800
|
||||
#define HI_SURROGATE_END 0xDBFF
|
||||
#define LO_SURROGATE_START 0xDC00
|
||||
#define LO_SURROGATE_END 0xDFFF
|
||||
|
||||
/*
|
||||
* Transform Unicode characters into glyphs.
|
||||
*
|
||||
* Fills the "glyphsAsInts" array with the glyph codes for the current font,
|
||||
* or the negative unicode value if we know the character can be hot-substituted.
|
||||
*
|
||||
* This is the heart of "Universal Font Substitution" in Java.
|
||||
* Fills the "glyphsAsInts" array with the glyph codes for the current font.
|
||||
*/
|
||||
void CTS_GetGlyphsAsIntsForCharacters(const AWTFont *font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[], const size_t count);
|
||||
|
||||
// Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
|
||||
// Returns the substituted font, and places the appropriate glyph into "glyph"
|
||||
CTFontRef CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef);
|
||||
|
||||
// Translates a Unicode into a CGGlyph/CTFontRef pair
|
||||
// Returns the substituted font, and places the appropriate glyph into "glyphRef"
|
||||
CTFontRef CTS_CopyCTFallbackFontAndGlyphForUnicode(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count);
|
||||
|
||||
// Transform a single Unicode character code into glyph code.
|
||||
// Names of the relevant font are also returned, if the substitution is used.
|
||||
// Non-null components of fontNames array should always be released by the calling code, regardless of the returned value.
|
||||
CGGlyph CTS_CopyGlyphAndFontNamesForCodePoint(const AWTFont *font, const UnicodeScalarValue codePoint, CFStringRef fontNames[]);
|
||||
|
||||
// Breakup a 32 bit unicode value into the component surrogate pairs
|
||||
void CTS_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]);
|
||||
|
||||
|
||||
// Basic struct that holds everything CoreText is interested in
|
||||
typedef struct CTS_ProviderStruct {
|
||||
|
||||
@@ -88,161 +88,18 @@ ReleaseCTStateDictionary(CFDictionaryRef ctStateDict)
|
||||
CFRelease(ctStateDict); // GC
|
||||
}
|
||||
|
||||
void GetFontsAndGlyphsForCharacters(CTFontRef font, CTFontRef fallbackBase,
|
||||
const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[],
|
||||
CTFontRef actualFonts[], const size_t count)
|
||||
{
|
||||
CTFontGetGlyphsForCharacters(font, unicodes, glyphs, count);
|
||||
if (!fallbackBase) fallbackBase = font;
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
UniChar unicode = unicodes[i];
|
||||
UniChar nextUnicode = (i+1) < count ? unicodes[i+1] : 0;
|
||||
bool surrogatePair = unicode >= HI_SURROGATE_START && unicode <= HI_SURROGATE_END
|
||||
&& nextUnicode >= LO_SURROGATE_START && nextUnicode <= LO_SURROGATE_END;
|
||||
|
||||
CGGlyph glyph = glyphs[i];
|
||||
if (glyph > 0) {
|
||||
glyphsAsInts[i] = glyph;
|
||||
if (surrogatePair) i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters(fallbackBase, &unicodes[i], surrogatePair ? 2 : 1);
|
||||
if (fallback) {
|
||||
CTFontGetGlyphsForCharacters(fallback, &unicodes[i], &glyphs[i], surrogatePair ? 2 : 1);
|
||||
glyph = glyphs[i];
|
||||
if (actualFonts && glyph > 0) {
|
||||
actualFonts[i] = fallback;
|
||||
} else {
|
||||
CFRelease(fallback);
|
||||
}
|
||||
}
|
||||
|
||||
if (glyph > 0) {
|
||||
int codePoint = surrogatePair ? (((int)(unicode - HI_SURROGATE_START)) << 10)
|
||||
+ nextUnicode - LO_SURROGATE_START + 0x10000 : unicode;
|
||||
glyphsAsInts[i] = -codePoint; // set the glyph code to the negative unicode value
|
||||
} else {
|
||||
glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either
|
||||
}
|
||||
if (surrogatePair) i++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform Unicode characters into glyphs.
|
||||
*
|
||||
* Fills the "glyphsAsInts" array with the glyph codes for the current font,
|
||||
* or the negative unicode value if we know the character can be hot-substituted.
|
||||
*
|
||||
* This is the heart of "Universal Font Substitution" in Java.
|
||||
* Fills the "glyphsAsInts" array with the glyph codes for the current font.
|
||||
*/
|
||||
void CTS_GetGlyphsAsIntsForCharacters
|
||||
(const AWTFont *font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[], const size_t count)
|
||||
{
|
||||
GetFontsAndGlyphsForCharacters((CTFontRef)font->fFont, (CTFontRef)font->fFallbackBase,
|
||||
unicodes, glyphs, glyphsAsInts, NULL, count);
|
||||
}
|
||||
CTFontGetGlyphsForCharacters((CTFontRef)font->fFont, unicodes, glyphs, count);
|
||||
|
||||
/*
|
||||
* Returns glyph code for a given Unicode character.
|
||||
* Names of the corresponding substituted font are also returned if substitution is performed.
|
||||
*/
|
||||
CGGlyph CTS_CopyGlyphAndFontNamesForCodePoint
|
||||
(const AWTFont *font, const UnicodeScalarValue codePoint, CFStringRef fontNames[])
|
||||
{
|
||||
CTFontRef fontRef = (CTFontRef)font->fFont;
|
||||
CTFontRef fallbackBase = (CTFontRef)font->fFallbackBase;
|
||||
int count = codePoint >= 0x10000 ? 2 : 1;
|
||||
UTF16Char unicodes[count];
|
||||
if (count == 1) {
|
||||
unicodes[0] = (UTF16Char)codePoint;
|
||||
} else {
|
||||
CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, unicodes);
|
||||
}
|
||||
CGGlyph glyphs[count];
|
||||
jint glyphsAsInts[count];
|
||||
CTFontRef actualFonts[count];
|
||||
GetFontsAndGlyphsForCharacters(fontRef, fallbackBase, unicodes, glyphs, glyphsAsInts, actualFonts, count);
|
||||
CGGlyph glyph = glyphs[0];
|
||||
bool substitutionHappened = glyphsAsInts[0] < 0;
|
||||
if (glyph > 0 && substitutionHappened) {
|
||||
CTFontRef actualFont = actualFonts[0];
|
||||
CFStringRef fontName = CTFontCopyPostScriptName(actualFont);
|
||||
CFStringRef familyName = CTFontCopyFamilyName(actualFont);
|
||||
CFRelease(actualFont);
|
||||
fontNames[0] = fontName;
|
||||
fontNames[1] = familyName;
|
||||
if (!fontName || !familyName) glyph = 0;
|
||||
}
|
||||
return glyph;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translates a Unicode into a CGGlyph/CTFontRef pair
|
||||
* Returns the substituted font, and places the appropriate glyph into "glyphRef"
|
||||
*/
|
||||
CTFontRef CTS_CopyCTFallbackFontAndGlyphForUnicode
|
||||
(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {
|
||||
CTFontRef primary = (CTFontRef)font->fFont;
|
||||
CTFontRef fallbackBase = (CTFontRef)font->fFallbackBase;
|
||||
if (fallbackBase) {
|
||||
CTFontGetGlyphsForCharacters(primary, charRef, glyphRef, count);
|
||||
if (glyphRef[0] > 0) {
|
||||
CFRetain(primary);
|
||||
return primary;
|
||||
}
|
||||
} else {
|
||||
fallbackBase = primary;
|
||||
}
|
||||
CTFontRef fallback = JRSFontCreateFallbackFontForCharacters(fallbackBase, charRef, count);
|
||||
if (fallback == NULL)
|
||||
{
|
||||
// use the original font if we somehow got duped into trying to fallback something we can't
|
||||
fallback = (CTFontRef)font->fFont;
|
||||
CFRetain(fallback);
|
||||
}
|
||||
|
||||
CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
|
||||
* Returns the substituted font, and places the appropriate glyph into "glyphRef"
|
||||
*/
|
||||
CTFontRef CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode
|
||||
(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef)
|
||||
{
|
||||
// negative glyph codes are really unicodes, which were placed there by the mapper
|
||||
// to indicate we should use CoreText to substitute the character
|
||||
if (glyphCode >= 0)
|
||||
{
|
||||
*glyphRef = glyphCode;
|
||||
CFRetain(font->fFont);
|
||||
return (CTFontRef)font->fFont;
|
||||
}
|
||||
|
||||
int codePoint = -glyphCode;
|
||||
if (codePoint >= 0x10000) {
|
||||
UTF16Char chars[2];
|
||||
CGGlyph glyphs[2];
|
||||
CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, chars);
|
||||
CTFontRef result = CTS_CopyCTFallbackFontAndGlyphForUnicode(font, chars, glyphs, 2);
|
||||
*glyphRef = glyphs[0];
|
||||
return result;
|
||||
} else {
|
||||
UTF16Char character = codePoint;
|
||||
return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
glyphsAsInts[i] = glyphs[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Breakup a 32 bit unicode value into the component surrogate pairs
|
||||
void CTS_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) {
|
||||
int value = uniChar - 0x10000;
|
||||
UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START;
|
||||
UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START;
|
||||
charRef[0] = high_surrogate;
|
||||
charRef[1] = low_surrogate;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ static jint vertexCacheIndex = 0;
|
||||
|
||||
static MTLPooledTextureHandle * maskCacheTex = NULL;
|
||||
static jint maskCacheIndex = 0;
|
||||
static bool gammaCorrection = NO;
|
||||
static id<MTLRenderCommandEncoder> encoder = NULL;
|
||||
|
||||
#define MTLVC_ADD_VERTEX(TX, TY, DX, DY, DZ) \
|
||||
@@ -144,9 +143,12 @@ MTLVertexCache_InitMaskCache(MTLContext *mtlc) {
|
||||
}
|
||||
// init special fully opaque tile in the upper-right corner of
|
||||
// the mask cache texture
|
||||
|
||||
char tile[MTLVC_MASK_CACHE_TILE_SIZE];
|
||||
memset(tile, 0xff, MTLVC_MASK_CACHE_TILE_SIZE);
|
||||
static char tile[MTLVC_MASK_CACHE_TILE_SIZE];
|
||||
static char* pTile = NULL;
|
||||
if (!pTile) {
|
||||
memset(tile, 0xff, MTLVC_MASK_CACHE_TILE_SIZE);
|
||||
pTile = tile;
|
||||
}
|
||||
|
||||
jint texx = MTLVC_MASK_CACHE_TILE_WIDTH * (MTLVC_MASK_CACHE_WIDTH_IN_TILES - 1);
|
||||
|
||||
@@ -183,7 +185,7 @@ MTLVertexCache_EnableMaskCache(MTLContext *mtlc, BMTLSDOps *dstOps)
|
||||
return;
|
||||
}
|
||||
}
|
||||
MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps, gammaCorrection);
|
||||
MTLVertexCache_CreateSamplingEncoder(mtlc, dstOps, NO);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -195,7 +197,6 @@ MTLVertexCache_DisableMaskCache(MTLContext *mtlc)
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_DisableMaskCache");
|
||||
MTLVertexCache_FlushVertexCache(mtlc);
|
||||
maskCacheIndex = 0;
|
||||
gammaCorrection = NO;
|
||||
free(vertexCache);
|
||||
vertexCache = NULL;
|
||||
}
|
||||
@@ -203,7 +204,6 @@ MTLVertexCache_DisableMaskCache(MTLContext *mtlc)
|
||||
void
|
||||
MTLVertexCache_CreateSamplingEncoder(MTLContext *mtlc, BMTLSDOps *dstOps, bool gmc) {
|
||||
J2dTraceLn(J2D_TRACE_INFO, "MTLVertexCache_CreateSamplingEncoder");
|
||||
gammaCorrection = gmc;
|
||||
encoder = [mtlc.encoderManager getTextEncoder:dstOps
|
||||
isSrcOpaque:NO
|
||||
gammaCorrection:gmc];
|
||||
|
||||
@@ -67,6 +67,7 @@ import sun.font.FontDesignMetrics;
|
||||
import sun.font.FontLineMetrics;
|
||||
import sun.font.FontManager;
|
||||
import sun.font.FontManagerFactory;
|
||||
import sun.font.FontSubstitution;
|
||||
import sun.font.FontUtilities;
|
||||
import sun.font.GlyphLayout;
|
||||
import sun.font.StandardGlyphVector;
|
||||
@@ -266,6 +267,11 @@ public class Font implements java.io.Serializable
|
||||
return font.getFont2D();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font2D getFont2DWithSubstitution(Font font) {
|
||||
return font.getFont2DWithSubstitution();
|
||||
}
|
||||
|
||||
public void setFont2D(Font font, Font2DHandle handle) {
|
||||
font.font2DHandle = handle;
|
||||
}
|
||||
@@ -537,6 +543,11 @@ public class Font implements java.io.Serializable
|
||||
return font2DHandle.font2D;
|
||||
}
|
||||
|
||||
private Font2D getFont2DWithSubstitution() {
|
||||
Font2D font2D = getFont2D();
|
||||
return font2D instanceof FontSubstitution ? ((FontSubstitution) font2D).getCompositeFont2D() : font2D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code Font} from the specified name, style and
|
||||
* point size.
|
||||
@@ -2223,7 +2234,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public boolean canDisplay(char c){
|
||||
return getFont2D().canDisplay(c);
|
||||
return getFont2DWithSubstitution().canDisplay(c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2244,7 +2255,7 @@ public class Font implements java.io.Serializable
|
||||
throw new IllegalArgumentException("invalid code point: " +
|
||||
Integer.toHexString(codePoint));
|
||||
}
|
||||
return getFont2D().canDisplay(codePoint);
|
||||
return getFont2DWithSubstitution().canDisplay(codePoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2265,7 +2276,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public int canDisplayUpTo(String str) {
|
||||
Font2D font2d = getFont2D();
|
||||
Font2D font2d = getFont2DWithSubstitution();
|
||||
int len = str.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = str.charAt(i);
|
||||
@@ -2303,7 +2314,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public int canDisplayUpTo(char[] text, int start, int limit) {
|
||||
Font2D font2d = getFont2D();
|
||||
Font2D font2d = getFont2DWithSubstitution();
|
||||
for (int i = start; i < limit; i++) {
|
||||
char c = text[i];
|
||||
if (font2d.canDisplay(c)) {
|
||||
@@ -2338,7 +2349,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
|
||||
Font2D font2d = getFont2D();
|
||||
Font2D font2d = getFont2DWithSubstitution();
|
||||
char c = iter.setIndex(start);
|
||||
for (int i = start; i < limit; i++, c = iter.next()) {
|
||||
if (font2d.canDisplay(c)) {
|
||||
|
||||
@@ -38,7 +38,7 @@ import java.awt.Font;
|
||||
* But its probably OK to include it so long as only composites include
|
||||
* fallbacks. If physicals do then it would be really confusing ..
|
||||
*/
|
||||
public class CompositeFont extends Font2D {
|
||||
public final class CompositeFont extends Font2D {
|
||||
|
||||
private boolean[] deferredInitialisation;
|
||||
String[] componentFileNames;
|
||||
|
||||
@@ -108,7 +108,7 @@ public class CompositeGlyphMapper extends CharToGlyphMapper {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
protected int convertToGlyph(int unicode) {
|
||||
private int convertToGlyph(int unicode) {
|
||||
|
||||
for (int slot = 0; slot < font.numSlots; slot++) {
|
||||
if (!hasExcludes || !font.isExcludedChar(slot, unicode)) {
|
||||
|
||||
@@ -335,7 +335,7 @@ public abstract class Font2D {
|
||||
return getStrike(desc, true);
|
||||
}
|
||||
|
||||
FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
|
||||
private FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
|
||||
/* Before looking in the map, see if the descriptor matches the
|
||||
* last strike returned from this Font2D. This should often be a win
|
||||
* since its common for the same font, in the same size to be
|
||||
|
||||
@@ -43,6 +43,7 @@ public abstract class FontAccess {
|
||||
}
|
||||
|
||||
public abstract Font2D getFont2D(Font f);
|
||||
public abstract Font2D getFont2DWithSubstitution(Font f);
|
||||
public abstract void setFont2D(Font f, Font2DHandle h);
|
||||
public abstract void setCreatedFont(Font f);
|
||||
public abstract boolean isCreatedFont(Font f);
|
||||
|
||||
@@ -356,7 +356,7 @@ public final class FontDesignMetrics extends FontMetrics {
|
||||
|
||||
private void initMatrixAndMetrics() {
|
||||
|
||||
Font2D font2D = FontUtilities.getFont2D(font);
|
||||
Font2D font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
fontStrike = font2D.getStrike(font, frc);
|
||||
StrikeMetrics metrics = fontStrike.getFontMetrics();
|
||||
this.ascent = metrics.getAscent();
|
||||
|
||||
@@ -266,12 +266,12 @@ public class FontFamily {
|
||||
doSetFont(fontAndStyle.font, fontAndStyle.style);
|
||||
}
|
||||
if (italic == null && plain instanceof FontWithDerivedItalic) {
|
||||
italic = ((FontWithDerivedItalic)plain).createItalic();
|
||||
italic = ((FontWithDerivedItalic)plain).createItalicVariant();
|
||||
}
|
||||
if (bolditalic == null) {
|
||||
Font2D boldItalicPrototype = bold != null ? bold : plain;
|
||||
if (boldItalicPrototype instanceof FontWithDerivedItalic) {
|
||||
bolditalic = ((FontWithDerivedItalic)boldItalicPrototype).createItalic();
|
||||
bolditalic = ((FontWithDerivedItalic)boldItalicPrototype).createItalicVariant();
|
||||
}
|
||||
}
|
||||
fontSequence.clear();
|
||||
|
||||
@@ -168,6 +168,10 @@ public final class FontUtilities {
|
||||
return FontAccess.getFontAccess().getFont2D(font);
|
||||
}
|
||||
|
||||
public static Font2D getFont2DWithSubstitution(Font font) {
|
||||
return FontAccess.getFontAccess().getFont2DWithSubstitution(font);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there any characters which would trigger layout.
|
||||
* This method considers supplementary characters to be simple,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package sun.font;
|
||||
|
||||
interface FontWithDerivedItalic {
|
||||
Font2D createItalic();
|
||||
Font2D createItalicVariant();
|
||||
}
|
||||
@@ -410,10 +410,7 @@ public final class GlyphLayout {
|
||||
|
||||
int lang = -1; // default for now
|
||||
|
||||
Font2D font2D = FontUtilities.getFont2D(font);
|
||||
if (font2D instanceof FontSubstitution) {
|
||||
font2D = ((FontSubstitution)font2D).getCompositeFont2D();
|
||||
}
|
||||
Font2D font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
|
||||
_textRecord.init(text, offset, lim, min, max);
|
||||
int start = offset;
|
||||
|
||||
@@ -197,8 +197,7 @@ public class StandardGlyphVector extends GlyphVector {
|
||||
|
||||
// how do we know its a base glyph
|
||||
// for now, it is if the natural advance of the glyph is non-zero
|
||||
Font2D f2d = FontUtilities.getFont2D(font);
|
||||
FontStrike strike = f2d.getStrike(font, frc);
|
||||
FontStrike strike = font2D.getStrike(font, frc);
|
||||
|
||||
float[] deltas = { trackPt.x, trackPt.y };
|
||||
for (int j = 0; j < deltas.length; ++j) {
|
||||
@@ -1106,10 +1105,7 @@ public class StandardGlyphVector extends GlyphVector {
|
||||
}
|
||||
|
||||
private void initFontData() {
|
||||
font2D = FontUtilities.getFont2D(font);
|
||||
if (font2D instanceof FontSubstitution) {
|
||||
font2D = ((FontSubstitution)font2D).getCompositeFont2D();
|
||||
}
|
||||
font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
float s = font.getSize2D();
|
||||
if (font.isTransformed()) {
|
||||
ftx = font.getTransform();
|
||||
@@ -1728,12 +1724,7 @@ public class StandardGlyphVector extends GlyphVector {
|
||||
aa, fm);
|
||||
// Get the strike via the handle. Shouldn't matter
|
||||
// if we've invalidated the font but its an extra precaution.
|
||||
// do we want the CompFont from CFont here ?
|
||||
Font2D f2d = sgv.font2D;
|
||||
if (f2d instanceof FontSubstitution) {
|
||||
f2d = ((FontSubstitution)f2d).getCompositeFont2D();
|
||||
}
|
||||
FontStrike strike = f2d.handle.font2D.getStrike(desc); // !!! getStrike(desc, false)
|
||||
FontStrike strike = sgv.font2D.handle.font2D.getStrike(desc); // !!! getStrike(desc, false)
|
||||
|
||||
return new GlyphStrike(sgv, strike, dx, dy);
|
||||
}
|
||||
|
||||
@@ -670,7 +670,7 @@ public final class SunGraphics2D
|
||||
info.nonInvertibleTx =
|
||||
(Math.abs(textAt.getDeterminant()) <= Double.MIN_VALUE);
|
||||
|
||||
info.font2D = FontUtilities.getFont2D(font);
|
||||
info.font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
|
||||
int fmhint = fractionalMetricsHint;
|
||||
if (fmhint == SunHints.INTVAL_FRACTIONALMETRICS_DEFAULT) {
|
||||
|
||||
@@ -698,7 +698,7 @@ public abstract class PathGraphics extends ProxyGraphics2D {
|
||||
}
|
||||
|
||||
Font font = g.getFont();
|
||||
Font2D font2D = FontUtilities.getFont2D(font);
|
||||
Font2D font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
if (font2D.handle.font2D != font2D) {
|
||||
/* suspicious, may be a bad font. lets bail */
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -44,6 +44,7 @@ import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
@@ -120,14 +121,17 @@ public class Main {
|
||||
Set<Entry> entries = new LinkedHashSet<>();
|
||||
|
||||
// module-info.class entries need to be added/updated.
|
||||
Map<String,byte[]> moduleInfos = new HashMap<>();
|
||||
Map<String, ModuleInfoEntry> moduleInfos = new HashMap<>();
|
||||
|
||||
// A paths Set for each version, where each Set contains directories
|
||||
// specified by the "-C" operation.
|
||||
Map<Integer,Set<String>> pathsMap = new HashMap<>();
|
||||
|
||||
// There's also a files array per version
|
||||
Map<Integer,String[]> filesMap = new HashMap<>();
|
||||
// base version is the first entry and then follow with the version given
|
||||
// from the --release option in the command-line order.
|
||||
// The value of each entry is the files given in the command-line order.
|
||||
Map<Integer,String[]> filesMap = new LinkedHashMap<>();
|
||||
|
||||
// Do we think this is a multi-release jar? Set to true
|
||||
// if --release option found followed by at least file
|
||||
@@ -772,15 +776,17 @@ public class Main {
|
||||
private void expand(File dir, String[] files, Set<String> cpaths, int version)
|
||||
throws IOException
|
||||
{
|
||||
if (files == null)
|
||||
if (files == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File f;
|
||||
if (dir == null)
|
||||
if (dir == null) {
|
||||
f = new File(files[i]);
|
||||
else
|
||||
} else {
|
||||
f = new File(dir, files[i]);
|
||||
}
|
||||
|
||||
boolean isDir = f.isDirectory();
|
||||
String name = toEntryName(f.getPath(), cpaths, isDir);
|
||||
@@ -801,19 +807,24 @@ public class Main {
|
||||
if (f.isFile()) {
|
||||
Entry e = new Entry(f, name, false);
|
||||
if (isModuleInfoEntry(name)) {
|
||||
moduleInfos.putIfAbsent(name, Files.readAllBytes(f.toPath()));
|
||||
if (uflag)
|
||||
Path path = f.toPath();
|
||||
byte[] fileContent = Files.readAllBytes(path);
|
||||
ModuleInfoEntry mie = new StreamedModuleInfoEntry(name, fileContent, Files.getLastModifiedTime(path));
|
||||
moduleInfos.putIfAbsent(name, mie);
|
||||
if (uflag) {
|
||||
entryMap.put(name, e);
|
||||
}
|
||||
} else if (entries.add(e)) {
|
||||
if (uflag)
|
||||
if (uflag) {
|
||||
entryMap.put(name, e);
|
||||
}
|
||||
}
|
||||
} else if (isDir) {
|
||||
Entry e = new Entry(f, name, true);
|
||||
if (entries.add(e)) {
|
||||
// utilize entryMap for the duplicate dir check even in
|
||||
// case of cflag == true.
|
||||
// dir name confilict/duplicate could happen with -C option.
|
||||
// dir name conflict/duplicate could happen with -C option.
|
||||
// just remove the last "e" from the "entries" (zos will fail
|
||||
// with "duplicated" entries), but continue expanding the
|
||||
// sub tree
|
||||
@@ -822,7 +833,12 @@ public class Main {
|
||||
} else {
|
||||
entryMap.put(name, e);
|
||||
}
|
||||
expand(f, f.list(), cpaths, version);
|
||||
String[] dirFiles = f.list();
|
||||
// Ensure files list is sorted for reproducible jar content
|
||||
if (dirFiles != null) {
|
||||
Arrays.sort(dirFiles);
|
||||
}
|
||||
expand(f, dirFiles, cpaths, version);
|
||||
}
|
||||
} else {
|
||||
error(formatMsg("error.nosuch.fileordir", String.valueOf(f)));
|
||||
@@ -895,7 +911,7 @@ public class Main {
|
||||
*/
|
||||
boolean update(InputStream in, OutputStream out,
|
||||
InputStream newManifest,
|
||||
Map<String,byte[]> moduleInfos,
|
||||
Map<String, ModuleInfoEntry> moduleInfos,
|
||||
JarIndex jarIndex) throws IOException
|
||||
{
|
||||
ZipInputStream zis = new ZipInputStream(in);
|
||||
@@ -944,7 +960,7 @@ public class Main {
|
||||
return false;
|
||||
}
|
||||
} else if (moduleInfos != null && isModuleInfoEntry) {
|
||||
moduleInfos.putIfAbsent(name, zis.readAllBytes());
|
||||
moduleInfos.putIfAbsent(name, new StreamedModuleInfoEntry(name, zis.readAllBytes(), e.getLastModifiedTime()));
|
||||
} else {
|
||||
boolean isDir = e.isDirectory();
|
||||
if (!entryMap.containsKey(name)) { // copy the old stuff
|
||||
@@ -1028,15 +1044,21 @@ public class Main {
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
private void updateModuleInfo(Map<String,byte[]> moduleInfos, ZipOutputStream zos)
|
||||
private void updateModuleInfo(Map<String, ModuleInfoEntry> moduleInfos, ZipOutputStream zos)
|
||||
throws IOException
|
||||
{
|
||||
String fmt = uflag ? "out.update.module-info": "out.added.module-info";
|
||||
for (Map.Entry<String,byte[]> mi : moduleInfos.entrySet()) {
|
||||
for (Map.Entry<String, ModuleInfoEntry> mi : moduleInfos.entrySet()) {
|
||||
String name = mi.getKey();
|
||||
byte[] bytes = mi.getValue();
|
||||
ModuleInfoEntry mie = mi.getValue();
|
||||
byte[] bytes = mie.readAllBytes();
|
||||
ZipEntry e = new ZipEntry(name);
|
||||
e.setTime(System.currentTimeMillis());
|
||||
FileTime lastModified = mie.getLastModifiedTime();
|
||||
if (lastModified != null) {
|
||||
e.setLastModifiedTime(lastModified);
|
||||
} else {
|
||||
e.setLastModifiedTime(FileTime.fromMillis(System.currentTimeMillis()));
|
||||
}
|
||||
if (flag0) {
|
||||
crc32ModuleInfo(e, bytes);
|
||||
}
|
||||
@@ -1731,12 +1753,23 @@ public class Main {
|
||||
|
||||
/**
|
||||
* Associates a module descriptor's zip entry name along with its
|
||||
* bytes and an optional URI. Used when describing modules.
|
||||
* bytes and an optional URI.
|
||||
*/
|
||||
interface ModuleInfoEntry {
|
||||
String name();
|
||||
Optional<String> uriString();
|
||||
InputStream bytes() throws IOException;
|
||||
String name();
|
||||
Optional<String> uriString();
|
||||
InputStream bytes() throws IOException;
|
||||
/**
|
||||
* @return Returns the last modified time of the module-info.class.
|
||||
* Returns null if the last modified time is unknown or cannot be
|
||||
* determined.
|
||||
*/
|
||||
FileTime getLastModifiedTime();
|
||||
default byte[] readAllBytes() throws IOException {
|
||||
try (InputStream is = bytes()) {
|
||||
return is.readAllBytes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class ZipFileModuleInfoEntry implements ModuleInfoEntry {
|
||||
@@ -1750,6 +1783,12 @@ public class Main {
|
||||
@Override public InputStream bytes() throws IOException {
|
||||
return zipFile.getInputStream(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getLastModifiedTime() {
|
||||
return entry.getLastModifiedTime();
|
||||
}
|
||||
|
||||
/** Returns an optional containing the effective URI. */
|
||||
@Override public Optional<String> uriString() {
|
||||
String uri = (Paths.get(zipFile.getName())).toUri().toString();
|
||||
@@ -1761,14 +1800,28 @@ public class Main {
|
||||
static class StreamedModuleInfoEntry implements ModuleInfoEntry {
|
||||
private final String name;
|
||||
private final byte[] bytes;
|
||||
StreamedModuleInfoEntry(String name, byte[] bytes) {
|
||||
private final FileTime lastModifiedTime;
|
||||
|
||||
StreamedModuleInfoEntry(String name, byte[] bytes, FileTime lastModifiedTime) {
|
||||
this.name = name;
|
||||
this.bytes = bytes;
|
||||
this.lastModifiedTime = lastModifiedTime;
|
||||
}
|
||||
@Override public String name() { return name; }
|
||||
@Override public InputStream bytes() throws IOException {
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] readAllBytes() throws IOException {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime getLastModifiedTime() {
|
||||
return lastModifiedTime;
|
||||
}
|
||||
|
||||
/** Returns an empty optional. */
|
||||
@Override public Optional<String> uriString() {
|
||||
return Optional.empty(); // no URI can be derived
|
||||
@@ -1820,7 +1873,7 @@ public class Main {
|
||||
while ((e = zis.getNextEntry()) != null) {
|
||||
String ename = e.getName();
|
||||
if (isModuleInfoEntry(ename)) {
|
||||
infos.add(new StreamedModuleInfoEntry(ename, zis.readAllBytes()));
|
||||
infos.add(new StreamedModuleInfoEntry(ename, zis.readAllBytes(), e.getLastModifiedTime()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2033,14 +2086,14 @@ public class Main {
|
||||
return (classname.replace('.', '/')) + ".class";
|
||||
}
|
||||
|
||||
private boolean checkModuleInfo(byte[] moduleInfoBytes, Set<String> entries)
|
||||
private boolean checkModuleInfo(ModuleInfoEntry moduleInfoEntry, Set<String> entries)
|
||||
throws IOException
|
||||
{
|
||||
boolean ok = true;
|
||||
if (moduleInfoBytes != null) { // no root module-info.class if null
|
||||
if (moduleInfoEntry != null) { // no root module-info.class if null
|
||||
try {
|
||||
// ModuleDescriptor.read() checks open/exported pkgs vs packages
|
||||
ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(moduleInfoBytes));
|
||||
ModuleDescriptor md = ModuleDescriptor.read(moduleInfoEntry.bytes());
|
||||
// A module must have the implementation class of the services it 'provides'.
|
||||
if (md.provides().stream().map(Provides::providers).flatMap(List::stream)
|
||||
.filter(p -> !entries.contains(toBinaryName(p)))
|
||||
@@ -2058,15 +2111,19 @@ public class Main {
|
||||
|
||||
/**
|
||||
* Adds extended modules attributes to the given module-info's. The given
|
||||
* Map values are updated in-place. Returns false if an error occurs.
|
||||
* Map values are updated in-place.
|
||||
*/
|
||||
private void addExtendedModuleAttributes(Map<String,byte[]> moduleInfos,
|
||||
private void addExtendedModuleAttributes(Map<String, ModuleInfoEntry> moduleInfos,
|
||||
Set<String> packages)
|
||||
throws IOException
|
||||
{
|
||||
for (Map.Entry<String,byte[]> e: moduleInfos.entrySet()) {
|
||||
ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(e.getValue()));
|
||||
e.setValue(extendedInfoBytes(md, e.getValue(), packages));
|
||||
for (Map.Entry<String, ModuleInfoEntry> e: moduleInfos.entrySet()) {
|
||||
ModuleInfoEntry mie = e.getValue();
|
||||
byte[] bytes = mie.readAllBytes();
|
||||
ModuleDescriptor md = ModuleDescriptor.read(ByteBuffer.wrap(bytes));
|
||||
byte[] extended = extendedInfoBytes(md, bytes, packages);
|
||||
// replace the entry value with the extended bytes
|
||||
e.setValue(new StreamedModuleInfoEntry(mie.name(), extended, mie.getLastModifiedTime()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -326,7 +326,7 @@ public class ModuleDotGraph {
|
||||
|
||||
private final String name;
|
||||
private final Graph<String> graph;
|
||||
private final Set<ModuleDescriptor> descriptors = new TreeSet<>();
|
||||
private final TreeSet<ModuleDescriptor> descriptors = new TreeSet<>();
|
||||
private final List<SubGraph> subgraphs = new ArrayList<>();
|
||||
private final Attributes attributes;
|
||||
public DotGraphBuilder(String name,
|
||||
@@ -406,8 +406,8 @@ public class ModuleDotGraph {
|
||||
.collect(toSet());
|
||||
|
||||
String mn = md.name();
|
||||
edges.stream().forEach(dn -> {
|
||||
String attr;
|
||||
edges.stream().sorted().forEach(dn -> {
|
||||
String attr = "";
|
||||
if (dn.equals("java.base")) {
|
||||
attr = "color=\"" + attributes.requiresMandatedColor() + "\"";
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, 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
|
||||
@@ -767,6 +767,10 @@ public class JmodTask {
|
||||
void processSection(JmodOutputStream out, Section section, Path path)
|
||||
throws IOException
|
||||
{
|
||||
// Keep a sorted set of files to be processed, so that the jmod
|
||||
// content is reproducible as Files.walkFileTree order is not defined
|
||||
SortedMap<String, Path> filesToProcess = new TreeMap<String, Path>();
|
||||
|
||||
Files.walkFileTree(path, Set.of(FileVisitOption.FOLLOW_LINKS),
|
||||
Integer.MAX_VALUE, new SimpleFileVisitor<Path>() {
|
||||
@Override
|
||||
@@ -782,14 +786,21 @@ public class JmodTask {
|
||||
if (out.contains(section, name)) {
|
||||
warning("warn.ignore.duplicate.entry", name, section);
|
||||
} else {
|
||||
try (InputStream in = Files.newInputStream(file)) {
|
||||
out.writeEntry(in, section, name);
|
||||
}
|
||||
filesToProcess.put(name, file);
|
||||
}
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
|
||||
// Process files in sorted order for deterministic jmod content
|
||||
for (Map.Entry<String, Path> entry : filesToProcess.entrySet()) {
|
||||
String name = entry.getKey();
|
||||
Path file = entry.getValue();
|
||||
try (InputStream in = Files.newInputStream(file)) {
|
||||
out.writeEntry(in, section, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean matches(Path path, List<PathMatcher> matchers) {
|
||||
|
||||
@@ -41,10 +41,8 @@
|
||||
# :hotspot_compiler
|
||||
|
||||
compiler/ciReplay/TestSAServer.java 8029528 generic-all
|
||||
compiler/codecache/jmx/PoolsIndependenceTest.java 8167015 generic-all
|
||||
compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all
|
||||
compiler/jvmci/compilerToVM/GetFlagValueTest.java 8204459 generic-all
|
||||
compiler/tiered/LevelTransitionTest.java 8067651 generic-all
|
||||
|
||||
compiler/cpuflags/TestAESIntrinsicsOnSupportedConfig.java 8190680 generic-all
|
||||
|
||||
@@ -85,8 +83,6 @@ gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java 8241293 macosx-x64
|
||||
runtime/cds/appcds/jigsaw/modulepath/ModulePathAndCP_JFR.java 8253437 windows-x64
|
||||
runtime/cds/DeterministicDump.java 8253495 generic-all
|
||||
runtime/jni/terminatedThread/TestTerminatedThread.java 8219652 aix-ppc64
|
||||
runtime/ReservedStack/ReservedStackTest.java 8231031 generic-all
|
||||
containers/docker/TestJFRWithJMX.java 8256417 linux-5.4.17-2011.5.3.el8uek.x86_64
|
||||
|
||||
#############################################################################
|
||||
|
||||
@@ -95,12 +91,8 @@ containers/docker/TestJFRWithJMX.java 8256417 linux-5.4.17-2011.5.3.el8uek.x86_6
|
||||
serviceability/sa/sadebugd/DebugdConnectTest.java 8239062 macosx-x64
|
||||
serviceability/sa/TestRevPtrsForInvokeDynamic.java 8241235 generic-all
|
||||
|
||||
serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatIntervalTest.java 8214032 generic-all
|
||||
serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatArrayCorrectnessTest.java 8224150 generic-all
|
||||
serviceability/jvmti/ModuleAwareAgents/ThreadStart/MAAThreadStart.java 8225354 windows-all
|
||||
|
||||
serviceability/attach/RemovingUnixDomainSocketTest.java 8248162 linux-x64
|
||||
|
||||
#############################################################################
|
||||
|
||||
# :hotspot_misc
|
||||
@@ -124,8 +116,6 @@ vmTestbase/nsk/monitoring/ThreadMXBean/ThreadInfo/Deadlock/JavaDeadlock001/TestD
|
||||
|
||||
vmTestbase/nsk/jdi/ThreadReference/stop/stop001/TestDescription.java 7034630 generic-all
|
||||
|
||||
vmTestbase/nsk/jdb/eval/eval001/eval001.java 8221503 generic-all
|
||||
|
||||
vmTestbase/metaspace/gc/firstGC_10m/TestDescription.java 8208250 generic-all
|
||||
vmTestbase/metaspace/gc/firstGC_50m/TestDescription.java 8208250 generic-all
|
||||
vmTestbase/metaspace/gc/firstGC_99m/TestDescription.java 8208250 generic-all
|
||||
@@ -142,13 +132,6 @@ vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all
|
||||
vmTestbase/jit/escape/LockCoarsening/LockCoarsening002.java 8208259 generic-all
|
||||
|
||||
vmTestbase/vm/mlvm/indy/func/jvmti/redefineClassInBootstrap/TestDescription.java 8013267 generic-all
|
||||
vmTestbase/vm/mlvm/meth/func/java/throwException/Test.java 8058176 generic-all
|
||||
vmTestbase/vm/mlvm/meth/stress/compiler/deoptimize/Test.java#id1 8058176 generic-all
|
||||
vmTestbase/vm/mlvm/meth/stress/compiler/i2c_c2i/Test.java 8058176 generic-all
|
||||
vmTestbase/vm/mlvm/meth/stress/compiler/sequences/Test.java 8058176 generic-all
|
||||
vmTestbase/vm/mlvm/meth/stress/gc/callSequencesDuringGC/Test.java 8058176 generic-all
|
||||
vmTestbase/vm/mlvm/meth/stress/java/sequences/Test.java 8058176 generic-all
|
||||
vmTestbase/vm/mlvm/meth/stress/jdi/breakpointInCompiledCode/Test.java 8058176 generic-all
|
||||
vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2none_a/TestDescription.java 8013267 generic-all
|
||||
vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_b/TestDescription.java 8013267 generic-all
|
||||
vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manySame_b/TestDescription.java 8013267 generic-all
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, Google and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@@ -36,10 +36,16 @@ package MyPackage;
|
||||
public class HeapMonitorStatArrayCorrectnessTest {
|
||||
|
||||
private static final int maxCount = 10;
|
||||
// Do 100000 iterations and expect maxIteration / multiplier samples.
|
||||
private static final int maxIteration = 100000;
|
||||
// Do 200000 iterations and expect maxIteration / multiplier samples.
|
||||
private static final int maxIteration = 200_000;
|
||||
private static int array[];
|
||||
|
||||
// 15% error ensures a sanity test without becoming flaky.
|
||||
// Flakiness is due to the fact that this test is dependent on the sampling interval, which is a
|
||||
// statistical geometric variable around the sampling interval. This means that the test could be
|
||||
// unlucky and not achieve the mean average fast enough for the test case.
|
||||
private static final int acceptedErrorPercentage = 15;
|
||||
|
||||
private static void allocate(int size) {
|
||||
for (int j = 0; j < maxIteration; j++) {
|
||||
array = new int[size];
|
||||
@@ -85,11 +91,7 @@ public class HeapMonitorStatArrayCorrectnessTest {
|
||||
expected *= 4;
|
||||
expected /= samplingMultiplier;
|
||||
|
||||
// 10% error ensures a sanity test without becoming flaky.
|
||||
// Flakiness is due to the fact that this test is dependent on the sampling interval, which is a
|
||||
// statistical geometric variable around the sampling interval. This means that the test could be
|
||||
// unlucky and not achieve the mean average fast enough for the test case.
|
||||
if (HeapMonitor.statsHaveExpectedNumberSamples((int) expected, 10)) {
|
||||
if (HeapMonitor.statsHaveExpectedNumberSamples((int) expected, acceptedErrorPercentage)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class HeapMonitorStatIntervalTest {
|
||||
HeapMonitor.enableSamplingEvents();
|
||||
|
||||
int allocationTotal = 10 * 1024 * 1024;
|
||||
int allocationIterations = 10;
|
||||
int allocationIterations = 20;
|
||||
|
||||
double actualCount = 0;
|
||||
for (int i = 0; i < allocationIterations; i++) {
|
||||
@@ -58,13 +58,13 @@ public class HeapMonitorStatIntervalTest {
|
||||
double error = Math.abs(actualCount - expectedCount);
|
||||
double errorPercentage = error / expectedCount * 100;
|
||||
|
||||
boolean success = (errorPercentage < 10.0);
|
||||
boolean success = (errorPercentage < 15.0);
|
||||
System.out.println("Interval: " + interval + ", throw if failure: " + throwIfFailure
|
||||
+ " - Expected count: " + expectedCount + ", allocationIterations: " + allocationIterations
|
||||
+ ", actualCount: " + actualCount + " -> " + success);
|
||||
|
||||
if (!success && throwIfFailure) {
|
||||
throw new RuntimeException("Interval average over 10% for interval " + interval + " -> "
|
||||
throw new RuntimeException("Interval average over 15% for interval " + interval + " -> "
|
||||
+ actualCount + ", " + expectedCount);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class HeapMonitorStatIntervalTest {
|
||||
|
||||
private static void testInterval(int interval) {
|
||||
// Test the interval twice, it can happen that the test is "unlucky" and the interval just goes above
|
||||
// the 10% mark. So try again to squash flakiness.
|
||||
// the 15% mark. So try again to squash flakiness.
|
||||
// Flakiness is due to the fact that this test is dependent on the sampling interval, which is a
|
||||
// statistical geometric variable around the sampling interval. This means that the test could be
|
||||
// unlucky and not achieve the mean average fast enough for the test case.
|
||||
|
||||
@@ -36,11 +36,15 @@ package MyPackage;
|
||||
/** This test is checking the object allocation path works with heap sampling. */
|
||||
public class HeapMonitorStatObjectCorrectnessTest {
|
||||
|
||||
// Do 200000 iterations and expect maxIteration / multiplier samples.
|
||||
private static final int maxIteration = 200000;
|
||||
// Do 400000 iterations and expect maxIteration / multiplier samples.
|
||||
private static final int maxIteration = 400_000;
|
||||
private static BigObject obj;
|
||||
|
||||
private native static boolean statsHaveExpectedNumberSamples(int expected, int percentError);
|
||||
// 15% error ensures a sanity test without becoming flaky.
|
||||
// Flakiness is due to the fact that this test is dependent on the sampling interval, which is a
|
||||
// statistical geometric variable around the sampling interval. This means that the test could be
|
||||
// unlucky and not achieve the mean average fast enough for the test case.
|
||||
private static final int acceptedErrorPercentage = 15;
|
||||
|
||||
private static void allocate() {
|
||||
emptyStorage();
|
||||
@@ -83,11 +87,7 @@ public class HeapMonitorStatObjectCorrectnessTest {
|
||||
double expected = maxIteration;
|
||||
expected /= samplingMultiplier;
|
||||
|
||||
// 10% error ensures a sanity test without becoming flaky.
|
||||
// Flakiness is due to the fact that this test is dependent on the sampling interval, which is a
|
||||
// statistical geometric variable around the sampling interval. This means that the test could be
|
||||
// unlucky and not achieve the mean average fast enough for the test case.
|
||||
if (!HeapMonitor.statsHaveExpectedNumberSamples((int) expected, 10)) {
|
||||
if (!HeapMonitor.statsHaveExpectedNumberSamples((int) expected, acceptedErrorPercentage)) {
|
||||
throw new RuntimeException("Statistics should show about " + expected + " samples.");
|
||||
}
|
||||
}
|
||||
@@ -108,11 +108,7 @@ public class HeapMonitorStatObjectCorrectnessTest {
|
||||
|
||||
double expected = maxIteration;
|
||||
|
||||
// 10% error ensures a sanity test without becoming flaky.
|
||||
// Flakiness is due to the fact that this test is dependent on the sampling interval, which is a
|
||||
// statistical geometric variable around the sampling interval. This means that the test could be
|
||||
// unlucky and not achieve the mean average fast enough for the test case.
|
||||
if (!HeapMonitor.statsHaveExpectedNumberSamples((int) expected, 10)) {
|
||||
if (!HeapMonitor.statsHaveExpectedNumberSamples((int) expected, acceptedErrorPercentage)) {
|
||||
throw new RuntimeException("Statistics should show about " + expected + " samples.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ java/awt/Frame/ExceptionOnSetExtendedStateTest/ExceptionOnSetExtendedStateTest.j
|
||||
java/awt/Frame/ShapeNotSetSometimes/ShapeNotSetSometimes.java 8144030 macosx-all,linux-all
|
||||
java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java 7080150 macosx-all
|
||||
java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java 8168646 generic-all
|
||||
java/awt/KeyboardFocusmanager/TypeAhead/TestDialogTypeAhead.java 8198626 macosx-all
|
||||
java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.java 8273520 macosx-all
|
||||
java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java 8049405 macosx-all
|
||||
java/awt/Mixing/AWT_Mixing/OpaqueOverlappingChoice.java 8048171 generic-all
|
||||
java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java 8159451 linux-all,windows-all,macosx-all
|
||||
@@ -182,7 +182,6 @@ java/awt/Mixing/AWT_Mixing/JToggleButtonInGlassPaneOverlapping.java 8158801 wind
|
||||
java/awt/Mixing/AWT_Mixing/JToggleButtonOverlapping.java 8158801 windows-all
|
||||
java/awt/Mixing/MixingOnDialog.java 8225777 linux-all
|
||||
java/awt/Mixing/NonOpaqueInternalFrame.java 7124549 macosx-all
|
||||
java/awt/Mouse/GetMousePositionTest/GetMousePositionWithOverlay.java 8168388 linux-all
|
||||
java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java 6829264 generic-all
|
||||
java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java 8080982 generic-all
|
||||
java/awt/datatransfer/SystemFlavorMap/AddFlavorTest.java 8079268 linux-all
|
||||
@@ -191,13 +190,12 @@ java/awt/Toolkit/RealSync/Test.java 6849383 linux-all
|
||||
java/awt/LightweightComponent/LightweightEventTest/LightweightEventTest.java 8159252 windows-all
|
||||
java/awt/EventDispatchThread/HandleExceptionOnEDT/HandleExceptionOnEDT.java 8203047 macosx-all
|
||||
java/awt/EventDispatchThread/LoopRobustness/LoopRobustness.java 8073636 macosx-all
|
||||
java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java 7019055 windows-all,linux-all
|
||||
java/awt/FullScreen/FullScreenInsets/FullScreenInsets.java 7019055,8266245 windows-all,linux-all,macosx-aarch64
|
||||
java/awt/Focus/8013611/JDK8013611.java 8175366 windows-all,macosx-all
|
||||
java/awt/Focus/6981400/Test1.java 8029675 windows-all,macosx-all
|
||||
java/awt/Focus/6981400/Test3.java 8173264 generic-all
|
||||
java/awt/event/KeyEvent/ExtendedKeyCode/ExtendedKeyCodeTest.java 8169476 windows-all,macosx-all
|
||||
java/awt/event/KeyEvent/KeyChar/KeyCharTest.java 8169474,8224055 macosx-all,windows-all
|
||||
java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_3.java 6854300 generic-all
|
||||
java/awt/event/KeyEvent/ExtendedModifiersTest/ExtendedModifiersTest.java 8129778 generic-all
|
||||
java/awt/event/KeyEvent/KeyMaskTest/KeyMaskTest.java 8129778 generic-all
|
||||
java/awt/event/KeyEvent/KeyTyped/CtrlASCII.java 8252713 linux-all
|
||||
@@ -206,7 +204,6 @@ java/awt/event/MouseEvent/MouseButtonsAndKeyMasksTest/MouseButtonsAndKeyMasksTes
|
||||
java/awt/dnd/URIListToFileListBetweenJVMsTest/URIListToFileListBetweenJVMsTest.java 8194947 generic-all
|
||||
java/awt/Frame/FramesGC/FramesGC.java 8079069 macosx-all
|
||||
java/awt/GridLayout/LayoutExtraGaps/LayoutExtraGaps.java 8000171 windows-all
|
||||
java/awt/Mouse/GetMousePositionTest/GetMousePositionWithPopup.java 8196017 windows-all
|
||||
java/awt/Scrollbar/ScrollbarMouseWheelTest/ScrollbarMouseWheelTest.java 8196018 windows-all,linux-all
|
||||
java/awt/TrayIcon/ActionCommand/ActionCommand.java 8150540 windows-all
|
||||
java/awt/TrayIcon/ActionEventMask/ActionEventMask.java 8150540 windows-all
|
||||
@@ -221,7 +218,6 @@ java/awt/TrayIcon/TrayIconEvents/TrayIconEventsTest.java 8150540 windows-all
|
||||
java/awt/TrayIcon/TrayIconMouseTest/TrayIconMouseTest.java 8150540 windows-all
|
||||
java/awt/TrayIcon/TrayIconPopup/TrayIconPopupClickTest.java 8150540 windows-all,macosx-all
|
||||
java/awt/TrayIcon/TrayIconPopup/TrayIconPopupTest.java 8150540 windows-all
|
||||
java/awt/TrayIcon/PopupMenuLeakTest/PopupMenuLeakTest.java 8196440 linux-all
|
||||
|
||||
java/awt/Window/ShapedAndTranslucentWindows/SetShapeAndClick.java 8197936 macosx-all
|
||||
java/awt/Window/ShapedAndTranslucentWindows/SetShapeDynamicallyAndClick.java 8013450 macosx-all
|
||||
@@ -236,12 +232,10 @@ java/awt/Window/ShapedAndTranslucentWindows/Translucent.java 8222328 windows-all
|
||||
java/awt/Window/AlwaysOnTop/AutoTestOnTop.java 6847593 linux-all
|
||||
java/awt/Window/GrabSequence/GrabSequence.java 6848409 macosx-all,linux-all
|
||||
java/awt/Window/LocationAtScreenCorner/LocationAtScreenCorner.java 8203371 linux-all
|
||||
java/awt/font/TextLayout/CombiningPerf.java 8192931 generic-all
|
||||
java/awt/font/TextLayout/TextLayoutBounds.java 8169188 generic-all
|
||||
java/awt/FontMetrics/FontCrash.java 8198336 windows-all
|
||||
java/awt/image/BufferedImage/ICMColorDataTest/ICMColorDataTest.java 8233028 generic-all
|
||||
java/awt/image/DrawImage/IncorrectAlphaSurface2SW.java 8056077 linux-all
|
||||
java/awt/image/DrawImage/BlitRotateClippedArea.java 8255724 linux-all
|
||||
java/awt/image/multiresolution/MultiresolutionIconTest.java 8169187,8252812 macosx-all,windows-all,linux-x64
|
||||
java/awt/print/Headless/HeadlessPrinterJob.java 8196088 windows-all
|
||||
sun/awt/datatransfer/SuplementaryCharactersTransferTest.java 8011371 generic-all
|
||||
@@ -257,14 +251,15 @@ sun/java2d/SunGraphics2D/SimplePrimQuality.java 6992007 generic-all
|
||||
sun/java2d/SunGraphics2D/SourceClippingBlitTest/SourceClippingBlitTest.java 8196185 generic-all
|
||||
|
||||
sun/java2d/X11SurfaceData/SharedMemoryPixmapsTest/SharedMemoryPixmapsTest.sh 8221451 linux-all
|
||||
java/awt/FullScreen/DisplayChangeVITest/DisplayChangeVITest.java 8169469 windows-all
|
||||
java/awt/FullScreen/DisplayChangeVITest/DisplayChangeVITest.java 8169469,8273618 windows-all,macosx-aarch64
|
||||
java/awt/FullScreen/UninitializedDisplayModeChangeTest/UninitializedDisplayModeChangeTest.java 8273617 macosx-all
|
||||
java/awt/print/PrinterJob/PSQuestionMark.java 7003378 generic-all
|
||||
java/awt/print/PrinterJob/GlyphPositions.java 7003378 generic-all
|
||||
java/awt/Choice/ChoiceMouseWheelTest/ChoiceMouseWheelTest.java 7100044 macosx-all,linux-all
|
||||
java/awt/Component/GetScreenLocTest/GetScreenLocTest.java 4753654 generic-all
|
||||
java/awt/Component/SetEnabledPerformance/SetEnabledPerformance.java 8165863 macosx-all
|
||||
java/awt/Clipboard/HTMLTransferTest/HTMLTransferTest.java 8017454 macosx-all
|
||||
java/awt/Frame/MiscUndecorated/RepaintTest.java 8079267 windows-all,linux-all
|
||||
java/awt/Frame/MiscUndecorated/RepaintTest.java 8079267,8266244 windows-all,linux-all,macosx-aarch64
|
||||
java/awt/Robot/ModifierRobotKey/ModifierRobotKeyTest.java 8157173 generic-all
|
||||
java/awt/Modal/FileDialog/FileDialogAppModal1Test.java 7186009 macosx-all
|
||||
java/awt/Modal/FileDialog/FileDialogAppModal2Test.java 7186009 macosx-all
|
||||
@@ -474,12 +469,11 @@ java/awt/font/TextLayout/LigatureCaretTest.java 8266312 generic-all
|
||||
java/awt/image/VolatileImage/CustomCompositeTest.java 8199002 windows-all,linux-all
|
||||
java/awt/image/VolatileImage/GradientPaints.java 8199003 linux-all
|
||||
java/awt/JAWT/JAWT.sh 8197798 windows-all,linux-all
|
||||
java/awt/Debug/DumpOnKey/DumpOnKey.java 8202667 windows-all
|
||||
java/awt/Robot/RobotWheelTest/RobotWheelTest.java 8129827 generic-all
|
||||
java/awt/Focus/WindowUpdateFocusabilityTest/WindowUpdateFocusabilityTest.java 8202926 linux-all
|
||||
java/awt/datatransfer/ConstructFlavoredObjectTest/ConstructFlavoredObjectTest.java 8202860 linux-all
|
||||
java/awt/dnd/DisposeFrameOnDragCrash/DisposeFrameOnDragTest.java 8202790 macosx-all,linux-all
|
||||
java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java 8202882,8255898 linux-all,macosx-all
|
||||
java/awt/FileDialog/FilenameFilterTest/FilenameFilterTest.java 8202882 linux-all
|
||||
java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java 8030121 macosx-all,linux-all
|
||||
java/awt/Choice/ChoicePopupLocation/ChoicePopupLocation.java 8202931 macosx-all,linux-all
|
||||
java/awt/Focus/NonFocusableBlockedOwnerTest/NonFocusableBlockedOwnerTest.java 7124275 macosx-all
|
||||
@@ -499,11 +493,9 @@ java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsDocModalTest.java 816
|
||||
java/awt/im/memoryleak/InputContextMemoryLeakTest.java 8023814 linux-all
|
||||
java/awt/Frame/DisposeParentGC/DisposeParentGC.java 8079786 macosx-all
|
||||
java/awt/FullScreen/NoResizeEventOnDMChangeTest/NoResizeEventOnDMChangeTest.java 8169468 macosx-all
|
||||
java/awt/TextArea/AutoScrollOnSelectAndAppend/AutoScrollOnSelectAndAppend.java 8213120 macosx-all
|
||||
|
||||
java/awt/GraphicsDevice/DisplayModes/CycleDMImage.java 7099223 linux-all,windows-all
|
||||
java/awt/Window/WindowResizing/DoubleClickTitleBarTest.java 8233557 macosx-all
|
||||
java/awt/Window/WindowOwnedByEmbeddedFrameTest/WindowOwnedByEmbeddedFrameTest.java 8233558 macosx-all
|
||||
java/awt/keyboard/AllKeyCode/AllKeyCode.java 8242930 macosx-all
|
||||
java/awt/FullScreen/8013581/bug8013581.java 8169471 macosx-all
|
||||
java/awt/event/MouseEvent/RobotLWTest/RobotLWTest.java 8233568 macosx-all
|
||||
@@ -511,7 +503,6 @@ java/awt/event/MouseEvent/MultipleMouseButtonsTest/MultipleMouseButtonsTest.java
|
||||
java/awt/event/MouseEvent/ClickDuringKeypress/ClickDuringKeypress.java 8233568 macosx-all
|
||||
java/awt/event/KeyEvent/DeadKey/DeadKeyMacOSXInputText.java 8233568 macosx-all
|
||||
java/awt/event/KeyEvent/DeadKey/deadKeyMacOSX.java 8233568 macosx-all
|
||||
com/apple/eawt/DefaultMenuBar/DefaultMenuBarTest.java 8233648 macosx-all
|
||||
java/awt/Choice/ChoiceKeyEventReaction/ChoiceKeyEventReaction.java 7185258 macosx-all
|
||||
java/awt/TrayIcon/RightClickWhenBalloonDisplayed/RightClickWhenBalloonDisplayed.java 8238720 windows-all
|
||||
java/awt/PopupMenu/PopupMenuLocation.java 8238720 windows-all
|
||||
@@ -529,6 +520,7 @@ java/awt/Graphics2D/DrawString/DrawRotatedStringUsingRotatedFont.java 8266283 ge
|
||||
java/awt/KeyboardFocusmanager/TypeAhead/ButtonActionKeyTest/ButtonActionKeyTest.java 8257529 windows-x64
|
||||
|
||||
java/awt/Window/GetScreenLocation/GetScreenLocationTest.java 8225787 linux-x64
|
||||
java/awt/Dialog/MakeWindowAlwaysOnTop/MakeWindowAlwaysOnTop.java 8266243 macosx-aarch64
|
||||
|
||||
############################################################################
|
||||
|
||||
@@ -549,11 +541,11 @@ java/foreign/TestMismatch.java 8249684 macosx-all
|
||||
|
||||
# jdk_lang
|
||||
|
||||
java/lang/StringCoding/CheckEncodings.sh 7008363 generic-all
|
||||
java/lang/ProcessHandle/InfoTest.java 8211847 aix-ppc64
|
||||
java/lang/invoke/LFCaching/LFMultiThreadCachingTest.java 8151492 generic-all
|
||||
java/lang/invoke/LFCaching/LFGarbageCollectedTest.java 8078602 generic-all
|
||||
java/lang/invoke/lambda/LambdaFileEncodingSerialization.java 8249079 linux-x64
|
||||
java/lang/invoke/RicochetTest.java 8251969 generic-all
|
||||
|
||||
############################################################################
|
||||
|
||||
@@ -663,7 +655,6 @@ sun/security/provider/KeyStore/DKSTest.sh 8180266 windows-
|
||||
sun/security/pkcs11/KeyStore/SecretKeysBasic.java 8209398 generic-all
|
||||
|
||||
security/infra/java/security/cert/CertPathValidator/certification/ActalisCA.java 8224768 generic-all
|
||||
security/infra/java/security/cert/CertPathValidator/certification/ComodoCA.java 8263059 generic-all
|
||||
|
||||
sun/security/smartcardio/TestChannel.java 8039280 generic-all
|
||||
sun/security/smartcardio/TestConnect.java 8039280 generic-all
|
||||
@@ -742,11 +733,8 @@ javax/swing/dnd/8139050/NativeErrorsInTableDnD.java 8202765 macosx-all,linux-al
|
||||
javax/swing/Popup/TaskbarPositionTest.java 8065097 macosx-all,linux-all
|
||||
javax/swing/JEditorPane/6917744/bug6917744.java 8213124 macosx-all
|
||||
javax/swing/JRootPane/4670486/bug4670486.java 8042381 macosx-all
|
||||
javax/swing/JPopupMenu/4634626/bug4634626.java 8017175 macosx-all
|
||||
javax/swing/JFileChooser/FileSystemView/SystemIconTest.java 8268280 windows-x64
|
||||
|
||||
javax/swing/plaf/basic/BasicHTML/4251579/bug4251579.java 8137101 linux-x64
|
||||
javax/swing/JComponent/7154030/bug7154030.java 8268284 macosx-x64
|
||||
javax/swing/JButton/8151303/PressedIconTest.java 8266246 macosx-aarch64
|
||||
javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java 8273573 macosx-all
|
||||
|
||||
sanity/client/SwingSet/src/ToolTipDemoTest.java 8225012 windows-all,macosx-all
|
||||
sanity/client/SwingSet/src/ScrollPaneDemoTest.java 8225013 linux-all
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2021, 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
|
||||
@@ -24,18 +24,21 @@
|
||||
/**
|
||||
* @test
|
||||
* @key headful
|
||||
* @bug 8007267
|
||||
* @bug 8007267 8233648
|
||||
* @summary [macosx] com.apple.eawt.Application.setDefaultMenuBar is not working
|
||||
* @requires (os.family == "mac")
|
||||
* @author leonid.romanov@oracle.com
|
||||
* @modules java.desktop/sun.awt
|
||||
* java.desktop/com.apple.eawt
|
||||
* @run main DefaultMenuBarTest
|
||||
* @modules java.desktop/com.apple.eawt
|
||||
* @run main/othervm DefaultMenuBarTest
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
import java.awt.Robot;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
@@ -50,14 +53,11 @@ public class DefaultMenuBarTest {
|
||||
}
|
||||
|
||||
System.setProperty("apple.laf.useScreenMenuBar", "true");
|
||||
SwingUtilities.invokeAndWait(new Runnable() {
|
||||
public void run() {
|
||||
createAndShowGUI();
|
||||
}
|
||||
});
|
||||
SwingUtilities.invokeAndWait(DefaultMenuBarTest::createAndShowGUI);
|
||||
|
||||
Robot robot = new Robot();
|
||||
robot.setAutoDelay(100);
|
||||
robot.waitForIdle();
|
||||
|
||||
robot.keyPress(KeyEvent.VK_META);
|
||||
robot.keyPress(ks.getKeyCode());
|
||||
@@ -76,13 +76,7 @@ public class DefaultMenuBarTest {
|
||||
JMenuItem newItem = new JMenuItem("Open");
|
||||
|
||||
newItem.setAccelerator(ks);
|
||||
newItem.addActionListener(
|
||||
new ActionListener(){
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
listenerCallCounter++;
|
||||
}
|
||||
}
|
||||
);
|
||||
newItem.addActionListener(e -> listenerCallCounter++);
|
||||
menu.add(newItem);
|
||||
|
||||
JMenuBar defaultMenu = new JMenuBar();
|
||||
@@ -104,7 +98,7 @@ public class DefaultMenuBarTest {
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -26,68 +26,68 @@
|
||||
@key headful
|
||||
@bug 4140484
|
||||
@summary Heavyweight components inside invisible lightweight containers still show
|
||||
@author Your Name: art@sparc.spb.su
|
||||
@run main NativeInLightShow
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Button;
|
||||
import java.awt.Container;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Point;
|
||||
import java.awt.Robot;
|
||||
import java.awt.event.InputEvent;
|
||||
|
||||
|
||||
// The test verifies that the mixing code correctly handles COMPONENT_SHOWN events
|
||||
// while the top-level container is invisible.
|
||||
|
||||
public class NativeInLightShow
|
||||
{
|
||||
public class NativeInLightShow {
|
||||
//Declare things used in the test, like buttons and labels here
|
||||
static boolean buttonPressed = false;
|
||||
public static void main(String args[]) throws Exception {
|
||||
Frame f = new Frame("Test");
|
||||
static volatile boolean buttonPressed = false;
|
||||
|
||||
Robot robot = null;
|
||||
robot = new Robot();
|
||||
robot.setAutoDelay(50);
|
||||
public static void main(String[] args) throws Exception {
|
||||
Frame frame = new Frame("Test");
|
||||
|
||||
Container c = new Container();
|
||||
c.setLayout(new BorderLayout());
|
||||
Button b = new Button("I'm should be visible!");
|
||||
b.addActionListener(new ActionListener()
|
||||
{
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.out.println("Test PASSED");
|
||||
buttonPressed = true;
|
||||
}
|
||||
Robot robot = new Robot();
|
||||
|
||||
Container container = new Container();
|
||||
container.setLayout(new BorderLayout());
|
||||
Button button = new Button("I'm should be visible!");
|
||||
button.addActionListener(e -> {
|
||||
System.out.println("Test PASSED");
|
||||
buttonPressed = true;
|
||||
});
|
||||
c.add(b);
|
||||
|
||||
f.add(c);
|
||||
container.add(button);
|
||||
frame.add(container);
|
||||
frame.pack();
|
||||
|
||||
f.pack();
|
||||
|
||||
c.setVisible(false);
|
||||
c.setVisible(true);
|
||||
container.setVisible(false);
|
||||
container.setVisible(true);
|
||||
|
||||
// Wait for a while for COMPONENT_SHOW event to be dispatched
|
||||
robot.waitForIdle();
|
||||
|
||||
f.setVisible(true);
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.setVisible(true);
|
||||
|
||||
robot.waitForIdle();
|
||||
robot.delay(1000);
|
||||
|
||||
Point buttonLocation = b.getLocationOnScreen();
|
||||
Point buttonLocation = button.getLocationOnScreen();
|
||||
|
||||
robot.mouseMove(buttonLocation.x + 5, buttonLocation.y + 5);
|
||||
robot.mousePress(InputEvent.BUTTON1_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_MASK);
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
|
||||
// Wait for a while for ACTION event to be dispatched
|
||||
robot.waitForIdle();
|
||||
robot.delay(100);
|
||||
robot.delay(500);
|
||||
|
||||
frame.dispose();
|
||||
if (!buttonPressed) {
|
||||
System.out.println("Test FAILED");
|
||||
throw new RuntimeException("Button was not pressed");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -22,6 +22,7 @@
|
||||
*/
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Robot;
|
||||
import java.awt.Window;
|
||||
@@ -58,9 +59,11 @@ public final class DumpOnKey {
|
||||
w.setSize(200, 200);
|
||||
w.setLocationRelativeTo(null);
|
||||
w.setVisible(true);
|
||||
w.toFront();
|
||||
w.requestFocus();
|
||||
|
||||
final Robot robot = new Robot();
|
||||
robot.setAutoDelay(50);
|
||||
robot.setAutoDelay(100);
|
||||
robot.setAutoWaitForIdle(true);
|
||||
robot.mouseMove(w.getX() + w.getWidth() / 2,
|
||||
w.getY() + w.getHeight() / 2);
|
||||
@@ -74,7 +77,14 @@ public final class DumpOnKey {
|
||||
robot.keyRelease(KeyEvent.VK_SHIFT);
|
||||
robot.keyRelease(KeyEvent.VK_CONTROL);
|
||||
|
||||
w.dispose();
|
||||
try {
|
||||
EventQueue.invokeAndWait(() -> {
|
||||
w.dispose();
|
||||
});
|
||||
} catch (Exception e) {}
|
||||
|
||||
robot.delay(2000);
|
||||
|
||||
if (dumped != dump) {
|
||||
throw new RuntimeException("Exp:" + dump + ", actual:" + dumped);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
@summary namefilter is not called for file dialog on windows
|
||||
@library ../../regtesthelpers
|
||||
@build Util
|
||||
@run main FilenameFilterTest
|
||||
@run main/othervm FilenameFilterTest
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -26,7 +26,6 @@
|
||||
* @bug 6646411
|
||||
* @summary Tests that full screen window and its children receive resize
|
||||
event when display mode changes
|
||||
* @author Dmitri.Trembovetski@sun.com: area=Graphics
|
||||
* @run main/othervm NoResizeEventOnDMChangeTest
|
||||
* @run main/othervm -Dsun.java2d.d3d=false NoResizeEventOnDMChangeTest
|
||||
*/
|
||||
@@ -151,9 +150,22 @@ public class NoResizeEventOnDMChangeTest {
|
||||
System.err.printf("----------- Setting DM %dx%d:\n",
|
||||
dm1.getWidth(), dm1.getHeight());
|
||||
try {
|
||||
Frame f = fsWin instanceof Frame ? (Frame) fsWin : (Frame) fsWin.getOwner();
|
||||
DisplayMode oldMode = f.getGraphicsConfiguration().getDevice().getDisplayMode();
|
||||
gd.setDisplayMode(dm1);
|
||||
r1.incDmChanges();
|
||||
r2.incDmChanges();
|
||||
sleep(2000);
|
||||
// Check if setting new display mode actually results in frame being
|
||||
// placed onto display with different resolution.
|
||||
DisplayMode newMode = f.getGraphicsConfiguration().getDevice().getDisplayMode();
|
||||
if (oldMode.getWidth() != newMode.getWidth()
|
||||
|| oldMode.getHeight() != newMode.getHeight()) {
|
||||
r1.incDmChanges();
|
||||
r2.incDmChanges();
|
||||
} else {
|
||||
System.out.println("Skipping this iteration. Details:");
|
||||
System.out.println("Requested device = " + gd);
|
||||
System.out.println("Actual device = " + f.getGraphicsConfiguration().getDevice());
|
||||
}
|
||||
} catch (IllegalArgumentException iae) {}
|
||||
}
|
||||
});
|
||||
@@ -166,6 +178,7 @@ public class NoResizeEventOnDMChangeTest {
|
||||
fsWin.removeComponentListener(r1);
|
||||
c.removeComponentListener(r2);
|
||||
}
|
||||
|
||||
try {
|
||||
EventQueue.invokeAndWait(new Runnable() {
|
||||
public void run() {
|
||||
@@ -191,10 +204,14 @@ public class NoResizeEventOnDMChangeTest {
|
||||
}
|
||||
|
||||
static void sleep(long ms) {
|
||||
try {
|
||||
Thread.sleep(ms);
|
||||
} catch (InterruptedException ex) {}
|
||||
long targetTime = System.currentTimeMillis() + ms;
|
||||
do {
|
||||
try {
|
||||
Thread.sleep(targetTime - System.currentTimeMillis());
|
||||
} catch (InterruptedException ex) {}
|
||||
} while (System.currentTimeMillis() < targetTime);
|
||||
}
|
||||
|
||||
static class ResizeEventChecker extends ComponentAdapter {
|
||||
int dmChanges;
|
||||
int resizes;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -26,14 +26,29 @@
|
||||
@key headful
|
||||
@bug 4799136
|
||||
@summary Tests that type-ahead for dialog works and doesn't block program
|
||||
@library ../../regtesthelpers
|
||||
@modules java.desktop/sun.awt
|
||||
@build Util
|
||||
@run main TestDialogTypeAhead
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.Button;
|
||||
import java.awt.Component;
|
||||
import java.awt.DefaultKeyboardFocusManager;
|
||||
import java.awt.Dialog;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Frame;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Point;
|
||||
import java.awt.Robot;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.AWTEventListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.FocusAdapter;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
public class TestDialogTypeAhead {
|
||||
@@ -49,8 +64,17 @@ public class TestDialogTypeAhead {
|
||||
|
||||
public static void main(final String[] args) {
|
||||
TestDialogTypeAhead app = new TestDialogTypeAhead();
|
||||
app.init();
|
||||
app.start();
|
||||
try {
|
||||
app.init();
|
||||
app.start();
|
||||
} finally {
|
||||
if (d != null) {
|
||||
d.dispose();
|
||||
}
|
||||
if (f != null) {
|
||||
f.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void init()
|
||||
@@ -73,13 +97,12 @@ public class TestDialogTypeAhead {
|
||||
ok.addKeyListener(new KeyAdapter() {
|
||||
public void keyPressed(KeyEvent e) {
|
||||
System.err.println("OK pressed");
|
||||
d.dispose();
|
||||
f.dispose();
|
||||
// Typed-ahead key events should only be accepted if
|
||||
// they arrive after FOCUS_GAINED
|
||||
if (gotFocus) {
|
||||
pressSema.raise();
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
ok.addFocusListener(new FocusAdapter() {
|
||||
@@ -112,6 +135,7 @@ public class TestDialogTypeAhead {
|
||||
{
|
||||
try {
|
||||
robot = new Robot();
|
||||
robot.setAutoDelay(100);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Can't create robot:" + e);
|
||||
}
|
||||
@@ -128,6 +152,7 @@ public class TestDialogTypeAhead {
|
||||
|
||||
robot.keyPress(KeyEvent.VK_SPACE);
|
||||
robot.keyRelease(KeyEvent.VK_SPACE);
|
||||
|
||||
try {
|
||||
robotSema.doWait(1000);
|
||||
} catch (InterruptedException ie) {
|
||||
@@ -149,13 +174,13 @@ public class TestDialogTypeAhead {
|
||||
if (!pressSema.getState()) {
|
||||
throw new RuntimeException("Type-ahead doesn't work");
|
||||
}
|
||||
|
||||
}// start()
|
||||
|
||||
private void moveMouseOver(Container c) {
|
||||
private void moveMouseOver(Component c) {
|
||||
Point p = c.getLocationOnScreen();
|
||||
Dimension d = c.getSize();
|
||||
robot.mouseMove(p.x + (int)(d.getWidth()/2), p.y + (int)(d.getHeight()/2));
|
||||
robot.mouseMove(p.x + (int)(d.getWidth()/2),
|
||||
p.y + (int)(d.getHeight()/2));
|
||||
}
|
||||
private void waitForIdle() {
|
||||
try {
|
||||
@@ -209,7 +234,10 @@ public class TestDialogTypeAhead {
|
||||
}
|
||||
comp.removeFocusListener(fa);
|
||||
if (!comp.isFocusOwner()) {
|
||||
throw new RuntimeException("Can't make " + comp + " focused, current owner is " + KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner());
|
||||
throw new RuntimeException("Can't make " + comp + " focused,"
|
||||
+ "current owner is "
|
||||
+ KeyboardFocusManager
|
||||
.getCurrentKeyboardFocusManager().getFocusOwner());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,4 +285,3 @@ public class TestDialogTypeAhead {
|
||||
}
|
||||
}
|
||||
}// class TestDialogTypeAhead
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ public class ActionEventTest extends Frame {
|
||||
add(list);
|
||||
setSize(400,400);
|
||||
setLayout(new FlowLayout());
|
||||
setLocationRelativeTo(null);
|
||||
pack();
|
||||
setVisible(true);
|
||||
}
|
||||
@@ -70,9 +71,9 @@ public class ActionEventTest extends Frame {
|
||||
|
||||
if ((md & expectedMask) != expectedMask) {
|
||||
|
||||
robot.keyRelease(KeyEvent.VK_ALT);
|
||||
robot.keyRelease(KeyEvent.VK_SHIFT);
|
||||
robot.keyRelease(KeyEvent.VK_CONTROL);
|
||||
robot.keyRelease(KeyEvent.VK_SHIFT);
|
||||
robot.keyRelease(KeyEvent.VK_ALT);
|
||||
dispose();
|
||||
throw new RuntimeException("Action Event modifiers are not"
|
||||
+ " set correctly.");
|
||||
@@ -87,9 +88,9 @@ public class ActionEventTest extends Frame {
|
||||
// Press Enter on list item, to generate action event.
|
||||
robot.keyPress(KeyEvent.VK_ENTER);
|
||||
robot.keyRelease(KeyEvent.VK_ENTER);
|
||||
robot.keyRelease(KeyEvent.VK_ALT);
|
||||
robot.keyRelease(KeyEvent.VK_SHIFT);
|
||||
robot.keyRelease(KeyEvent.VK_CONTROL);
|
||||
robot.keyRelease(KeyEvent.VK_SHIFT);
|
||||
robot.keyRelease(KeyEvent.VK_ALT);
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -25,6 +25,7 @@ import java.awt.Frame;
|
||||
import java.awt.Point;
|
||||
import java.awt.Robot;
|
||||
import java.awt.Rectangle;
|
||||
import javax.swing.SwingUtilities;
|
||||
|
||||
/*
|
||||
* @test
|
||||
@@ -42,23 +43,21 @@ public class GetMousePositionWithOverlay {
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
robot = new Robot();
|
||||
robot.setAutoDelay(100);
|
||||
|
||||
try{
|
||||
constructTestUI();
|
||||
} catch (Exception e) {
|
||||
try {
|
||||
SwingUtilities.invokeAndWait(GetMousePositionWithOverlay::constructTestUI);
|
||||
doTest();
|
||||
} finally {
|
||||
dispose();
|
||||
throw new RuntimeException("Unexpected Exception!");
|
||||
}
|
||||
|
||||
robot.waitForIdle();
|
||||
|
||||
doTest();
|
||||
dispose();
|
||||
}
|
||||
|
||||
private static void doTest() {
|
||||
|
||||
frontFrame.toFront();
|
||||
private static void doTest() throws Exception {
|
||||
SwingUtilities.invokeAndWait(() -> frontFrame.toFront());
|
||||
robot.waitForIdle();
|
||||
|
||||
Rectangle bounds = new Rectangle(frontFrame.getLocationOnScreen(), frontFrame.getSize());
|
||||
@@ -67,45 +66,44 @@ public class GetMousePositionWithOverlay {
|
||||
|
||||
Point pos = backFrame.getMousePosition();
|
||||
if (pos != null) {
|
||||
dispose();
|
||||
throw new RuntimeException("Test failed. Mouse position should be null but was " + pos);
|
||||
}
|
||||
|
||||
pos = frontFrame.getMousePosition();
|
||||
if (pos == null) {
|
||||
dispose();
|
||||
throw new RuntimeException("Test failed. Mouse position should not be null");
|
||||
}
|
||||
|
||||
robot.mouseMove(189, 189);
|
||||
robot.mouseMove(bounds.x + bounds.width + 5, bounds.y + bounds.height + 5);
|
||||
robot.waitForIdle();
|
||||
|
||||
pos = backFrame.getMousePosition();
|
||||
if (pos == null) {
|
||||
dispose();
|
||||
throw new RuntimeException("Test failed. Mouse position should not be null");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void dispose() {
|
||||
private static void dispose() throws Exception {
|
||||
SwingUtilities.invokeAndWait(() -> {
|
||||
if (backFrame != null) {
|
||||
backFrame.dispose();
|
||||
}
|
||||
|
||||
if (backFrame != null) {
|
||||
backFrame.dispose();
|
||||
}
|
||||
|
||||
if (frontFrame != null) {
|
||||
frontFrame.dispose();
|
||||
}
|
||||
if (frontFrame != null) {
|
||||
frontFrame.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void constructTestUI() {
|
||||
backFrame = new Frame();
|
||||
backFrame.setUndecorated(true);
|
||||
backFrame.setBounds(100, 100, 100, 100);
|
||||
backFrame.setResizable(false);
|
||||
backFrame.setVisible(true);
|
||||
|
||||
frontFrame = new Frame();
|
||||
frontFrame.setUndecorated(true);
|
||||
frontFrame.setBounds(120, 120, 60, 60);
|
||||
frontFrame.setResizable(false);
|
||||
frontFrame.setVisible(true);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2021, 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
|
||||
@@ -23,8 +23,10 @@
|
||||
|
||||
import test.java.awt.regtesthelpers.Util;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import javax.swing.SwingUtilities;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Point;
|
||||
import java.awt.Robot;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionAdapter;
|
||||
|
||||
@@ -33,11 +35,10 @@ import java.awt.event.MouseMotionAdapter;
|
||||
* @key headful
|
||||
* @bug 8012026 8027154
|
||||
* @summary Component.getMousePosition() does not work in an applet on MacOS
|
||||
* @author Petr Pchelko
|
||||
* @library ../../regtesthelpers
|
||||
* @build Util
|
||||
* @compile GetMousePositionWithPopup.java
|
||||
* @run main/othervm GetMousePositionWithPopup
|
||||
* @run main GetMousePositionWithPopup
|
||||
*/
|
||||
|
||||
public class GetMousePositionWithPopup {
|
||||
@@ -48,6 +49,7 @@ public class GetMousePositionWithPopup {
|
||||
public static void main(String[] args) throws Exception {
|
||||
try {
|
||||
Robot r = Util.createRobot();
|
||||
r.setAutoDelay(100);
|
||||
r.mouseMove(0, 0);
|
||||
Util.waitForIdle(null);
|
||||
|
||||
@@ -61,7 +63,7 @@ public class GetMousePositionWithPopup {
|
||||
Util.waitForIdle(null);
|
||||
r.mouseMove(149, 149);
|
||||
Util.waitForIdle(null);
|
||||
r.mouseMove(150, 150);
|
||||
r.mouseMove(170, 170);
|
||||
Util.waitForIdle(null);
|
||||
|
||||
} finally {
|
||||
@@ -78,20 +80,25 @@ public class GetMousePositionWithPopup {
|
||||
private static void constructTestUI() {
|
||||
frame1 = new Frame();
|
||||
frame1.setBounds(100, 100, 100, 100);
|
||||
frame1.setVisible(true);
|
||||
frame1.addMouseMotionListener(new MouseMotionAdapter() {
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
if (frame2 != null) {
|
||||
return;
|
||||
}
|
||||
frame2 = new Frame();
|
||||
frame2.setBounds(120, 120, 120, 120);
|
||||
|
||||
frame2.setVisible(true);
|
||||
frame2.addMouseMotionListener(new MouseMotionAdapter() {
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e)
|
||||
{
|
||||
Point positionInFrame2 = frame2.getMousePosition();
|
||||
if (positionInFrame2.x != 30 || positionInFrame2.y != 30) {
|
||||
throw new RuntimeException("Wrong position reported. Should be [30, 30] but was [" +
|
||||
int deltaX = Math.abs(50 - positionInFrame2.x);
|
||||
int deltaY = Math.abs(50 - positionInFrame2.y);
|
||||
if (deltaX > 2 || deltaY > 2) {
|
||||
throw new RuntimeException("Wrong position reported. Should be [50, 50] but was [" +
|
||||
positionInFrame2.x + ", " + positionInFrame2.y + "]");
|
||||
}
|
||||
|
||||
@@ -101,10 +108,7 @@ public class GetMousePositionWithPopup {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
frame2.setVisible(true);
|
||||
}
|
||||
});
|
||||
frame1.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,12 +101,14 @@ public class AutoScrollOnSelectAndAppend {
|
||||
public AutoScrollOnSelectAndAppend() {
|
||||
try {
|
||||
robot = new Robot();
|
||||
robot.setAutoDelay(100);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Robot Creation Failed.");
|
||||
}
|
||||
frame = new Frame();
|
||||
frame.setSize(200, 200);
|
||||
frame.setLayout(new FlowLayout());
|
||||
frame.setLocationRelativeTo(null);
|
||||
|
||||
textArea = new TextArea(5, 20);
|
||||
composeTextArea();
|
||||
@@ -128,11 +130,11 @@ public class AutoScrollOnSelectAndAppend {
|
||||
// Delay to make sure auto scroll is finished.
|
||||
robot.waitForIdle();
|
||||
robot.delay(500);
|
||||
robot.mousePress(InputEvent.BUTTON1_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_MASK);
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.delay(100);
|
||||
robot.mousePress(InputEvent.BUTTON1_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_MASK);
|
||||
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
|
||||
robot.waitForIdle();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2021, 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
|
||||
@@ -54,6 +54,10 @@ public class PopupMenuLeakTest {
|
||||
static final AtomicReference<WeakReference<PopupMenu>> popupWeakReference = new AtomicReference<>();
|
||||
static ExtendedRobot robot;
|
||||
public static void main(String[] args) throws Exception {
|
||||
if (!SystemTray.isSupported()) {
|
||||
System.out.println("SystemTray not supported. Skipping the test.");
|
||||
return;
|
||||
}
|
||||
robot = new ExtendedRobot();
|
||||
SwingUtilities.invokeAndWait(PopupMenuLeakTest::createSystemTrayIcon);
|
||||
sleep();
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
* @bug 8130655
|
||||
* @summary Tests that window owned by EmbeddedFrame can receive keyboard input
|
||||
* @requires (os.family == "mac")
|
||||
* @modules java.desktop/sun.awt
|
||||
* @modules java.desktop/sun.awt java.desktop/sun.lwawt.macosx:open
|
||||
* @library ../../regtesthelpers
|
||||
* @build Util
|
||||
* @run main WindowOwnedByEmbeddedFrameTest
|
||||
|
||||
@@ -90,6 +90,7 @@ public class RecognizedActionTest implements AWTEventListener {
|
||||
dragGestureListener);
|
||||
|
||||
frame.getToolkit().addAWTEventListener(this, AWTEvent.MOUSE_EVENT_MASK);
|
||||
frame.setLocationRelativeTo(null);
|
||||
frame.setVisible(true);
|
||||
Thread.sleep(100);
|
||||
|
||||
@@ -165,10 +166,10 @@ public class RecognizedActionTest implements AWTEventListener {
|
||||
break;
|
||||
|
||||
case InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK:
|
||||
robot.keyRelease(KeyEvent.VK_CONTROL);
|
||||
robot.waitForIdle();
|
||||
robot.keyRelease(KeyEvent.VK_SHIFT);
|
||||
robot.waitForIdle();
|
||||
robot.keyRelease(KeyEvent.VK_CONTROL);
|
||||
robot.waitForIdle();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 2021, 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
|
||||
@@ -49,44 +49,70 @@
|
||||
" move the pointer between B to C.",
|
||||
*/
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Button;
|
||||
import java.awt.Component;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Point;
|
||||
import java.awt.Robot;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
import test.java.awt.regtesthelpers.Util;
|
||||
import javax.swing.*;
|
||||
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
|
||||
public class SpuriousExitEnter_3 {
|
||||
static JFrame frame = new JFrame("SpuriousExitEnter_3_LW");
|
||||
static JButton jbutton = new JButton("jbutton");
|
||||
static Frame frame1 = new Frame("SpuriousExitEnter_3_HW");
|
||||
static Button button1 = new Button("button");
|
||||
static JFrame frame;
|
||||
static JButton jbutton;
|
||||
|
||||
static EnterExitAdapter frameAdapter;
|
||||
static EnterExitAdapter buttonAdapter;
|
||||
static Robot r = Util.createRobot();
|
||||
static Frame frame1;
|
||||
static Button button1;
|
||||
|
||||
public static void testCase(Window w, Component comp) {
|
||||
frameAdapter = new EnterExitAdapter(w);
|
||||
buttonAdapter = new EnterExitAdapter(comp);
|
||||
static final Robot r = Util.createRobot();
|
||||
|
||||
w.addMouseListener(frameAdapter);
|
||||
comp.addMouseListener(buttonAdapter);
|
||||
static volatile EnterExitAdapter frameAdapter;
|
||||
static volatile EnterExitAdapter buttonAdapter;
|
||||
static volatile Point centerA;
|
||||
static volatile Point centerB;
|
||||
static volatile Point centerC_1 ;
|
||||
static volatile Point centerC_2;
|
||||
|
||||
w.setSize(200, 200);
|
||||
w.add(comp, BorderLayout.NORTH);
|
||||
w.setLocationRelativeTo(null);
|
||||
w.setVisible(true);
|
||||
public static void testCase(Window w, Component comp) throws InterruptedException, InvocationTargetException {
|
||||
EventQueue.invokeAndWait(()-> {
|
||||
frameAdapter = new EnterExitAdapter(w);
|
||||
buttonAdapter = new EnterExitAdapter(comp);
|
||||
|
||||
Point centerA = new Point(comp.getLocationOnScreen().x + comp.getWidth() / 2,
|
||||
comp.getLocationOnScreen().y + comp.getHeight() / 2);
|
||||
Point centerB = new Point(w.getLocationOnScreen().x + w.getWidth() / 2,
|
||||
w.getLocationOnScreen().y + w.getHeight() / 2);
|
||||
//for moving from A outside: don't cross the A area. Move straight to the right.
|
||||
Point centerC_1 = new Point(w.getLocationOnScreen().x + w.getWidth() + 20, //go right off the border
|
||||
comp.getLocationOnScreen().y + comp.getHeight() / 2); //don't cross the A area!
|
||||
w.addMouseListener(frameAdapter);
|
||||
comp.addMouseListener(buttonAdapter);
|
||||
|
||||
w.setSize(200, 200);
|
||||
w.add(comp, BorderLayout.NORTH);
|
||||
w.setLocationRelativeTo(null);
|
||||
w.setVisible(true);
|
||||
});
|
||||
|
||||
r.waitForIdle();
|
||||
r.delay(1000);
|
||||
|
||||
EventQueue.invokeAndWait(()-> {
|
||||
centerA = new Point(comp.getLocationOnScreen().x + comp.getWidth() / 2,
|
||||
comp.getLocationOnScreen().y + comp.getHeight() / 2);
|
||||
centerB = new Point(w.getLocationOnScreen().x + w.getWidth() / 2,
|
||||
w.getLocationOnScreen().y + w.getHeight() / 2);
|
||||
//for moving from A outside: don't cross the A area. Move straight to the right.
|
||||
centerC_1 = new Point(w.getLocationOnScreen().x + w.getWidth() + 20, //go right off the border
|
||||
comp.getLocationOnScreen().y + comp.getHeight() / 2); //don't cross the A area!
|
||||
|
||||
//for moving from B outside: don't cross the B area. Move straight to the bottom.
|
||||
centerC_2 = new Point(w.getLocationOnScreen().x + w.getWidth() / 2,
|
||||
w.getLocationOnScreen().y + w.getHeight() + 20); //go below the bottom border
|
||||
});
|
||||
|
||||
//for moving from B outside: don't cross the B area. Move straight to the bottom.
|
||||
Point centerC_2 = new Point(w.getLocationOnScreen().x + w.getWidth() / 2,
|
||||
w.getLocationOnScreen().y + w.getHeight() + 20); //go below the bottom border
|
||||
//A and B areas
|
||||
Util.pointOnComp(comp, r);
|
||||
Util.waitForIdle(r);
|
||||
@@ -118,12 +144,23 @@ public class SpuriousExitEnter_3 {
|
||||
Util.waitForIdle(r);
|
||||
}
|
||||
|
||||
public static void main(String []s)
|
||||
{
|
||||
//LW case:
|
||||
testCase(frame, jbutton);
|
||||
//HW case
|
||||
testCase(frame1, button1);
|
||||
|
||||
public static void main(String []s) throws InterruptedException, InvocationTargetException {
|
||||
EventQueue.invokeAndWait(() -> {
|
||||
frame = new JFrame("SpuriousExitEnter_3_LW");
|
||||
jbutton = new JButton("jbutton");
|
||||
|
||||
frame1 = new Frame("SpuriousExitEnter_3_HW");
|
||||
button1 = new Button("button");
|
||||
});
|
||||
|
||||
try {
|
||||
testCase(frame, jbutton); //LW case
|
||||
testCase(frame1, button1); //HW case
|
||||
} finally {
|
||||
EventQueue.invokeLater(frame::dispose);
|
||||
EventQueue.invokeLater(frame1::dispose);
|
||||
}
|
||||
}
|
||||
|
||||
private static void moveBetween(Robot r, Point first, Point second) {
|
||||
@@ -150,9 +187,9 @@ public class SpuriousExitEnter_3 {
|
||||
|
||||
|
||||
class EnterExitAdapter extends MouseAdapter {
|
||||
private Component target;
|
||||
private int enteredEventCount = 0;
|
||||
private int exitedEventCount = 0;
|
||||
private final Component target;
|
||||
private volatile int enteredEventCount = 0;
|
||||
private volatile int exitedEventCount = 0;
|
||||
|
||||
public EnterExitAdapter(Component target) {
|
||||
this.target = target;
|
||||
@@ -170,7 +207,7 @@ class EnterExitAdapter extends MouseAdapter {
|
||||
}
|
||||
|
||||
public void zeroCounters(){
|
||||
System.out.println("Zeroeing on " +target.getClass().getName());
|
||||
System.out.println("Zeroing on " +target.getClass().getName());
|
||||
enteredEventCount = 0;
|
||||
exitedEventCount = 0;
|
||||
}
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 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 6328154 6962082
|
||||
* @summary ensure that ascii, and latin-1 text without combining marks, both layout faster
|
||||
* than latin-1 text with combining marks. The presumption is then that the canonical
|
||||
* GSUB table is being run only on the latter and not on either of the former.
|
||||
*/
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.TextLayout;
|
||||
|
||||
import static java.awt.Font.*;
|
||||
|
||||
public class CombiningPerf {
|
||||
private static Font font;
|
||||
private static FontRenderContext frc;
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
System.err.println("start");
|
||||
|
||||
GraphicsEnvironment.getLocalGraphicsEnvironment();
|
||||
|
||||
font = new Font("Lucida Sans Regular", PLAIN, 12);
|
||||
frc = new FontRenderContext(null, false, false);
|
||||
|
||||
String ascii = "the characters are critical noodles?";
|
||||
String french = "l'aper\u00e7u caract\u00e8re one \u00e9t\u00e9 cr\u00e9\u00e9s";
|
||||
String frenchX = "l'aper\u00e7u caracte\u0300re one e\u0301te\u0301 ere\u0301e\u0301s";
|
||||
|
||||
// warmup
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
TextLayout tl = new TextLayout(french, font, frc);
|
||||
tl = new TextLayout(ascii, font, frc);
|
||||
tl = new TextLayout(frenchX, font, frc);
|
||||
}
|
||||
/**/
|
||||
long atime = test(ascii);
|
||||
System.err.println("atime: " + (atime/1000000.0) + " length: " + ascii.length());
|
||||
|
||||
long ftime = test(french);
|
||||
System.err.println("ftime: " + (ftime/1000000.0) + " length: " + french.length());
|
||||
|
||||
long xtime = test(frenchX);
|
||||
System.err.println("xtime: " + (xtime/1000000.0) + " length: " + frenchX.length());
|
||||
|
||||
long limit = xtime * 2 / 3;
|
||||
if (atime > limit || ftime > limit) {
|
||||
throw new Exception("took too long");
|
||||
}
|
||||
/**/
|
||||
}
|
||||
|
||||
private static long test(String text) {
|
||||
long start = System.nanoTime();
|
||||
for (int i = 0; i < 2000; ++i) {
|
||||
TextLayout tl = new TextLayout(text, font, frc);
|
||||
}
|
||||
return System.nanoTime() - start;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@@ -36,7 +36,7 @@ import static java.awt.Transparency.TRANSLUCENT;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8255722
|
||||
* @bug 8255722 8255724
|
||||
* @key headful
|
||||
*/
|
||||
public class BlitRotateClippedArea {
|
||||
@@ -103,10 +103,15 @@ public class BlitRotateClippedArea {
|
||||
throws IOException {
|
||||
for (int x = 0; x < gold.getWidth(); ++x) {
|
||||
for (int y = 0; y < gold.getHeight(); ++y) {
|
||||
if (gold.getRGB(x, y) != img.getRGB(x, y)) {
|
||||
ImageIO.write(gold, "png", new File("gold.png"));
|
||||
ImageIO.write(img, "png", new File("snapshot.png"));
|
||||
throw new RuntimeException("Test failed.");
|
||||
Color goldColor = new Color(gold.getRGB(x, y));
|
||||
Color actualColor = new Color(img.getRGB(x, y));
|
||||
if ((Math.abs(goldColor.getRed() - actualColor.getRed()) > 1) ||
|
||||
(Math.abs(goldColor.getGreen() - actualColor.getGreen()) > 1) ||
|
||||
(Math.abs(goldColor.getBlue() - actualColor.getBlue()) > 1)) {
|
||||
ImageIO.write(gold, "png", new File("gold.png"));
|
||||
ImageIO.write(img, "png", new File("snapshot.png"));
|
||||
throw new RuntimeException("Test failed for pixel :"
|
||||
+ x + "/" + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2002, 2020, 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
|
||||
# @summary Verify that unsupported encodings are handled gracefully.
|
||||
# @bug 4629543 4785473
|
||||
#
|
||||
# @run shell/timeout=300 CheckEncodings.sh
|
||||
|
||||
# set platform-dependent variables
|
||||
OS=`uname -s`
|
||||
case "$OS" in
|
||||
Linux | Darwin | AIX ) ;;
|
||||
Windows* | CYGWIN* )
|
||||
echo "Passed"; exit 0 ;;
|
||||
* ) echo "Unrecognized system!" ; exit 1 ;;
|
||||
esac
|
||||
|
||||
expectPass() {
|
||||
if [ $1 -eq 0 ]
|
||||
then echo "--- passed as expected"
|
||||
else
|
||||
echo "--- failed"
|
||||
exit $1
|
||||
fi
|
||||
}
|
||||
|
||||
runTest() {
|
||||
echo "Testing:" ${1}
|
||||
set LC_ALL="${1}"; export LC_ALL
|
||||
locale
|
||||
${TESTJAVA}/bin/java ${TESTVMOPTS} -version 2>&1
|
||||
expectPass $?
|
||||
}
|
||||
|
||||
|
||||
locale -a > machine_locales.txt
|
||||
|
||||
# ${TESTSRC}/locales.txt contains the list of "fully supported" locales
|
||||
# as defined by the i18n doc for 1.4
|
||||
cat ${TESTSRC}/locales.txt machine_locales.txt | sort | uniq > locale_union.txt
|
||||
|
||||
for i in `xargs < locale_union.txt` ; do
|
||||
runTest ${i}
|
||||
done
|
||||
|
||||
# random strings
|
||||
for i in FOO 1234 ZZ; do
|
||||
runTest ${i}
|
||||
done
|
||||
@@ -1,25 +0,0 @@
|
||||
ar_SA
|
||||
zh_CN
|
||||
zh_TW
|
||||
nl_NL
|
||||
nl_NL_EURO
|
||||
en_AU
|
||||
en_CA
|
||||
en_GB
|
||||
en_US
|
||||
fr_CA
|
||||
fr_FR
|
||||
fr_FR_EURO
|
||||
de_DE
|
||||
de_DE_EURO
|
||||
iw_IL
|
||||
hi_IN
|
||||
it_IT
|
||||
it_IT_EURO
|
||||
ja_JP
|
||||
ko_KR
|
||||
pt_BR
|
||||
es_ES
|
||||
es_ES_EURO
|
||||
sv_SE
|
||||
th_TH
|
||||
76
test/jdk/java/lang/module/ModuleDescriptorHashCodeTest.java
Normal file
76
test/jdk/java/lang/module/ModuleDescriptorHashCodeTest.java
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 org.testng.annotations.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.module.ModuleDescriptor;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotSame;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8275509
|
||||
* @run testng ModuleDescriptorHashCodeTest
|
||||
* @run testng/othervm -Xshare:off ModuleDescriptorHashCodeTest
|
||||
* @summary Tests the ModuleDescriptor.hashCode() for boot layer modules
|
||||
*/
|
||||
public class ModuleDescriptorHashCodeTest {
|
||||
|
||||
/**
|
||||
* Verifies that the ModuleDescriptor.hashCode() returned by a boot layer module is
|
||||
* the same as that returned by a ModuleDescriptor constructed from the ModuleDescriptor.Builder
|
||||
* for the same module.
|
||||
*/
|
||||
@Test
|
||||
public void testBootModuleDescriptor() throws Exception {
|
||||
Set<Module> bootModules = ModuleLayer.boot().modules();
|
||||
for (Module bootModule : bootModules) {
|
||||
System.out.println("Testing module descriptor of boot module " + bootModule);
|
||||
ModuleDescriptor bootMD = bootModule.getDescriptor();
|
||||
ModuleDescriptor mdFromBuilder = fromModuleInfoClass(bootModule);
|
||||
// verify that this object is indeed a different object instance than the boot module descriptor
|
||||
// to prevent any artificial passing of the test
|
||||
assertNotSame(mdFromBuilder, bootMD, "ModuleDescriptor loaded from boot layer and " +
|
||||
"one created from module-info.class unexpectedly returned the same instance");
|
||||
assertEquals(mdFromBuilder.hashCode(), bootMD.hashCode(),
|
||||
"Unexpected ModuleDescriptor.hashCode() for " + mdFromBuilder);
|
||||
assertEquals(mdFromBuilder.compareTo(bootMD), 0,
|
||||
"Unexpected ModuleDescriptor.compareTo() for " + mdFromBuilder);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a ModuleDescriptor parsed out of the module-info.class of the passed Module
|
||||
private static ModuleDescriptor fromModuleInfoClass(Module module) throws IOException {
|
||||
try (InputStream moduleInfo = module.getResourceAsStream("module-info.class")) {
|
||||
if (moduleInfo == null) {
|
||||
throw new RuntimeException("Could not locate module-info.class in " + module);
|
||||
}
|
||||
// internally calls ModuleDescriptor.Builder
|
||||
return ModuleDescriptor.read(moduleInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,18 +23,16 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Verifies that UNIX socket doesn't throw when opened with
|
||||
* a non-default file system installed. NB: the opened socket isn't
|
||||
* supposed to be useable.
|
||||
* @summary Verifies that an attempt to call SelectorProvider.provider().openSelector()
|
||||
* on a non-default file system succeeds.
|
||||
* @library /test/lib
|
||||
* @build TestProvider UnixSocketInNonDefaultFS
|
||||
* @run main/othervm -Djava.nio.file.spi.DefaultFileSystemProvider=TestProvider UnixSocketInNonDefaultFS
|
||||
*/
|
||||
import java.nio.channels.ServerSocketChannel;
|
||||
import java.net.StandardProtocolFamily;
|
||||
import java.nio.channels.spi.SelectorProvider;
|
||||
|
||||
public class UnixSocketInNonDefaultFS {
|
||||
public static void main(String args[]) throws java.io.IOException {
|
||||
ServerSocketChannel server = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
|
||||
SelectorProvider.provider().openSelector();
|
||||
}
|
||||
}
|
||||
|
||||
275
test/jdk/java/util/Properties/PropertiesStoreTest.java
Normal file
275
test/jdk/java/util/Properties/PropertiesStoreTest.java
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 org.testng.Assert;
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Writer;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary tests the order in which the Properties.store() method writes out the properties
|
||||
* @bug 8231640
|
||||
* @run testng PropertiesStoreTest
|
||||
*/
|
||||
public class PropertiesStoreTest {
|
||||
|
||||
private static final String DATE_FORMAT_PATTERN = "EEE MMM dd HH:mm:ss zzz uuuu";
|
||||
|
||||
@DataProvider(name = "propsProvider")
|
||||
private Object[][] createProps() {
|
||||
final Properties simple = new Properties();
|
||||
simple.setProperty("1", "one");
|
||||
simple.setProperty("2", "two");
|
||||
simple.setProperty("10", "ten");
|
||||
simple.setProperty("02", "zero-two");
|
||||
simple.setProperty("3", "three");
|
||||
simple.setProperty("0", "zero");
|
||||
simple.setProperty("00", "zero-zero");
|
||||
simple.setProperty("0", "zero-again");
|
||||
|
||||
final Properties specialChars = new Properties();
|
||||
// some special chars
|
||||
simple.setProperty(" 1", "space-one");
|
||||
simple.setProperty("\t 3 7 \n", "tab-space-three-space-seven-space-newline");
|
||||
// add some simple chars
|
||||
simple.setProperty("3", "three");
|
||||
simple.setProperty("0", "zero");
|
||||
|
||||
final Properties overrideCallsSuper = new OverridesEntrySetCallsSuper();
|
||||
overrideCallsSuper.putAll(simple);
|
||||
|
||||
final OverridesEntrySet overridesEntrySet = new OverridesEntrySet();
|
||||
overridesEntrySet.putAll(simple);
|
||||
|
||||
final Properties doesNotOverrideEntrySet = new DoesNotOverrideEntrySet();
|
||||
doesNotOverrideEntrySet.putAll(simple);
|
||||
|
||||
return new Object[][]{
|
||||
{simple, naturalOrder(simple)},
|
||||
{specialChars, naturalOrder(specialChars)},
|
||||
{overrideCallsSuper, naturalOrder(overrideCallsSuper)},
|
||||
{overridesEntrySet, overridesEntrySet.expectedKeyOrder()},
|
||||
{doesNotOverrideEntrySet, naturalOrder(doesNotOverrideEntrySet)}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the {@link Properties#store(Writer, String)} API writes out the properties
|
||||
* in the expected order
|
||||
*/
|
||||
@Test(dataProvider = "propsProvider")
|
||||
public void testStoreWriterKeyOrder(final Properties props, final String[] expectedOrder) throws Exception {
|
||||
// Properties.store(...) to a temp file
|
||||
final Path tmpFile = Files.createTempFile("8231640", "props");
|
||||
try (final Writer writer = Files.newBufferedWriter(tmpFile)) {
|
||||
props.store(writer, null);
|
||||
}
|
||||
testStoreKeyOrder(props, tmpFile, expectedOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the {@link Properties#store(OutputStream, String)} API writes out the properties
|
||||
* in the expected order
|
||||
*/
|
||||
@Test(dataProvider = "propsProvider")
|
||||
public void testStoreOutputStreamKeyOrder(final Properties props, final String[] expectedOrder) throws Exception {
|
||||
// Properties.store(...) to a temp file
|
||||
final Path tmpFile = Files.createTempFile("8231640", "props");
|
||||
try (final OutputStream os = Files.newOutputStream(tmpFile)) {
|
||||
props.store(os, null);
|
||||
}
|
||||
testStoreKeyOrder(props, tmpFile, expectedOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link Properties#load(InputStream) Loads a Properties instance} from the passed
|
||||
* {@code Path} and then verifies that:
|
||||
* - the loaded properties instance "equals" the passed (original) "props" instance
|
||||
* - the order in which the properties appear in the file represented by the path
|
||||
* is the same as the passed "expectedOrder"
|
||||
*/
|
||||
private void testStoreKeyOrder(final Properties props, final Path storedProps,
|
||||
final String[] expectedOrder) throws Exception {
|
||||
// Properties.load(...) from that stored file and verify that the loaded
|
||||
// Properties has expected content
|
||||
final Properties loaded = new Properties();
|
||||
try (final InputStream is = Files.newInputStream(storedProps)) {
|
||||
loaded.load(is);
|
||||
}
|
||||
Assert.assertEquals(loaded, props, "Unexpected properties loaded from stored state");
|
||||
|
||||
// now read lines from the stored file and keep track of the order in which the keys were
|
||||
// found in that file. Compare that order with the expected store order of the keys.
|
||||
final List<String> actualOrder;
|
||||
try (final BufferedReader reader = Files.newBufferedReader(storedProps)) {
|
||||
actualOrder = readInOrder(reader);
|
||||
}
|
||||
Assert.assertEquals(actualOrder.size(), expectedOrder.length,
|
||||
"Unexpected number of keys read from stored properties");
|
||||
if (!Arrays.equals(actualOrder.toArray(new String[0]), expectedOrder)) {
|
||||
Assert.fail("Unexpected order of stored property keys. Expected order: " + Arrays.toString(expectedOrder)
|
||||
+ ", found order: " + actualOrder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that {@link Properties#store(Writer, String)} writes out a proper date comment
|
||||
*/
|
||||
@Test
|
||||
public void testStoreWriterDateComment() throws Exception {
|
||||
final Properties props = new Properties();
|
||||
props.setProperty("a", "b");
|
||||
final Path tmpFile = Files.createTempFile("8231640", "props");
|
||||
try (final Writer writer = Files.newBufferedWriter(tmpFile)) {
|
||||
props.store(writer, null);
|
||||
}
|
||||
testDateComment(tmpFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that {@link Properties#store(OutputStream, String)} writes out a proper date comment
|
||||
*/
|
||||
@Test
|
||||
public void testStoreOutputStreamDateComment() throws Exception {
|
||||
final Properties props = new Properties();
|
||||
props.setProperty("a", "b");
|
||||
final Path tmpFile = Files.createTempFile("8231640", "props");
|
||||
try (final Writer writer = Files.newBufferedWriter(tmpFile)) {
|
||||
props.store(writer, null);
|
||||
}
|
||||
testDateComment(tmpFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads each line in the {@code file} and verifies that there is only one comment line
|
||||
* and that comment line can be parsed into a {@link java.util.Date}
|
||||
*/
|
||||
private void testDateComment(Path file) throws Exception {
|
||||
String comment = null;
|
||||
try (final BufferedReader reader = Files.newBufferedReader(file)) {
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith("#")) {
|
||||
if (comment != null) {
|
||||
Assert.fail("More than one comment line found in the stored properties file " + file);
|
||||
}
|
||||
comment = line.substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (comment == null) {
|
||||
Assert.fail("No comment line found in the stored properties file " + file);
|
||||
}
|
||||
try {
|
||||
DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN).parse(comment);
|
||||
} catch (DateTimeParseException pe) {
|
||||
Assert.fail("Unexpected date comment: " + comment, pe);
|
||||
}
|
||||
}
|
||||
|
||||
// returns the property keys in their natural order
|
||||
private static String[] naturalOrder(final Properties props) {
|
||||
return new TreeSet<>(props.stringPropertyNames()).toArray(new String[0]);
|
||||
}
|
||||
|
||||
// reads each non-comment line and keeps track of the order in which the property key lines
|
||||
// were read
|
||||
private static List<String> readInOrder(final BufferedReader reader) throws IOException {
|
||||
final List<String> readKeys = new ArrayList<>();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith("#")) {
|
||||
continue;
|
||||
}
|
||||
final String key = line.substring(0, line.indexOf("="));
|
||||
// the Properties.store(...) APIs write out the keys in a specific format for certain
|
||||
// special characters. Our test uses some of the keys which have those special characters.
|
||||
// Here we handle such special character conversion (for only those characters that this test uses).
|
||||
// replace the backslash character followed by the t character with the tab character
|
||||
String replacedKey = key.replace("\\t", "\t");
|
||||
// replace the backslash character followed by the n character with the newline character
|
||||
replacedKey = replacedKey.replace("\\n", "\n");
|
||||
// replace backslash character followed by the space character with the space character
|
||||
replacedKey = replacedKey.replace("\\ ", " ");
|
||||
readKeys.add(replacedKey);
|
||||
}
|
||||
return readKeys;
|
||||
}
|
||||
|
||||
// Extends java.util.Properties and overrides entrySet() to return a reverse
|
||||
// sorted entries set
|
||||
private static class OverridesEntrySet extends Properties {
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<Map.Entry<Object, Object>> entrySet() {
|
||||
// return a reverse sorted entries set
|
||||
var entries = super.entrySet();
|
||||
Comparator<Map.Entry<String, String>> comparator = Map.Entry.comparingByKey(Comparator.reverseOrder());
|
||||
TreeSet<Map.Entry<String, String>> reverseSorted = new TreeSet<>(comparator);
|
||||
reverseSorted.addAll((Set) entries);
|
||||
return (Set) reverseSorted;
|
||||
}
|
||||
|
||||
String[] expectedKeyOrder() {
|
||||
// returns in reverse order of the property keys' natural ordering
|
||||
var keys = new ArrayList<>(stringPropertyNames());
|
||||
keys.sort(Comparator.reverseOrder());
|
||||
return keys.toArray(new String[0]);
|
||||
}
|
||||
}
|
||||
|
||||
// Extends java.util.Properties and overrides entrySet() to just return "super.entrySet()"
|
||||
private static class OverridesEntrySetCallsSuper extends Properties {
|
||||
@Override
|
||||
public Set<Map.Entry<Object, Object>> entrySet() {
|
||||
return super.entrySet();
|
||||
}
|
||||
}
|
||||
|
||||
// Extends java.util.Properties but doesn't override entrySet() method
|
||||
private static class DoesNotOverrideEntrySet extends Properties {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DoesNotOverrideEntrySet - " + super.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
494
test/jdk/java/util/Properties/StoreReproducibilityTest.java
Normal file
494
test/jdk/java/util/Properties/StoreReproducibilityTest.java
Normal file
@@ -0,0 +1,494 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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 jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Tests that the Properties.store() APIs generate output that is reproducible
|
||||
* @bug 8231640
|
||||
* @library /test/lib
|
||||
* @run driver StoreReproducibilityTest
|
||||
*/
|
||||
public class StoreReproducibilityTest {
|
||||
|
||||
private static final String DATE_FORMAT_PATTERN = "EEE MMM dd HH:mm:ss zzz uuuu";
|
||||
private static final String SYS_PROP_JAVA_PROPERTIES_DATE = "java.properties.date";
|
||||
private static final DateTimeFormatter reproducibleDateTimeFormatter = DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN)
|
||||
.withLocale(Locale.ROOT).withZone(ZoneOffset.UTC);
|
||||
|
||||
public static void main(final String[] args) throws Exception {
|
||||
// no security manager enabled
|
||||
testWithoutSecurityManager();
|
||||
// security manager enabled and security policy explicitly allows
|
||||
// read permissions on java.properties.date system property
|
||||
testWithSecMgrExplicitPermission();
|
||||
// security manager enabled and no explicit permission on java.properties.date system property
|
||||
testWithSecMgrNoSpecificPermission();
|
||||
// free form non-date value for java.properties.date system property
|
||||
testNonDateSysPropValue();
|
||||
// blank value for java.properties.date system property
|
||||
testBlankSysPropValue();
|
||||
// empty value for java.properties.date system property
|
||||
testEmptySysPropValue();
|
||||
// value for java.properties.date system property contains line terminator characters
|
||||
testMultiLineSysPropValue();
|
||||
// value for java.properties.date system property contains backslash character
|
||||
testBackSlashInSysPropValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a Java program which is responsible for using Properties.store() to write out the
|
||||
* properties to a file. The launched Java program is passed a value for the
|
||||
* {@code java.properties.date} system property and the date comment written out
|
||||
* to the file is expected to use this value.
|
||||
* The program is launched multiple times with the same value for {@code java.properties.date}
|
||||
* and the output written by each run of this program is verified to be exactly the same.
|
||||
* Additionally, the date comment that's written out is verified to be the expected date that
|
||||
* corresponds to the passed {@code java.properties.date}.
|
||||
* The launched Java program is run without any security manager
|
||||
*/
|
||||
private static void testWithoutSecurityManager() throws Exception {
|
||||
final List<Path> storedFiles = new ArrayList<>();
|
||||
final String sysPropVal = reproducibleDateTimeFormatter.format(Instant.ofEpochSecond(243535322));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final Path tmpFile = Files.createTempFile("8231640", ".props");
|
||||
storedFiles.add(tmpFile);
|
||||
final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
|
||||
"-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal,
|
||||
StoreTest.class.getName(),
|
||||
tmpFile.toString(),
|
||||
i % 2 == 0 ? "--use-outputstream" : "--use-writer");
|
||||
executeJavaProcess(processBuilder);
|
||||
assertExpectedComment(tmpFile, sysPropVal);
|
||||
if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) {
|
||||
throw new RuntimeException("Unexpected properties stored in " + tmpFile);
|
||||
}
|
||||
}
|
||||
assertAllFileContentsAreSame(storedFiles, sysPropVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a Java program which is responsible for using Properties.store() to write out the
|
||||
* properties to a file. The launched Java program is passed a value for the
|
||||
* {@code java.properties.date} system property and the date comment written out to the file
|
||||
* is expected to use this value.
|
||||
* The launched Java program is run with the default security manager and is granted
|
||||
* a {@code read} permission on {@code java.properties.date}.
|
||||
* The program is launched multiple times with the same value for {@code java.properties.date}
|
||||
* and the output written by each run of this program is verified to be exactly the same.
|
||||
* Additionally, the date comment that's written out is verified to be the expected date that
|
||||
* corresponds to the passed {@code java.properties.date}.
|
||||
*/
|
||||
private static void testWithSecMgrExplicitPermission() throws Exception {
|
||||
final Path policyFile = Files.createTempFile("8231640", ".policy");
|
||||
Files.write(policyFile, Collections.singleton("""
|
||||
grant {
|
||||
// test writes/stores to a file, so FilePermission
|
||||
permission java.io.FilePermission "<<ALL FILES>>", "read,write";
|
||||
// explicitly grant read permission on java.properties.date system property
|
||||
// to verify store() APIs work fine
|
||||
permission java.util.PropertyPermission "java.properties.date", "read";
|
||||
};
|
||||
"""));
|
||||
final List<Path> storedFiles = new ArrayList<>();
|
||||
final String sysPropVal = reproducibleDateTimeFormatter.format(Instant.ofEpochSecond(1234342423));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final Path tmpFile = Files.createTempFile("8231640", ".props");
|
||||
storedFiles.add(tmpFile);
|
||||
final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
|
||||
"-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal,
|
||||
"-Djava.security.manager",
|
||||
"-Djava.security.policy=" + policyFile.toString(),
|
||||
StoreTest.class.getName(),
|
||||
tmpFile.toString(),
|
||||
i % 2 == 0 ? "--use-outputstream" : "--use-writer");
|
||||
executeJavaProcess(processBuilder);
|
||||
assertExpectedComment(tmpFile, sysPropVal);
|
||||
if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) {
|
||||
throw new RuntimeException("Unexpected properties stored in " + tmpFile);
|
||||
}
|
||||
}
|
||||
assertAllFileContentsAreSame(storedFiles, sysPropVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a Java program which is responsible for using Properties.store() to write out the
|
||||
* properties to a file. The launched Java program is passed a value for the
|
||||
* {@code java.properties.date} system property and the date comment written out to the file
|
||||
* is expected to use this value.
|
||||
* The launched Java program is run with the default security manager and is NOT granted
|
||||
* any explicit permission for {@code java.properties.date} system property.
|
||||
* The program is launched multiple times with the same value for {@code java.properties.date}
|
||||
* and the output written by each run of this program is verified to be exactly the same.
|
||||
* Additionally, the date comment that's written out is verified to be the expected date that
|
||||
* corresponds to the passed {@code java.properties.date}.
|
||||
*/
|
||||
private static void testWithSecMgrNoSpecificPermission() throws Exception {
|
||||
final Path policyFile = Files.createTempFile("8231640", ".policy");
|
||||
Files.write(policyFile, Collections.singleton("""
|
||||
grant {
|
||||
// test writes/stores to a file, so FilePermission
|
||||
permission java.io.FilePermission "<<ALL FILES>>", "read,write";
|
||||
// no other grants, not even "read" java.properties.date system property.
|
||||
// test should still work fine and the date comment should correspond to the value of
|
||||
// java.properties.date system property.
|
||||
};
|
||||
"""));
|
||||
final List<Path> storedFiles = new ArrayList<>();
|
||||
final String sysPropVal = reproducibleDateTimeFormatter.format(Instant.ofEpochSecond(1234342423));
|
||||
for (int i = 0; i < 5; i++) {
|
||||
final Path tmpFile = Files.createTempFile("8231640", ".props");
|
||||
storedFiles.add(tmpFile);
|
||||
final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
|
||||
"-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal,
|
||||
"-Djava.security.manager",
|
||||
"-Djava.security.policy=" + policyFile.toString(),
|
||||
StoreTest.class.getName(),
|
||||
tmpFile.toString(),
|
||||
i % 2 == 0 ? "--use-outputstream" : "--use-writer");
|
||||
executeJavaProcess(processBuilder);
|
||||
assertExpectedComment(tmpFile, sysPropVal);
|
||||
if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) {
|
||||
throw new RuntimeException("Unexpected properties stored in " + tmpFile);
|
||||
}
|
||||
}
|
||||
assertAllFileContentsAreSame(storedFiles, sysPropVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a Java program which is responsible for using Properties.store() to write out the
|
||||
* properties to a file. The launched Java program is passed a {@link String#isBlank() blank} value
|
||||
* for the {@code java.properties.date} system property.
|
||||
* It is expected and verified in this test that such a value for the system property
|
||||
* will cause a comment line to be written out with only whitespaces.
|
||||
* The launched program is expected to complete without any errors.
|
||||
*/
|
||||
private static void testBlankSysPropValue() throws Exception {
|
||||
final List<Path> storedFiles = new ArrayList<>();
|
||||
final String sysPropVal = " \t";
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final Path tmpFile = Files.createTempFile("8231640", ".props");
|
||||
storedFiles.add(tmpFile);
|
||||
final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
|
||||
"-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal,
|
||||
StoreTest.class.getName(),
|
||||
tmpFile.toString(),
|
||||
i % 2 == 0 ? "--use-outputstream" : "--use-writer");
|
||||
executeJavaProcess(processBuilder);
|
||||
if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) {
|
||||
throw new RuntimeException("Unexpected properties stored in " + tmpFile);
|
||||
}
|
||||
String blankCommentLine = findNthComment(tmpFile, 2);
|
||||
if (blankCommentLine == null) {
|
||||
throw new RuntimeException("Comment line representing the value of "
|
||||
+ SYS_PROP_JAVA_PROPERTIES_DATE + " system property is missing in file " + tmpFile);
|
||||
}
|
||||
if (!blankCommentLine.isBlank()) {
|
||||
throw new RuntimeException("Expected comment line to be blank but was " + blankCommentLine);
|
||||
}
|
||||
}
|
||||
assertAllFileContentsAreSame(storedFiles, sysPropVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a Java program which is responsible for using Properties.store() to write out the
|
||||
* properties to a file. The launched Java program is passed a {@link String#isEmpty() empty} value
|
||||
* for the {@code java.properties.date} system property.
|
||||
* It is expected and verified in this test that such a value for the system property
|
||||
* will cause the current date and time to be written out as a comment.
|
||||
* The launched program is expected to complete without any errors.
|
||||
*/
|
||||
private static void testEmptySysPropValue() throws Exception {
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final Path tmpFile = Files.createTempFile("8231640", ".props");
|
||||
final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
|
||||
"-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + "",
|
||||
StoreTest.class.getName(),
|
||||
tmpFile.toString(),
|
||||
i % 2 == 0 ? "--use-outputstream" : "--use-writer");
|
||||
Date launchedAt = new Date();
|
||||
// wait for a second before launching so that we can then expect
|
||||
// the date written out by the store() APIs to be "after" this launch date
|
||||
Thread.sleep(1000);
|
||||
executeJavaProcess(processBuilder);
|
||||
if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) {
|
||||
throw new RuntimeException("Unexpected properties stored in " + tmpFile);
|
||||
}
|
||||
assertCurrentDate(tmpFile, launchedAt);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a Java program which is responsible for using Properties.store() to write out the
|
||||
* properties to a file. The launched Java program is passed the {@code java.properties.date}
|
||||
* system property with a value that doesn't represent a formatted date.
|
||||
* It is expected and verified in this test that such a value for the system property
|
||||
* will cause the comment to use that value verbatim. The launched program is expected to complete
|
||||
* without any errors.
|
||||
*/
|
||||
private static void testNonDateSysPropValue() throws Exception {
|
||||
final String sysPropVal = "foo-bar";
|
||||
final List<Path> storedFiles = new ArrayList<>();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final Path tmpFile = Files.createTempFile("8231640", ".props");
|
||||
storedFiles.add(tmpFile);
|
||||
final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
|
||||
"-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal,
|
||||
StoreTest.class.getName(),
|
||||
tmpFile.toString(),
|
||||
i % 2 == 0 ? "--use-outputstream" : "--use-writer");
|
||||
executeJavaProcess(processBuilder);
|
||||
if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) {
|
||||
throw new RuntimeException("Unexpected properties stored in " + tmpFile);
|
||||
}
|
||||
assertExpectedComment(tmpFile, sysPropVal);
|
||||
}
|
||||
assertAllFileContentsAreSame(storedFiles, sysPropVal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a Java program which is responsible for using Properties.store() to write out the
|
||||
* properties to a file. The launched Java program is passed the {@code java.properties.date}
|
||||
* system property with a value that has line terminator characters.
|
||||
* It is expected and verified in this test that such a value for the system property
|
||||
* will cause the comment written out to be multiple separate comments. The launched program is expected
|
||||
* to complete without any errors.
|
||||
*/
|
||||
private static void testMultiLineSysPropValue() throws Exception {
|
||||
final String[] sysPropVals = {"hello-world\nc=d", "hello-world\rc=d", "hello-world\r\nc=d"};
|
||||
for (final String sysPropVal : sysPropVals) {
|
||||
final List<Path> storedFiles = new ArrayList<>();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final Path tmpFile = Files.createTempFile("8231640", ".props");
|
||||
storedFiles.add(tmpFile);
|
||||
final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
|
||||
"-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal,
|
||||
StoreTest.class.getName(),
|
||||
tmpFile.toString(),
|
||||
i % 2 == 0 ? "--use-outputstream" : "--use-writer");
|
||||
executeJavaProcess(processBuilder);
|
||||
if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) {
|
||||
throw new RuntimeException("Unexpected properties stored in " + tmpFile);
|
||||
}
|
||||
// verify this results in 2 separate comment lines in the stored file
|
||||
String commentLine1 = findNthComment(tmpFile, 2);
|
||||
String commentLine2 = findNthComment(tmpFile, 3);
|
||||
if (commentLine1 == null || commentLine2 == null) {
|
||||
throw new RuntimeException("Did not find the expected multi-line comments in " + tmpFile);
|
||||
}
|
||||
if (!commentLine1.equals("hello-world")) {
|
||||
throw new RuntimeException("Unexpected comment line " + commentLine1 + " in " + tmpFile);
|
||||
}
|
||||
if (!commentLine2.equals("c=d")) {
|
||||
throw new RuntimeException("Unexpected comment line " + commentLine2 + " in " + tmpFile);
|
||||
}
|
||||
}
|
||||
assertAllFileContentsAreSame(storedFiles, sysPropVal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Launches a Java program which is responsible for using Properties.store() to write out the
|
||||
* properties to a file. The launched Java program is passed the {@code java.properties.date}
|
||||
* system property with a value that has backslash character.
|
||||
* It is expected and verified in this test that such a value for the system property
|
||||
* will not cause any malformed comments or introduce any new properties in the stored content.
|
||||
* The launched program is expected to complete without any errors.
|
||||
*/
|
||||
private static void testBackSlashInSysPropValue() throws Exception {
|
||||
final String[] sysPropVals = {"\\hello-world", "hello-world\\", "hello-world\\c=d",
|
||||
"newline-plus-backslash\\\nc=d"};
|
||||
for (final String sysPropVal : sysPropVals) {
|
||||
final List<Path> storedFiles = new ArrayList<>();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final Path tmpFile = Files.createTempFile("8231640", ".props");
|
||||
storedFiles.add(tmpFile);
|
||||
final ProcessBuilder processBuilder = ProcessTools.createJavaProcessBuilder(
|
||||
"-D" + SYS_PROP_JAVA_PROPERTIES_DATE + "=" + sysPropVal,
|
||||
StoreTest.class.getName(),
|
||||
tmpFile.toString(),
|
||||
i % 2 == 0 ? "--use-outputstream" : "--use-writer");
|
||||
executeJavaProcess(processBuilder);
|
||||
if (!StoreTest.propsToStore.equals(loadProperties(tmpFile))) {
|
||||
throw new RuntimeException("Unexpected properties stored in " + tmpFile);
|
||||
}
|
||||
String commentLine1 = findNthComment(tmpFile, 2);
|
||||
if (commentLine1 == null) {
|
||||
throw new RuntimeException("Did not find the expected comment line in " + tmpFile);
|
||||
}
|
||||
if (sysPropVal.contains("newline-plus-backslash")) {
|
||||
if (!commentLine1.equals("newline-plus-backslash\\")) {
|
||||
throw new RuntimeException("Unexpected comment line " + commentLine1 + " in " + tmpFile);
|
||||
}
|
||||
// we expect this specific system property value to be written out into 2 separate comment lines
|
||||
String commentLine2 = findNthComment(tmpFile, 3);
|
||||
if (commentLine2 == null) {
|
||||
throw new RuntimeException(sysPropVal + " was expected to be split into 2 comment line, " +
|
||||
"but wasn't, in " + tmpFile);
|
||||
}
|
||||
if (!commentLine2.equals("c=d")) {
|
||||
throw new RuntimeException("Unexpected comment line " + commentLine2 + " in " + tmpFile);
|
||||
}
|
||||
} else {
|
||||
if (!commentLine1.equals(sysPropVal)) {
|
||||
throw new RuntimeException("Unexpected comment line " + commentLine1 + " in " + tmpFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
assertAllFileContentsAreSame(storedFiles, sysPropVal);
|
||||
}
|
||||
}
|
||||
|
||||
// launches the java process and waits for it to exit. throws an exception if exit value is non-zero
|
||||
private static void executeJavaProcess(ProcessBuilder pb) throws Exception {
|
||||
final OutputAnalyzer outputAnalyzer = ProcessTools.executeProcess(pb);
|
||||
try {
|
||||
outputAnalyzer.shouldHaveExitValue(0);
|
||||
} finally {
|
||||
// print out any stdout/err that was generated in the launched program
|
||||
outputAnalyzer.reportDiagnosticSummary();
|
||||
}
|
||||
}
|
||||
|
||||
// Properties.load() from the passed file and return the loaded Properties instance
|
||||
private static Properties loadProperties(final Path file) throws IOException {
|
||||
final Properties props = new Properties();
|
||||
props.load(Files.newBufferedReader(file));
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the comment in the {@code destFile} is same as {@code expectedComment},
|
||||
* instead of the default date comment.
|
||||
*/
|
||||
private static void assertExpectedComment(final Path destFile,
|
||||
final String expectedComment) throws Exception {
|
||||
final String actualComment = findNthComment(destFile, 2);
|
||||
if (actualComment == null) {
|
||||
throw new RuntimeException("Comment \"" + expectedComment + "\" not found in stored properties " + destFile);
|
||||
}
|
||||
if (!expectedComment.equals(actualComment)) {
|
||||
throw new RuntimeException("Expected comment \"" + expectedComment + "\" but found \"" + actualComment + "\" " +
|
||||
"in stored properties " + destFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the date comment in the {@code destFile} can be parsed using the
|
||||
* "EEE MMM dd HH:mm:ss zzz uuuu" format and the time represented by it is {@link Date#after(Date) after}
|
||||
* the passed {@code date}
|
||||
*/
|
||||
private static void assertCurrentDate(final Path destFile, final Date date) throws Exception {
|
||||
final String dateComment = findNthComment(destFile, 2);
|
||||
if (dateComment == null) {
|
||||
throw new RuntimeException("Date comment not found in stored properties " + destFile);
|
||||
}
|
||||
System.out.println("Found date comment " + dateComment + " in file " + destFile);
|
||||
final Date parsedDate;
|
||||
try {
|
||||
Instant instant = Instant.from(DateTimeFormatter.ofPattern(DATE_FORMAT_PATTERN).parse(dateComment));
|
||||
parsedDate = new Date(instant.toEpochMilli());
|
||||
} catch (DateTimeParseException pe) {
|
||||
throw new RuntimeException("Unexpected date " + dateComment + " in stored properties " + destFile);
|
||||
}
|
||||
if (!parsedDate.after(date)) {
|
||||
throw new RuntimeException("Expected date comment " + dateComment + " to be after " + date
|
||||
+ " but was " + parsedDate);
|
||||
}
|
||||
}
|
||||
|
||||
// returns the "Nth" comment from the file. Comment index starts from 1.
|
||||
private static String findNthComment(Path file, int commentIndex) throws IOException {
|
||||
List<String> comments = new ArrayList<>();
|
||||
try (final BufferedReader reader = Files.newBufferedReader(file)) {
|
||||
String line = null;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.startsWith("#")) {
|
||||
comments.add(line.substring(1));
|
||||
if (comments.size() == commentIndex) {
|
||||
return comments.get(commentIndex - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// verifies the byte equality of the contents in each of the files
|
||||
private static void assertAllFileContentsAreSame(final List<Path> files,
|
||||
final String sysPropVal) throws Exception {
|
||||
final byte[] file1Contents = Files.readAllBytes(files.get(0));
|
||||
for (int i = 1; i < files.size(); i++) {
|
||||
final byte[] otherFileContents = Files.readAllBytes(files.get(i));
|
||||
if (!Arrays.equals(file1Contents, otherFileContents)) {
|
||||
throw new RuntimeException("Properties.store() did not generate reproducible content when " +
|
||||
SYS_PROP_JAVA_PROPERTIES_DATE + " was set to " + sysPropVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class StoreTest {
|
||||
private static final Properties propsToStore = new Properties();
|
||||
|
||||
static {
|
||||
propsToStore.setProperty("a", "b");
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses Properties.store() APIs to store the properties into file
|
||||
*/
|
||||
public static void main(final String[] args) throws Exception {
|
||||
final Path destFile = Path.of(args[0]);
|
||||
final String comment = "some user specified comment";
|
||||
System.out.println("Current default timezone is " + TimeZone.getDefault());
|
||||
if (args[1].equals("--use-outputstream")) {
|
||||
try (var os = Files.newOutputStream(destFile)) {
|
||||
propsToStore.store(os, comment);
|
||||
}
|
||||
} else {
|
||||
try (var br = Files.newBufferedWriter(destFile)) {
|
||||
propsToStore.store(br, comment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user