mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-24 18:29:46 +01:00
Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
67d6fd157a | ||
|
|
56d463d29a | ||
|
|
aa625213b5 | ||
|
|
1538f1e6ad | ||
|
|
47017e1e14 | ||
|
|
decffd42a5 | ||
|
|
f189c552a6 | ||
|
|
c20bd5a658 | ||
|
|
e900d17295 | ||
|
|
35f18de090 | ||
|
|
47d473b1a1 | ||
|
|
70dde74a8f | ||
|
|
5745455f66 | ||
|
|
a9ce9c763b | ||
|
|
c5507f0d9a | ||
|
|
8670e275a1 | ||
|
|
2fc34e9f04 | ||
|
|
fae9ac43a5 | ||
|
|
68db465ae1 | ||
|
|
0aa9b4f7de | ||
|
|
d40250ddf5 | ||
|
|
63b1c11712 | ||
|
|
1eab1527d5 | ||
|
|
9b5ebaaa5a | ||
|
|
a37db66560 | ||
|
|
39dd2f608c | ||
|
|
890efa0ea8 | ||
|
|
7efb0075bc | ||
|
|
413ff95d63 | ||
|
|
bfa7a36237 | ||
|
|
138596467d | ||
|
|
f7a0716ccd | ||
|
|
bdb9d3f12f | ||
|
|
1e8d2c0873 | ||
|
|
360f8f332c | ||
|
|
13512decff | ||
|
|
28ebc0c2e0 | ||
|
|
9a35ca0b25 | ||
|
|
e424a5bf19 | ||
|
|
ca4d838caf | ||
|
|
6ed5106466 | ||
|
|
098a50d91a | ||
|
|
050990303b | ||
|
|
9f9416a12e | ||
|
|
b6cb489fee | ||
|
|
446535b706 | ||
|
|
c18934bb98 | ||
|
|
e8a6e8bd6e | ||
|
|
4a7241931f | ||
|
|
b45b8c9913 | ||
|
|
f6cf71ce68 | ||
|
|
803039d6db | ||
|
|
436223316f | ||
|
|
9a0ab296fe | ||
|
|
bf4a191246 | ||
|
|
cdfff8f6ac | ||
|
|
6d6de1034a | ||
|
|
2333999906 | ||
|
|
6ffcd2bf91 | ||
|
|
822b4a8c49 | ||
|
|
debc6336c0 | ||
|
|
1f93154f62 | ||
|
|
9f069ca59e | ||
|
|
53f1a647fd |
@@ -31,7 +31,7 @@ architecture=$3 # aarch64 or x64
|
||||
bundle_type=$(do_maketest)
|
||||
do_maketest=$?
|
||||
tag_prefix="jbr-"
|
||||
OPENJDK_TAG=$(git log --simplify-by-decoration --decorate=short --pretty=short | grep "$tag_prefix" | cut -d "(" -f2 | cut -d ")" -f1 | awk '{print $2}' | sort -t "-" -k 2 -g | tail -n 1)
|
||||
OPENJDK_TAG=$(git log --simplify-by-decoration --decorate=short --pretty=short | grep "$tag_prefix" | cut -d "(" -f2 | cut -d ")" -f1 | awk '{print $2}' | sort -t "-" -k 2 -g | tail -n 1 | tr -d ",")
|
||||
VERSION_FEATURE=$(getVersionProp "DEFAULT_VERSION_FEATURE")
|
||||
VERSION_INTERIM=$(getVersionProp "DEFAULT_VERSION_INTERIM")
|
||||
VERSION_UPDATE=$(getVersionProp "DEFAULT_VERSION_UPDATE")
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
while getopts ":t" o; do
|
||||
case "${o}" in
|
||||
t)
|
||||
t="With Teamcity tests info"
|
||||
TC_PRINT=1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND-1))
|
||||
|
||||
NEWFILEPATH=$1
|
||||
CONFIGID=$2
|
||||
BUILDID=$3
|
||||
@@ -7,6 +18,7 @@ TOKEN=$4
|
||||
#
|
||||
# Get the size of new artifact
|
||||
#
|
||||
|
||||
unameOut="$(uname -s)"
|
||||
case "${unameOut}" in
|
||||
Linux*)
|
||||
@@ -16,7 +28,11 @@ case "${unameOut}" in
|
||||
NEWFILESIZE=$(stat -f%z "$NEWFILEPATH")
|
||||
;;
|
||||
CYGWIN*)
|
||||
NEWFILESIZE=$(stat -c%s "$NEWFILEPATH")
|
||||
NEWFILESIZE=$(stat -c%s$4
|
||||
#
|
||||
# Get the size of new artifact
|
||||
#
|
||||
"$NEWFILEPATH")
|
||||
;;
|
||||
MINGW*)
|
||||
NEWFILESIZE=$(stat -c%s "$NEWFILEPATH")
|
||||
@@ -25,32 +41,88 @@ case "${unameOut}" in
|
||||
echo "Unknown machine: ${unameOut}"
|
||||
exit 1
|
||||
esac
|
||||
FILENAME=$(basename ${NEWFILEPATH})
|
||||
|
||||
echo "New size of $NEWFILEPATH = $NEWFILESIZE bytes."
|
||||
#
|
||||
# Get pattern of artifact name
|
||||
# Base filename pattern: <BUNDLE_TYPE>-<JDK_VERSION>-<OS>-<ARCH>-b<BUILD>.tar.gz: jbr_dcevm-17.0.2-osx-x64-b1234.tar.gz
|
||||
# BUNDLE_TYPE: jbr, jbrsdk, jbr_dcevm, jbrsdk_jcef etc.
|
||||
# OS_ARCH_PATTERN - <os_architecture>: osx-x64, linux-aarch64, windows-x64 etc.
|
||||
|
||||
# example: IntellijCustomJdk_Jdk17_Master_LinuxX64jcef
|
||||
BUNDLE_TYPE=jbrsdk
|
||||
OS_ARCH_PATTERN=""
|
||||
FILE_EXTENSION=tar.gz
|
||||
|
||||
re='(jbr[a-z_]*).*-[0-9_\.]+-(.+)-b[0-9]+(.+)'
|
||||
if [[ $FILENAME =~ $re ]]; then
|
||||
BUNDLE_TYPE=${BASH_REMATCH[1]}
|
||||
OS_ARCH_PATTERN=${BASH_REMATCH[2]}
|
||||
FILE_EXTENSION=${BASH_REMATCH[3]}
|
||||
fi
|
||||
|
||||
if [ $TC_PRINT -eq 1 ]; then
|
||||
testname_file_ext=`echo $FILE_EXTENSION | sed 's/\./_/g'`
|
||||
testname=$BUNDLE_TYPE"_"$OS_ARCH_PATTERN$testname_file_ext
|
||||
echo \#\#teamcity[testStarted name=\'$testname\']
|
||||
fi
|
||||
|
||||
|
||||
echo "BUNDLE_TYPE: " $BUNDLE_TYPE
|
||||
echo "OS_ARCH_PATTERN: " $OS_ARCH_PATTERN
|
||||
echo "FILE_EXTENSION: " $FILE_EXTENSION
|
||||
echo "New size of $FILENAME = $NEWFILESIZE bytes."
|
||||
|
||||
|
||||
function test_failed_msg() {
|
||||
if [ $3 -eq 1 ]; then
|
||||
echo \#\#teamcity[testFailed name=\'$1\' message=\'$2\']
|
||||
fi
|
||||
}
|
||||
|
||||
function test_finished_msg() {
|
||||
if [ $2 -eq 1 ]; then
|
||||
echo \#\#teamcity[testFinished name=\'$1\']
|
||||
fi
|
||||
}
|
||||
|
||||
#
|
||||
# Get previous successful build ID
|
||||
# Example:
|
||||
# CONFIGID=IntellijCustomJdk_Jdk17_Master_LinuxX64jcef
|
||||
# BUILDID=12345678
|
||||
#
|
||||
# expected return value
|
||||
# id="123".number="567"
|
||||
#
|
||||
CURL_RESPONSE=$(curl --header "Authorization: Bearer $TOKEN" "https://buildserver.labs.intellij.net/app/rest/builds/?locator=buildType:(id:$CONFIGID),status:success,count:1,finishDate:(build:$BUILDID,condition:before)")
|
||||
re='id=\"([0-9]+)\".+number=\"([0-9\.]+)\"'
|
||||
|
||||
re='id=\"([0-9]+)\".+number=\"([0-9]+)\"'
|
||||
# ID: Previous successful build id
|
||||
ID=0
|
||||
|
||||
if [[ $CURL_RESPONSE =~ $re ]]; then
|
||||
ID=${BASH_REMATCH[1]}
|
||||
echo "BUILD Number: ${BASH_REMATCH[2]}"
|
||||
else
|
||||
echo "ERROR: can't find previous build"
|
||||
msg="ERROR: can't find previous build"
|
||||
echo $msg
|
||||
echo $CURL_RESPONSE
|
||||
test_failed_msg $testname $msg $TC_PRINT
|
||||
test_finished_msg $testname $TC_PRINT
|
||||
exit 1
|
||||
fi
|
||||
|
||||
#
|
||||
# Get artifacts from previous successful build
|
||||
#
|
||||
# expected return value
|
||||
# name="jbrsdk_jcef*.tar.gz size="123'
|
||||
#
|
||||
CURL_RESPONSE=$(curl --header "Authorization: Bearer $TOKEN" "https://buildserver.labs.intellij.net/app/rest/builds/$ID?fields=id,number,artifacts(file(name,size))")
|
||||
|
||||
echo "Atrifacts of last pinned build of $CONFIGID :\n"
|
||||
echo "Atrifacts of previous build of $CONFIGID :"
|
||||
echo $CURL_RESPONSE
|
||||
|
||||
# Find size (in response) with reg exp
|
||||
re='name=\"(jbrsdk_jcef[^\"]+\.tar\.gz)\" size=\"([0-9]+)\"'
|
||||
# Find binary size (in response) with reg exp
|
||||
re='name=\"('$BUNDLE_TYPE'[^\"]+'${OS_ARCH_PATTERN}'[^\"]+'${FILE_EXTENSION}')\" size=\"([0-9]+)\"'
|
||||
|
||||
if [[ $CURL_RESPONSE =~ $re ]]; then
|
||||
OLDFILENAME=${BASH_REMATCH[1]}
|
||||
@@ -61,12 +133,20 @@ if [[ $CURL_RESPONSE =~ $re ]]; then
|
||||
let allowedSize=OLDFILESIZE+OLDFILESIZE/20 # use 5% threshold
|
||||
echo "Allowed size = $allowedSize"
|
||||
if [[ "$NEWFILESIZE" -gt "$allowedSize" ]]; then
|
||||
echo "ERROR: new size is significally greater than prev size (need to investigate)"
|
||||
msg="ERROR: new size is significally greater than prev size (need to investigate)"
|
||||
echo $msg
|
||||
test_failed_msg $testname $msg $TC_PRINT
|
||||
test_finished_msg $testname $TC_PRINT
|
||||
exit 1
|
||||
else
|
||||
echo "PASSED"
|
||||
test_finished_msg $testname $TC_PRINT
|
||||
fi
|
||||
else
|
||||
echo "ERROR: can't find string with size in xml response:"
|
||||
msg="ERROR: can't find string with size in xml response:"
|
||||
echo $msg
|
||||
echo $CURL_RESPONSE
|
||||
test_failed_msg $testname $msg $TC_PRINT
|
||||
test_finished_msg $testname $TC_PRINT
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -95,8 +95,24 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS],
|
||||
# info flags for toolchains unless we know they work.
|
||||
# See JDK-8207057.
|
||||
ASFLAGS_DEBUG_SYMBOLS=""
|
||||
|
||||
# Debug prefix mapping if supported by compiler
|
||||
DEBUG_PREFIX_CFLAGS=
|
||||
|
||||
# Debug symbols
|
||||
if test "x$TOOLCHAIN_TYPE" = xgcc; then
|
||||
if test "x$ALLOW_ABSOLUTE_PATHS_IN_OUTPUT" = "xfalse"; then
|
||||
# Check if compiler supports -fdebug-prefix-map. If so, use that to make
|
||||
# the debug symbol paths resolve to paths relative to the workspace root.
|
||||
workspace_root_trailing_slash="${WORKSPACE_ROOT%/}/"
|
||||
DEBUG_PREFIX_CFLAGS="-fdebug-prefix-map=${workspace_root_trailing_slash}="
|
||||
FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${DEBUG_PREFIX_CFLAGS}],
|
||||
IF_FALSE: [
|
||||
DEBUG_PREFIX_CFLAGS=
|
||||
]
|
||||
)
|
||||
fi
|
||||
|
||||
CFLAGS_DEBUG_SYMBOLS="-g"
|
||||
ASFLAGS_DEBUG_SYMBOLS="-g"
|
||||
elif test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
@@ -108,6 +124,11 @@ AC_DEFUN([FLAGS_SETUP_DEBUG_SYMBOLS],
|
||||
CFLAGS_DEBUG_SYMBOLS="-Z7"
|
||||
fi
|
||||
|
||||
if test "x$DEBUG_PREFIX_CFLAGS" != x; then
|
||||
CFLAGS_DEBUG_SYMBOLS="$CFLAGS_DEBUG_SYMBOLS $DEBUG_PREFIX_CFLAGS"
|
||||
ASFLAGS_DEBUG_SYMBOLS="$ASFLAGS_DEBUG_SYMBOLS $DEBUG_PREFIX_CFLAGS"
|
||||
fi
|
||||
|
||||
AC_SUBST(CFLAGS_DEBUG_SYMBOLS)
|
||||
AC_SUBST(ASFLAGS_DEBUG_SYMBOLS)
|
||||
])
|
||||
@@ -778,8 +799,6 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
|
||||
FILE_MACRO_CFLAGS=
|
||||
]
|
||||
)
|
||||
# -fdebug-prefix-map is supported by all modern versions of gcc/clang
|
||||
DEBUG_PREFIX_CFLAGS=" -fdebug-prefix-map=${workspace_root_trailing_slash}="
|
||||
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft &&
|
||||
test "x$ENABLE_REPRODUCIBLE_BUILD" = xtrue; then
|
||||
# There is a known issue with the pathmap if the mapping is made to the
|
||||
@@ -810,12 +829,12 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_CPU_DEP],
|
||||
$TOOLCHAIN_CFLAGS_JVM ${$1_TOOLCHAIN_CFLAGS_JVM} \
|
||||
$OS_CFLAGS $OS_CFLAGS_JVM $CFLAGS_OS_DEF_JVM $DEBUG_CFLAGS_JVM \
|
||||
$WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG $FILE_MACRO_CFLAGS \
|
||||
$REPRODUCIBLE_CFLAGS $DEBUG_PREFIX_CFLAGS"
|
||||
$REPRODUCIBLE_CFLAGS"
|
||||
|
||||
CFLAGS_JDK_COMMON="$ALWAYS_CFLAGS_JDK $ALWAYS_DEFINES_JDK $TOOLCHAIN_CFLAGS_JDK \
|
||||
$OS_CFLAGS $CFLAGS_OS_DEF_JDK $DEBUG_CFLAGS_JDK $DEBUG_OPTIONS_FLAGS_JDK \
|
||||
$WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK \
|
||||
$FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS $DEBUG_PREFIX_CFLAGS"
|
||||
$FILE_MACRO_CFLAGS $REPRODUCIBLE_CFLAGS"
|
||||
|
||||
# Use ${$2EXTRA_CFLAGS} to block EXTRA_CFLAGS to be added to build flags.
|
||||
# (Currently we don't have any OPENJDK_BUILD_EXTRA_CFLAGS, but that might
|
||||
|
||||
@@ -82,14 +82,6 @@ AC_DEFUN([FLAGS_SETUP_ASFLAGS],
|
||||
elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
|
||||
BASIC_ASFLAGS="-nologo -c"
|
||||
fi
|
||||
|
||||
if test "x$ALLOW_ABSOLUTE_PATHS_IN_OUTPUT" = "xfalse"; then
|
||||
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
|
||||
workspace_root_trailing_slash="${WORKSPACE_ROOT%/}/"
|
||||
BASIC_ASFLAGS+=" -fdebug-prefix-map=${workspace_root_trailing_slash}="
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_SUBST(BASIC_ASFLAGS)
|
||||
|
||||
if test "x$OPENJDK_TARGET_OS" = xmacosx; then
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2022, 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
|
||||
@@ -230,8 +230,6 @@ AC_DEFUN([UTIL_GET_MATCHING_VALUES],
|
||||
# Converts an ISO-8601 date/time string to a unix epoch timestamp. If no
|
||||
# suitable conversion method was found, an empty string is returned.
|
||||
#
|
||||
# Sets the specified variable to the resulting list.
|
||||
#
|
||||
# $1: result variable name
|
||||
# $2: input date/time string
|
||||
AC_DEFUN([UTIL_GET_EPOCH_TIMESTAMP],
|
||||
@@ -241,11 +239,16 @@ AC_DEFUN([UTIL_GET_EPOCH_TIMESTAMP],
|
||||
timestamp=$($DATE --utc --date=$2 +"%s" 2> /dev/null)
|
||||
else
|
||||
# BSD date
|
||||
timestamp=$($DATE -u -j -f "%F %T" "$2" "+%s" 2> /dev/null)
|
||||
# ISO-8601 date&time in Zulu 'date'T'time'Z
|
||||
timestamp=$($DATE -u -j -f "%FT%TZ" "$2" "+%s" 2> /dev/null)
|
||||
if test "x$timestamp" = x; then
|
||||
# Perhaps the time was missing
|
||||
timestamp=$($DATE -u -j -f "%F %T" "$2 00:00:00" "+%s" 2> /dev/null)
|
||||
# If this did not work, we give up and return the empty string
|
||||
# BSD date cannot handle trailing milliseconds.
|
||||
# Try again ignoring characters at end
|
||||
timestamp=$($DATE -u -j -f "%Y-%m-%dT%H:%M:%S" "$2" "+%s" 2> /dev/null)
|
||||
fi
|
||||
if test "x$timestamp" = x; then
|
||||
# Perhaps the time was missing.
|
||||
timestamp=$($DATE -u -j -f "%FT%TZ" "$2""T00:00:00Z" "+%s" 2> /dev/null)
|
||||
fi
|
||||
fi
|
||||
$1=$timestamp
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2019, 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.
|
||||
#
|
||||
|
||||
# Default version, product, and vendor information to use,
|
||||
# unless overridden by configure
|
||||
|
||||
DEFAULT_VERSION_FEATURE=15
|
||||
DEFAULT_VERSION_INTERIM=0
|
||||
DEFAULT_VERSION_UPDATE=0
|
||||
DEFAULT_VERSION_PATCH=0
|
||||
DEFAULT_VERSION_EXTRA1=0
|
||||
DEFAULT_VERSION_EXTRA2=0
|
||||
DEFAULT_VERSION_EXTRA3=0
|
||||
DEFAULT_VERSION_DATE=2020-09-15
|
||||
DEFAULT_VERSION_CLASSFILE_MAJOR=59 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
|
||||
DEFAULT_VERSION_CLASSFILE_MINOR=0
|
||||
DEFAULT_ACCEPTABLE_BOOT_VERSIONS="14 15"
|
||||
DEFAULT_JDK_SOURCE_TARGET_VERSION=15
|
||||
DEFAULT_PROMOTED_VERSION_PRE=
|
||||
|
||||
LAUNCHER_NAME=openjdk
|
||||
PRODUCT_NAME=OpenJDK
|
||||
PRODUCT_SUFFIX="Runtime Environment"
|
||||
JDK_RC_PLATFORM_NAME=Platform
|
||||
COMPANY_NAME=N/A
|
||||
HOTSPOT_VM_DISTRO="Dynamic Code Evolution"
|
||||
VENDOR_URL=https://openjdk.java.net/
|
||||
VENDOR_URL_BUG=https://bugreport.java.com/bugreport/
|
||||
VENDOR_URL_VM_BUG=https://bugreport.java.com/bugreport/crash.jsp
|
||||
|
||||
# Might need better names for these
|
||||
MACOSX_BUNDLE_NAME_BASE="OpenJDK"
|
||||
MACOSX_BUNDLE_ID_BASE="net.java.openjdk"
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2022, 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
|
||||
@@ -193,7 +193,8 @@ define SetupJarArchiveBody
|
||||
$1_UPDATE_CONTENTS=\
|
||||
if [ "`$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'`" -gt "0" ]; then \
|
||||
$(ECHO) " updating" `$(WC) -l $$($1_BIN)/_the.$$($1_JARNAME)_contents | $(AWK) '{ print $$$$1 }'` files && \
|
||||
$$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents; \
|
||||
$(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \
|
||||
$$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted; \
|
||||
fi $$(NEWLINE)
|
||||
# The s-variants of the above macros are used when the jar is created from scratch.
|
||||
# NOTICE: please leave the parentheses space separated otherwise the AIX build will break!
|
||||
@@ -212,7 +213,9 @@ define SetupJarArchiveBody
|
||||
| $(SED) 's|$$(src)/|-C $$(src) |g' >> \
|
||||
$$($1_BIN)/_the.$$($1_JARNAME)_contents) $$(NEWLINE) )
|
||||
endif
|
||||
$1_SUPDATE_CONTENTS=$$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents $$(NEWLINE)
|
||||
$1_SUPDATE_CONTENTS=\
|
||||
$(SORT) $$($1_BIN)/_the.$$($1_JARNAME)_contents > $$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted && \
|
||||
$$($1_JAR_CMD) --update $$($1_JAR_OPTIONS) --file $$@ @$$($1_BIN)/_the.$$($1_JARNAME)_contents_sorted $$(NEWLINE)
|
||||
|
||||
# Use a slightly shorter name for logging, but with enough path to identify this jar.
|
||||
$1_NAME:=$$(subst $$(OUTPUTDIR)/,,$$($1_JAR))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2011, 2022, 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
|
||||
@@ -358,6 +358,20 @@ define SetupCompileNativeFileBody
|
||||
# Compile as preprocessed assembler file
|
||||
$1_FLAGS := $(BASIC_ASFLAGS) $$($1_BASE_ASFLAGS)
|
||||
$1_COMPILER := $(AS)
|
||||
|
||||
# gcc assembly files must contain an appropriate relative .file
|
||||
# path for reproducible builds.
|
||||
ifeq ($(TOOLCHAIN_TYPE), gcc)
|
||||
# If no absolute paths allowed, work out relative source file path
|
||||
# for assembly .file substitution, otherwise use full file path
|
||||
ifeq ($(ALLOW_ABSOLUTE_PATHS_IN_OUTPUT), false)
|
||||
$1_REL_ASM_SRC := $$(call RelativePath, $$($1_FILE), $(WORKSPACE_ROOT))
|
||||
else
|
||||
$1_REL_ASM_SRC := $$($1_FILE)
|
||||
endif
|
||||
$1_FLAGS := $$($1_FLAGS) -DASSEMBLY_SRC_FILE='"$$($1_REL_ASM_SRC)"' \
|
||||
-include $(TOPDIR)/make/data/autoheaders/assemblyprefix.h
|
||||
endif
|
||||
else ifneq ($$(filter %.cpp %.cc %.mm, $$($1_FILENAME)), )
|
||||
# Compile as a C++ or Objective-C++ file
|
||||
$1_FLAGS := $(CFLAGS_CCACHE) $$($1_USE_PCH_FLAGS) $$($1_BASE_CXXFLAGS) \
|
||||
@@ -389,6 +403,12 @@ define SetupCompileNativeFileBody
|
||||
$1_OBJ_DEPS := $$($1_SRC_FILE) $$($$($1_BASE)_COMPILE_VARDEPS_FILE) \
|
||||
$$($$($1_BASE)_EXTRA_DEPS) $$($1_VARDEPS_FILE)
|
||||
$1_COMPILE_OPTIONS := $$($1_FLAGS) $(CC_OUT_OPTION)$$($1_OBJ) $$($1_SRC_FILE)
|
||||
# For reproducible builds with gcc ensure random symbol generation is seeded deterministically
|
||||
ifeq ($(TOOLCHAIN_TYPE), gcc)
|
||||
ifeq ($$(ENABLE_REPRODUCIBLE_BUILD), true)
|
||||
$1_COMPILE_OPTIONS += -frandom-seed="$$($1_FILENAME)"
|
||||
endif
|
||||
endif
|
||||
|
||||
$$($1_OBJ_JSON): $$($1_OBJ_DEPS)
|
||||
$$(call WriteCompileCommandsFragment, $$@, $$(PWD), $$($1_SRC_FILE), \
|
||||
|
||||
29
make/data/autoheaders/assemblyprefix.h
Normal file
29
make/data/autoheaders/assemblyprefix.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#
|
||||
# Copyright (c) 2022, 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.
|
||||
#
|
||||
|
||||
// ASSEMBLY_SRC_FILE gets replaced by relative or absolute file path
|
||||
// in NativeCompilation.gmk for gcc tooling on Linux. This ensures a
|
||||
// reproducible object file through a predictable value of the STT_FILE
|
||||
// symbol, and subsequently a reproducible .debuginfo.
|
||||
.file ASSEMBLY_SRC_FILE
|
||||
|
||||
@@ -58,6 +58,9 @@ ifeq ($(call check-jvm-feature, compiler2), true)
|
||||
|
||||
ADLC_CFLAGS += -I$(TOPDIR)/src/hotspot/share
|
||||
|
||||
# Add file macro mappings
|
||||
ADLC_CFLAGS += $(FILE_MACRO_CFLAGS)
|
||||
|
||||
$(eval $(call SetupNativeCompilation, BUILD_ADLC, \
|
||||
NAME := adlc, \
|
||||
TYPE := EXECUTABLE, \
|
||||
|
||||
@@ -84,7 +84,7 @@ ifneq ($(call check-jvm-feature, jvmti), true)
|
||||
jvmtiImpl.cpp jvmtiManageCapabilities.cpp jvmtiRawMonitor.cpp jvmtiUtil.cpp jvmtiTrace.cpp \
|
||||
jvmtiCodeBlobEvents.cpp jvmtiEnv.cpp jvmtiRedefineClasses.cpp jvmtiEnvBase.cpp jvmtiEnvThreadState.cpp \
|
||||
jvmtiTagMap.cpp jvmtiEventController.cpp evmCompat.cpp jvmtiEnter.xsl jvmtiExport.cpp \
|
||||
jvmtiClassFileReconstituter.cpp jvmtiTagMapTable.cpp
|
||||
jvmtiClassFileReconstituter.cpp jvmtiTagMapTable.cpp jvmtiEnhancedRedefineClasses.cpp
|
||||
endif
|
||||
|
||||
ifneq ($(call check-jvm-feature, jvmci), true)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2022, 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
|
||||
@@ -204,6 +204,10 @@ public class MakeZipReproducible {
|
||||
entry.setTimeLocal(timestamp);
|
||||
}
|
||||
|
||||
// Ensure "extra" field is not set from original ZipEntry info that may be not deterministic
|
||||
// eg.may contain specific UID/GID
|
||||
entry.setExtra(null);
|
||||
|
||||
zos.putNextEntry(entry);
|
||||
if (entry.getSize() > 0 && entryInputStream != null) {
|
||||
entryInputStream.transferTo(zos);
|
||||
|
||||
@@ -84,7 +84,7 @@ TARGETS += $(COPY_LEGAL)
|
||||
################################################################################
|
||||
|
||||
FONTFILE_SRC_DIR := $(TOPDIR)/src/java.desktop/share
|
||||
FONTFILE_SRCS := $(wildcard $(FONTFILE_SRC_DIR)/fonts/*.ttf) $(FONTFILE_SRC_DIR)/fonts/fonts.dir $(FONTFILE_SRC_DIR)/fonts/font.conf
|
||||
FONTFILE_SRCS := $(wildcard $(FONTFILE_SRC_DIR)/fonts/*.ttf) $(wildcard $(FONTFILE_SRC_DIR)/fonts/*.otf) $(FONTFILE_SRC_DIR)/fonts/fonts.dir $(FONTFILE_SRC_DIR)/fonts/font.conf
|
||||
FONTFILE_TARGET_FILES := $(subst $(FONTFILE_SRC_DIR),$(LIB_DST_DIR),$(FONTFILE_SRCS))
|
||||
|
||||
$(LIB_DST_DIR)/fonts/%: $(FONTFILE_SRC_DIR)/fonts/%
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
#define ELF_TYPE(name, description) .type name,description
|
||||
#endif
|
||||
|
||||
.file "bsd_x86_32.S"
|
||||
.globl SYMBOL(fixcw)
|
||||
|
||||
# NOTE WELL! The _Copy functions are called directly
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#define ELF_TYPE(name, description) .type name,description
|
||||
#endif
|
||||
|
||||
.file "bsd_x86_64.S"
|
||||
# NOTE WELL! The _Copy functions are called directly
|
||||
# from server-compiler-generated code via CallLeafNoFP,
|
||||
# which means that they *must* either not use floating
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
// or visit www.oracle.com if you need additional information or have any
|
||||
// questions.
|
||||
|
||||
.file "atomic_linux_aarch64.S"
|
||||
|
||||
.text
|
||||
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
.file "copy_linux_aarch64.S"
|
||||
|
||||
.global _Copy_conjoint_words
|
||||
.global _Copy_disjoint_words
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
// or visit www.oracle.com if you need additional information or have any
|
||||
// questions.
|
||||
|
||||
.file "threadLS_linux_aarch64.S"
|
||||
|
||||
// JavaThread::aarch64_get_thread_helper()
|
||||
//
|
||||
// Return the current thread pointer in x0.
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
.file "linux_arm_32.S"
|
||||
|
||||
# NOTE WELL! The _Copy functions are called directly
|
||||
# from server-compiler-generated code via CallLeafNoFP,
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#
|
||||
|
||||
|
||||
.file "linux_x86_32.S"
|
||||
|
||||
# NOTE WELL! The _Copy functions are called directly
|
||||
# from server-compiler-generated code via CallLeafNoFP,
|
||||
# which means that they *must* either not use floating
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
# questions.
|
||||
#
|
||||
|
||||
.file "linux_x86_64.S"
|
||||
|
||||
# NOTE WELL! The _Copy functions are called directly
|
||||
# from server-compiler-generated code via CallLeafNoFP,
|
||||
# which means that they *must* either not use floating
|
||||
|
||||
@@ -335,16 +335,6 @@ void ClassLoaderData::classes_do(KlassClosure* klass_closure) {
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderData::initialized_classes_do(KlassClosure* klass_closure) {
|
||||
// Lock-free access requires load_acquire
|
||||
for (Klass* k = Atomic::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
if (k->is_instance_klass() && InstanceKlass::cast(k)->is_initialized()) {
|
||||
klass_closure->do_klass(k);
|
||||
}
|
||||
assert(k != k->next_link(), "no loops!");
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderData::classes_do(void f(Klass * const)) {
|
||||
// Lock-free access requires load_acquire
|
||||
for (Klass* k = Atomic::load_acquire(&_klasses); k != NULL; k = k->next_link()) {
|
||||
|
||||
@@ -272,7 +272,6 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
void oops_do(OopClosure* f, int claim_value, bool clear_modified_oops = false);
|
||||
|
||||
void classes_do(KlassClosure* klass_closure);
|
||||
void initialized_classes_do(KlassClosure* klass_closure);
|
||||
Klass* klasses() { return _klasses; }
|
||||
|
||||
JNIMethodBlock* jmethod_ids() const { return _jmethod_ids; }
|
||||
|
||||
@@ -361,13 +361,6 @@ void ClassLoaderDataGraph::classes_do(KlassClosure* klass_closure) {
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::initialized_classes_do(KlassClosure* klass_closure) {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
cld->initialized_classes_do(klass_closure);
|
||||
}
|
||||
}
|
||||
|
||||
void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
|
||||
ClassLoaderDataGraphIterator iter;
|
||||
while (ClassLoaderData* cld = iter.get_next()) {
|
||||
|
||||
@@ -79,9 +79,6 @@ class ClassLoaderDataGraph : public AllStatic {
|
||||
// Walking the ClassLoaderDataGraph also includes hidden classes.
|
||||
static void classes_do(KlassClosure* klass_closure);
|
||||
|
||||
// Enhanced class redefinition
|
||||
static void initialized_classes_do(KlassClosure* klass_closure);
|
||||
|
||||
static void classes_do(void f(Klass* const));
|
||||
static void methods_do(void f(Method*));
|
||||
static void modules_do(void f(ModuleEntry*));
|
||||
|
||||
@@ -68,6 +68,7 @@ static bool enable() {
|
||||
}
|
||||
_enabled = FlightRecorder;
|
||||
assert(_enabled, "invariant");
|
||||
AllowEnhancedClassRedefinition = false;
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
|
||||
@@ -3714,11 +3714,11 @@ bool PhaseIdealLoop::only_has_infinite_loops() {
|
||||
//----------------------------build_and_optimize-------------------------------
|
||||
// Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to
|
||||
// its corresponding LoopNode. If 'optimize' is true, do some loop cleanups.
|
||||
void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
||||
void PhaseIdealLoop::build_and_optimize() {
|
||||
assert(!C->post_loop_opts_phase(), "no loop opts allowed");
|
||||
|
||||
bool do_split_ifs = (mode == LoopOptsDefault);
|
||||
bool skip_loop_opts = (mode == LoopOptsNone);
|
||||
bool do_split_ifs = (_mode == LoopOptsDefault);
|
||||
bool skip_loop_opts = (_mode == LoopOptsNone);
|
||||
|
||||
int old_progress = C->major_progress();
|
||||
uint orig_worklist_size = _igvn._worklist.size();
|
||||
@@ -3789,9 +3789,9 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
||||
BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2();
|
||||
// Nothing to do, so get out
|
||||
bool stop_early = !C->has_loops() && !skip_loop_opts && !do_split_ifs && !_verify_me && !_verify_only &&
|
||||
!bs->is_gc_specific_loop_opts_pass(mode);
|
||||
!bs->is_gc_specific_loop_opts_pass(_mode);
|
||||
bool do_expensive_nodes = C->should_optimize_expensive_nodes(_igvn);
|
||||
bool strip_mined_loops_expanded = bs->strip_mined_loops_expanded(mode);
|
||||
bool strip_mined_loops_expanded = bs->strip_mined_loops_expanded(_mode);
|
||||
if (stop_early && !do_expensive_nodes) {
|
||||
return;
|
||||
}
|
||||
@@ -3883,7 +3883,7 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
||||
|
||||
if (_verify_only) {
|
||||
C->restore_major_progress(old_progress);
|
||||
assert(C->unique() == unique, "verification mode made Nodes? ? ?");
|
||||
assert(C->unique() == unique, "verification _mode made Nodes? ? ?");
|
||||
assert(_igvn._worklist.size() == orig_worklist_size, "shouldn't push anything");
|
||||
return;
|
||||
}
|
||||
@@ -3913,8 +3913,8 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
||||
#ifndef PRODUCT
|
||||
C->verify_graph_edges();
|
||||
if (_verify_me) { // Nested verify pass?
|
||||
// Check to see if the verify mode is broken
|
||||
assert(C->unique() == unique, "non-optimize mode made Nodes? ? ?");
|
||||
// Check to see if the verify _mode is broken
|
||||
assert(C->unique() == unique, "non-optimize _mode made Nodes? ? ?");
|
||||
return;
|
||||
}
|
||||
if (VerifyLoopOptimizations) verify();
|
||||
@@ -3928,7 +3928,7 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode == LoopOptsMaxUnroll) {
|
||||
if (_mode == LoopOptsMaxUnroll) {
|
||||
for (LoopTreeIterator iter(_ltree_root); !iter.done(); iter.next()) {
|
||||
IdealLoopTree* lpt = iter.current();
|
||||
if (lpt->is_innermost() && lpt->_allow_optimizations && !lpt->_has_call && lpt->is_counted()) {
|
||||
@@ -3949,7 +3949,7 @@ void PhaseIdealLoop::build_and_optimize(LoopOptsMode mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bs->optimize_loops(this, mode, visited, nstack, worklist)) {
|
||||
if (bs->optimize_loops(this, _mode, visited, nstack, worklist)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5383,7 +5383,7 @@ void PhaseIdealLoop::build_loop_late_post_work(Node *n, bool pinned) {
|
||||
}
|
||||
// Try not to place code on a loop entry projection
|
||||
// which can inhibit range check elimination.
|
||||
if (least != early) {
|
||||
if (least != early && !BarrierSet::barrier_set()->barrier_set_c2()->is_gc_specific_loop_opts_pass(_mode)) {
|
||||
Node* ctrl_out = least->unique_ctrl_out();
|
||||
if (ctrl_out && ctrl_out->is_Loop() &&
|
||||
least == ctrl_out->in(LoopNode::EntryControl) &&
|
||||
|
||||
@@ -1050,9 +1050,10 @@ private:
|
||||
Node **_idom; // Array of immediate dominators
|
||||
uint *_dom_depth; // Used for fast LCA test
|
||||
GrowableArray<uint>* _dom_stk; // For recomputation of dom depth
|
||||
LoopOptsMode _mode;
|
||||
|
||||
// build the loop tree and perform any requested optimizations
|
||||
void build_and_optimize(LoopOptsMode mode);
|
||||
void build_and_optimize();
|
||||
|
||||
// Dominators for the sea of nodes
|
||||
void Dominators();
|
||||
@@ -1063,9 +1064,10 @@ private:
|
||||
_igvn(igvn),
|
||||
_verify_me(nullptr),
|
||||
_verify_only(false),
|
||||
_mode(mode),
|
||||
_nodes_required(UINT_MAX) {
|
||||
assert(mode != LoopOptsVerify, "wrong constructor to verify IdealLoop");
|
||||
build_and_optimize(mode);
|
||||
build_and_optimize();
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
@@ -1076,8 +1078,9 @@ private:
|
||||
_igvn(igvn),
|
||||
_verify_me(verify_me),
|
||||
_verify_only(verify_me == nullptr),
|
||||
_mode(LoopOptsVerify),
|
||||
_nodes_required(UINT_MAX) {
|
||||
build_and_optimize(LoopOptsVerify);
|
||||
build_and_optimize();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2129,6 +2129,11 @@ class AffectedKlassClosure : public KlassClosure {
|
||||
void do_klass(Klass* klass) {
|
||||
assert(!_affected_klasses->contains(klass), "must not occur more than once!");
|
||||
|
||||
// allow only loaded classes
|
||||
if (!klass->is_instance_klass() || !InstanceKlass::cast(klass)->is_loaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (klass->new_version() != NULL) {
|
||||
return;
|
||||
}
|
||||
@@ -2185,12 +2190,8 @@ jvmtiError VM_EnhancedRedefineClasses::find_sorted_affected_classes(TRAPS) {
|
||||
{
|
||||
MutexLocker mcld(ClassLoaderDataGraph_lock);
|
||||
|
||||
// We can't use ClassLoaderDataGraph::classes_do since classes can be uninitialized in cld,
|
||||
// fully initialized class is in system dictionary, but hidden classes are excluded. Therefore
|
||||
// we use special method iterating over initialized classes only
|
||||
// ClassLoaderDataGraph::classes_do(&closure);
|
||||
|
||||
ClassLoaderDataGraph::initialized_classes_do(&closure);
|
||||
// Hidden classes are not in SystemDictionary, so we have to iterate ClassLoaderDataGraph
|
||||
ClassLoaderDataGraph::classes_do(&closure);
|
||||
}
|
||||
|
||||
log_trace(redefine, class, load)("%d classes affected", _affected_klasses->length());
|
||||
|
||||
@@ -372,10 +372,12 @@ public:
|
||||
};
|
||||
|
||||
class AdjustMethodEntriesDcevm : public StackObj {
|
||||
bool* _trace_name_printed;
|
||||
GrowableArray<oop>* _oops_to_add;
|
||||
GrowableArray<oop>* _oops_to_update;
|
||||
GrowableArray<Method*>* _old_methods;
|
||||
public:
|
||||
AdjustMethodEntriesDcevm(GrowableArray<oop>* oops_to_add, bool* trace_name_printed) : _trace_name_printed(trace_name_printed), _oops_to_add(oops_to_add) {};
|
||||
AdjustMethodEntriesDcevm(GrowableArray<oop>* oops_to_update, GrowableArray<Method*>* old_methods) :
|
||||
_oops_to_update(oops_to_update), _old_methods(old_methods) {};
|
||||
|
||||
bool operator()(WeakHandle* entry) {
|
||||
oop mem_name = entry->peek();
|
||||
if (mem_name == NULL) {
|
||||
@@ -386,46 +388,8 @@ public:
|
||||
Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
|
||||
|
||||
if (old_method->is_old()) {
|
||||
|
||||
InstanceKlass* newer_klass = InstanceKlass::cast(old_method->method_holder()->new_version());
|
||||
Method* newer_method;
|
||||
|
||||
// Method* new_method;
|
||||
if (old_method->is_deleted()) {
|
||||
newer_method = Universe::throw_no_such_method_error();
|
||||
} else {
|
||||
newer_method = newer_klass->method_with_idnum(old_method->orig_method_idnum());
|
||||
|
||||
log_debug(redefine, class, update)("Adjusting method: '%s' of new class %s", newer_method->name_and_sig_as_C_string(), newer_klass->name()->as_C_string());
|
||||
|
||||
assert(newer_klass == newer_method->method_holder(), "call after swapping redefined guts");
|
||||
assert(newer_method != NULL, "method_with_idnum() should not be NULL");
|
||||
assert(old_method != newer_method, "sanity check");
|
||||
|
||||
Thread* thread = Thread::current();
|
||||
ResolvedMethodTableLookup lookup(thread, method_hash(newer_method), newer_method);
|
||||
ResolvedMethodGet rmg(thread, newer_method);
|
||||
|
||||
if (_local_table->get(thread, lookup, rmg)) {
|
||||
// old method was already adjusted if new method exists in _the_table
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, newer_method);
|
||||
java_lang_invoke_ResolvedMethodName::set_vmholder(mem_name, newer_method->method_holder()->java_mirror());
|
||||
|
||||
newer_klass->set_has_resolved_methods();
|
||||
_oops_to_add->append(mem_name);
|
||||
|
||||
ResourceMark rm;
|
||||
if (!(*_trace_name_printed)) {
|
||||
log_debug(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
|
||||
*_trace_name_printed = true;
|
||||
}
|
||||
log_debug(redefine, class, update, constantpool)
|
||||
("ResolvedMethod method update: %s(%s)",
|
||||
newer_method->name()->as_C_string(), newer_method->signature()->as_C_string());
|
||||
_oops_to_update->append(mem_name);
|
||||
_old_methods->append(old_method);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -440,36 +404,70 @@ void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) {
|
||||
_local_table->do_safepoint_scan(adjust);
|
||||
}
|
||||
|
||||
// It is called at safepoint only for RedefineClasses
|
||||
// It is called at safepoint only for EnhancedRedefineClasses
|
||||
void ResolvedMethodTable::adjust_method_entries_dcevm(bool * trace_name_printed) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
||||
// For each entry in RMT, change to new method
|
||||
GrowableArray<oop> oops_to_add(0);
|
||||
AdjustMethodEntriesDcevm adjust(&oops_to_add, trace_name_printed);
|
||||
|
||||
GrowableArray<oop> oops_to_update(0);
|
||||
GrowableArray<Method*> old_methods(0);
|
||||
|
||||
AdjustMethodEntriesDcevm adjust(&oops_to_update, &old_methods);
|
||||
_local_table->do_safepoint_scan(adjust);
|
||||
|
||||
Thread* thread = Thread::current();
|
||||
for (int i = 0; i < oops_to_add.length(); i++) {
|
||||
oop mem_name = oops_to_add.at(i);
|
||||
Method* method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
|
||||
|
||||
// The hash table takes ownership of the WeakHandle, even if it's not inserted.
|
||||
for (int i = 0; i < oops_to_update.length(); i++) {
|
||||
oop mem_name = oops_to_update.at(i);
|
||||
Method *old_method = old_methods.at(i);
|
||||
|
||||
ResolvedMethodTableLookup lookup(thread, method_hash(method), method);
|
||||
ResolvedMethodGet rmg(thread, method);
|
||||
// 1. Remove old method, since we are going to update class that could be used for hash evaluation in parallel running ServiceThread
|
||||
ResolvedMethodTableLookup lookup(thread, method_hash(old_method), old_method);
|
||||
_local_table->remove(thread, lookup);
|
||||
|
||||
InstanceKlass* newer_klass = InstanceKlass::cast(old_method->method_holder()->new_version());
|
||||
Method* newer_method;
|
||||
|
||||
// Method* new_method;
|
||||
if (old_method->is_deleted()) {
|
||||
newer_method = Universe::throw_no_such_method_error();
|
||||
} else {
|
||||
newer_method = newer_klass->method_with_idnum(old_method->orig_method_idnum());
|
||||
|
||||
assert(newer_method != NULL, "method_with_idnum() should not be NULL");
|
||||
assert(newer_klass == newer_method->method_holder(), "call after swapping redefined guts");
|
||||
assert(old_method != newer_method, "sanity check");
|
||||
|
||||
Thread* thread = Thread::current();
|
||||
ResolvedMethodTableLookup lookup(thread, method_hash(newer_method), newer_method);
|
||||
ResolvedMethodGet rmg(thread, newer_method);
|
||||
|
||||
while (true) {
|
||||
if (_local_table->get(thread, lookup, rmg)) {
|
||||
break;
|
||||
}
|
||||
WeakHandle wh(_oop_storage, mem_name);
|
||||
// The hash table takes ownership of the WeakHandle, even if it's not inserted.
|
||||
if (_local_table->insert(thread, lookup, wh)) {
|
||||
log_insert(method);
|
||||
wh.resolve();
|
||||
break;
|
||||
// old method was already adjusted if new method exists in _the_table
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
log_debug(redefine, class, update)("Adjusting method: '%s' of new class %s", newer_method->name_and_sig_as_C_string(), newer_klass->name()->as_C_string());
|
||||
|
||||
// 2. Update method
|
||||
java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, newer_method);
|
||||
java_lang_invoke_ResolvedMethodName::set_vmholder(mem_name, newer_method->method_holder()->java_mirror());
|
||||
|
||||
newer_klass->set_has_resolved_methods();
|
||||
|
||||
ResourceMark rm;
|
||||
if (!(*trace_name_printed)) {
|
||||
log_debug(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
|
||||
*trace_name_printed = true;
|
||||
}
|
||||
log_debug(redefine, class, update, constantpool)
|
||||
("ResolvedMethod method update: %s(%s)",
|
||||
newer_method->name()->as_C_string(), newer_method->signature()->as_C_string());
|
||||
|
||||
// 3. add updated method to table again
|
||||
add_method(newer_method, Handle(thread, mem_name));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
||||
@@ -2501,6 +2501,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m
|
||||
if (res != JNI_OK) {
|
||||
return res;
|
||||
}
|
||||
} else if (match_option(option, "--illegal-access=", &tail)) {
|
||||
char version[256];
|
||||
JDK_Version::jdk(17).to_string(version, sizeof(version));
|
||||
warning("Ignoring option %s; support was removed in %s", option->optionString, version);
|
||||
} else if (match_option(option, "--jbr-illegal-access", &tail)) {
|
||||
warning("Option --jbr-illegal-access is deprecated and will be removed in a future release.");
|
||||
if (!create_module_property("jdk.module.illegalAccess", "permit", ExternalProperty)) {
|
||||
@@ -4030,9 +4034,9 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) {
|
||||
// Set object alignment values.
|
||||
set_object_alignment();
|
||||
|
||||
#ifndef ZERO
|
||||
#if INCLUDE_JFR
|
||||
if (FlightRecorder) {
|
||||
if (AllowEnhancedClassRedefinition) {
|
||||
if (AllowEnhancedClassRedefinition || StartFlightRecording != NULL) {
|
||||
warning("EnhancedClassRedefinition was disabled, it is not allowed in FlightRecorder.");
|
||||
AllowEnhancedClassRedefinition = false;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2022, 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
|
||||
@@ -47,7 +47,6 @@ import java.util.regex.Pattern;
|
||||
import jdk.internal.access.JavaIOFileDescriptorAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.ref.CleanerFactory;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
|
||||
/* This class is for the exclusive use of ProcessBuilder.start() to
|
||||
@@ -269,11 +268,22 @@ final class ProcessImpl extends Process {
|
||||
// command line parser. The case of the [""] tail escape
|
||||
// sequence could not be realized due to the argument validation
|
||||
// procedure.
|
||||
int count = countLeadingBackslash(verificationType, s, s.length());
|
||||
while (count-- > 0) {
|
||||
cmdbuf.append(BACKSLASH); // double the number of backslashes
|
||||
if (verificationType == VERIFICATION_WIN32_SAFE ||
|
||||
verificationType == VERIFICATION_LEGACY) {
|
||||
int count = countLeadingBackslash(verificationType, s, s.length());
|
||||
while (count-- > 0) {
|
||||
cmdbuf.append(BACKSLASH); // double the number of backslashes
|
||||
}
|
||||
}
|
||||
cmdbuf.append('"');
|
||||
} else if (verificationType == VERIFICATION_WIN32_SAFE &&
|
||||
(s.startsWith("\"") && s.endsWith("\"") && s.length() > 2)) {
|
||||
// Check that quoted argument does not escape the final quote
|
||||
cmdbuf.append(s);
|
||||
int count = countLeadingBackslash(verificationType, s, s.length() - 1);
|
||||
while (count-- > 0) {
|
||||
cmdbuf.insert(cmdbuf.length() - 1, BACKSLASH); // double the number of backslashes
|
||||
}
|
||||
} else {
|
||||
cmdbuf.append(s);
|
||||
}
|
||||
@@ -282,9 +292,7 @@ final class ProcessImpl extends Process {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the argument without quotes (1st and last) if properly quoted, else the arg.
|
||||
* A properly quoted string has first and last characters as quote and
|
||||
* the last quote is not escaped.
|
||||
* Return the argument without quotes (first and last) if quoted, otherwise the arg.
|
||||
* @param str a string
|
||||
* @return the string without quotes
|
||||
*/
|
||||
@@ -292,9 +300,6 @@ final class ProcessImpl extends Process {
|
||||
if (!str.startsWith("\"") || !str.endsWith("\"") || str.length() < 2)
|
||||
return str; // no beginning or ending quote, or too short not quoted
|
||||
|
||||
if (str.endsWith("\\\"")) {
|
||||
return str; // not properly quoted, treat as unquoted
|
||||
}
|
||||
// Strip leading and trailing quotes
|
||||
return str.substring(1, str.length() - 1);
|
||||
}
|
||||
|
||||
@@ -41,12 +41,14 @@ import sun.java2d.SunGraphicsEnvironment;
|
||||
import sun.java2d.MacOSFlags;
|
||||
import sun.java2d.metal.MTLGraphicsConfig;
|
||||
import sun.java2d.opengl.CGLGraphicsConfig;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import static java.awt.peer.ComponentPeer.SET_BOUNDS;
|
||||
|
||||
public final class CGraphicsDevice extends GraphicsDevice
|
||||
implements DisplayChangedListener {
|
||||
|
||||
private static final PlatformLogger logger = PlatformLogger.getLogger(CGraphicsDevice.class.getName());
|
||||
/**
|
||||
* CoreGraphics display ID. This identifier can become non-valid at any time
|
||||
* therefore methods, which is using this id should be ready to it.
|
||||
@@ -381,6 +383,7 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
}
|
||||
|
||||
private void initScaleFactor() {
|
||||
int _scale = scale;
|
||||
if (SunGraphicsEnvironment.isUIScaleEnabled()) {
|
||||
double debugScale = SunGraphicsEnvironment.getDebugScale();
|
||||
scale = (int) (debugScale >= 1
|
||||
@@ -389,6 +392,9 @@ public final class CGraphicsDevice extends GraphicsDevice
|
||||
} else {
|
||||
scale = 1;
|
||||
}
|
||||
if (_scale != scale && logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("current scale = " + _scale + ", new scale = " + scale + " (" + this + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private static native double nativeGetScaleFactor(int displayID);
|
||||
|
||||
@@ -128,8 +128,12 @@ public class CCharToGlyphMapper extends CharToGlyphMapper {
|
||||
};
|
||||
}
|
||||
|
||||
// Missing characters for any font on the system will be returned as 0,
|
||||
// as the getMissingGlyphCode() function above indicates.
|
||||
// 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.
|
||||
private static native void nativeCharsToGlyphs(final long nativeFontPtr,
|
||||
int count, char[] unicodes,
|
||||
int[] glyphs);
|
||||
|
||||
81
src/java.desktop/macosx/classes/sun/font/CCompositeFont.java
Normal file
81
src/java.desktop/macosx/classes/sun/font/CCompositeFont.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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,9 +31,6 @@ 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
|
||||
@@ -178,12 +175,14 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
isFakeItalic = other.isFakeItalic;
|
||||
}
|
||||
|
||||
public CFont createItalicVariant() {
|
||||
public CFont createItalicVariant(boolean updateStyle) {
|
||||
CFont font = new CFont(this, familyName);
|
||||
font.nativeFontName = fullName;
|
||||
font.fullName =
|
||||
fullName + (style == Font.BOLD ? "" : "-") + "Italic-Derived";
|
||||
font.style |= Font.ITALIC;
|
||||
if (updateStyle) {
|
||||
font.style |= Font.ITALIC;
|
||||
}
|
||||
font.isFakeItalic = true;
|
||||
return font;
|
||||
}
|
||||
@@ -205,51 +204,11 @@ 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 = createCompositeFont();
|
||||
compFont = new CCompositeFont(this);
|
||||
}
|
||||
return compFont;
|
||||
}
|
||||
@@ -277,6 +236,14 @@ 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;
|
||||
@@ -309,4 +276,8 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
", familyName: " + familyName + ", style: " + style +
|
||||
" } aka: " + super.toString();
|
||||
}
|
||||
|
||||
public Font2D createItalic() {
|
||||
return this.createItalicVariant(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,27 +30,20 @@ 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() {
|
||||
@@ -237,7 +230,6 @@ public final class CFontManager extends SunFontManager {
|
||||
public Object run() {
|
||||
if (!loadedAllFonts) {
|
||||
loadNativeFonts();
|
||||
collectAdditionalFallbackVariants();
|
||||
loadedAllFonts = true;
|
||||
}
|
||||
return null;
|
||||
@@ -345,40 +337,4 @@ 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,13 +249,6 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
}
|
||||
|
||||
int getSlot0GlyphImagePtrs(int[] glyphCodes, long[] images, int len) {
|
||||
int ourGlyphs = 0;
|
||||
while (ourGlyphs < len && (glyphCodes[ourGlyphs] & CompositeGlyphMapper.SLOTMASK) == 0) ourGlyphs++;
|
||||
getGlyphImagePtrs(glyphCodes, images, ourGlyphs);
|
||||
return ourGlyphs;
|
||||
}
|
||||
|
||||
// called from the Sun2D renderer
|
||||
void getGlyphImagePtrs(int[] glyphCodes, long[] images, int len) {
|
||||
synchronized (glyphInfoCache) {
|
||||
@@ -365,14 +358,18 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
}
|
||||
|
||||
// This class stores glyph pointers, and is indexed based on glyph codes.
|
||||
// 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.
|
||||
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) {
|
||||
@@ -381,9 +378,19 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
|
||||
public synchronized long get(final int index) {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[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 (generalCache == null) {
|
||||
@@ -397,10 +404,21 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
|
||||
public synchronized void put(final int index, final long value) {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
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 (generalCache == null) {
|
||||
@@ -423,6 +441,14 @@ 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()) {
|
||||
@@ -459,18 +485,56 @@ 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 < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[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 (generalCache == null) return 0;
|
||||
@@ -480,10 +544,21 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
|
||||
public synchronized void put(final int index, final float value) {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
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 (generalCache == null) {
|
||||
@@ -492,5 +567,34 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,13 @@ import sun.java2d.NullSurfaceData;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.lwawt.LWWindowPeer;
|
||||
import sun.lwawt.macosx.CFLayer;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.awt.GraphicsConfiguration;
|
||||
import java.awt.Insets;
|
||||
|
||||
public class MTLLayer extends CFLayer {
|
||||
private static final PlatformLogger logger = PlatformLogger.getLogger(MTLLayer.class.getName());
|
||||
|
||||
private native long nativeCreateLayer();
|
||||
private static native void nativeSetScale(long layerPtr, double scale);
|
||||
@@ -49,6 +52,14 @@ public class MTLLayer extends CFLayer {
|
||||
|
||||
setPtr(nativeCreateLayer());
|
||||
this.peer = peer;
|
||||
|
||||
MTLGraphicsConfig gc = (MTLGraphicsConfig)getGraphicsConfiguration();
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("device = " + (gc != null ? gc.getDevice() : "null"));
|
||||
}
|
||||
if (gc != null) {
|
||||
setScale(gc.getDevice().getScaleFactor());
|
||||
}
|
||||
}
|
||||
|
||||
public SurfaceData replaceSurfaceData() {
|
||||
@@ -99,6 +110,10 @@ public class MTLLayer extends CFLayer {
|
||||
|
||||
private void setScale(final int _scale) {
|
||||
if (scale != _scale) {
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
MTLGraphicsConfig gc = (MTLGraphicsConfig)getGraphicsConfiguration();
|
||||
logger.fine("current scale = " + scale + ", new scale = " + _scale + " (device = " + (gc != null ? gc.getDevice() : "null") + ")");
|
||||
}
|
||||
scale = _scale;
|
||||
execute(ptr -> nativeSetScale(ptr, scale));
|
||||
}
|
||||
|
||||
@@ -31,8 +31,10 @@ import sun.java2d.NullSurfaceData;
|
||||
import sun.lwawt.LWWindowPeer;
|
||||
import sun.java2d.SurfaceData;
|
||||
import sun.lwawt.macosx.CFLayer;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
public class CGLLayer extends CFLayer {
|
||||
private static final PlatformLogger logger = PlatformLogger.getLogger(CGLLayer.class.getName());
|
||||
|
||||
private native long nativeCreateLayer();
|
||||
private static native void nativeSetScale(long layerPtr, double scale);
|
||||
@@ -46,6 +48,14 @@ public class CGLLayer extends CFLayer {
|
||||
|
||||
setPtr(nativeCreateLayer());
|
||||
this.peer = peer;
|
||||
|
||||
CGraphicsConfig gc = (CGraphicsConfig)getGraphicsConfiguration();
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
logger.fine("device = " + (gc != null ? gc.getDevice() : "null"));
|
||||
}
|
||||
if (gc != null) {
|
||||
setScale(gc.getDevice().getScaleFactor());
|
||||
}
|
||||
}
|
||||
|
||||
public SurfaceData replaceSurfaceData() {
|
||||
@@ -94,8 +104,12 @@ public class CGLLayer extends CFLayer {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
private void setScale(final int _scale) {
|
||||
private void setScale(int _scale) {
|
||||
if (scale != _scale) {
|
||||
if (logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
CGraphicsConfig gc = (CGraphicsConfig)getGraphicsConfiguration();
|
||||
logger.fine("current scale = " + scale + ", new scale = " + _scale + " (device = " + (gc != null ? gc.getDevice() : "null") + ")");
|
||||
}
|
||||
scale = _scale;
|
||||
execute(ptr -> nativeSetScale(ptr, scale));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2022, 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
|
||||
@@ -59,6 +59,7 @@ import java.awt.peer.KeyboardFocusManagerPeer;
|
||||
import java.awt.peer.WindowPeer;
|
||||
import java.util.List;
|
||||
|
||||
import java.util.Objects;
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import sun.awt.AWTAccessor;
|
||||
@@ -283,6 +284,16 @@ public class LWWindowPeer
|
||||
super.disposeImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(final Color c) {
|
||||
Color oldBg = getBackground();
|
||||
if (Objects.equals(oldBg, c)) {
|
||||
return;
|
||||
}
|
||||
super.setBackground(c);
|
||||
updateOpaque();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setVisibleImpl(final boolean visible) {
|
||||
if (!visible && warningWindow != null) {
|
||||
@@ -291,10 +302,6 @@ public class LWWindowPeer
|
||||
updateFocusableWindowState();
|
||||
super.setVisibleImpl(visible);
|
||||
// TODO: update graphicsConfig, see 4868278
|
||||
if (visible) {
|
||||
// Set correct background for a window before making it visible
|
||||
platformWindow.setOpaque(!isTranslucent());
|
||||
}
|
||||
platformWindow.setVisible(visible);
|
||||
}
|
||||
|
||||
|
||||
@@ -205,8 +205,10 @@ class CAccessible extends CFRetainedResource implements Accessible {
|
||||
} else if (oldValue != null &&
|
||||
((AccessibleState) oldValue) == AccessibleState.VISIBLE) {
|
||||
execute(ptr -> menuClosed(ptr));
|
||||
execute(ptr -> unregisterFromCocoaAXSystem(ptr));
|
||||
}
|
||||
} else if (thisRole == AccessibleRole.MENU_ITEM) {
|
||||
} else if (thisRole == AccessibleRole.MENU_ITEM ||
|
||||
((parentRole == AccessibleRole.POPUP_MENU) && (thisRole == AccessibleRole.MENU))) {
|
||||
if (newValue != null &&
|
||||
((AccessibleState) newValue) == AccessibleState.FOCUSED) {
|
||||
execute(ptr -> menuItemSelected(ptr));
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
package sun.lwawt.macosx;
|
||||
|
||||
import sun.awt.AWTThreading;
|
||||
import java.awt.Menu;
|
||||
import java.awt.MenuBar;
|
||||
import java.awt.MenuItem;
|
||||
@@ -64,14 +65,14 @@ public class CMenu extends CMenuItem implements MenuPeer {
|
||||
LWCToolkit.targetToPeer(getTarget().getParent());
|
||||
|
||||
if (parent instanceof CMenu) {
|
||||
return parent.executeGet(this::nativeCreateSubMenu);
|
||||
return AWTThreading.executeWaitToolkit(() -> parent.executeGet(this::nativeCreateSubMenu));
|
||||
}
|
||||
if (parent instanceof CMenuBar) {
|
||||
MenuBar parentContainer = (MenuBar)getTarget().getParent();
|
||||
boolean isHelpMenu = parentContainer.getHelpMenu() == getTarget();
|
||||
int insertionLocation = ((CMenuBar)parent).getNextInsertionIndex();
|
||||
return parent.executeGet(ptr -> nativeCreateMenu(ptr, isHelpMenu,
|
||||
insertionLocation));
|
||||
return AWTThreading.executeWaitToolkit(() -> parent.executeGet(ptr -> nativeCreateMenu(ptr, isHelpMenu,
|
||||
insertionLocation)));
|
||||
}
|
||||
throw new InternalError("Parent must be CMenu or CMenuBar");
|
||||
}
|
||||
@@ -84,7 +85,7 @@ public class CMenu extends CMenuItem implements MenuPeer {
|
||||
|
||||
@Override
|
||||
public final void delItem(final int index) {
|
||||
execute(ptr -> nativeDeleteItem(ptr, index));
|
||||
AWTThreading.executeWaitToolkit(() -> execute(ptr -> nativeDeleteItem(ptr, index)));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,6 +33,7 @@ import java.awt.event.KeyEvent;
|
||||
import java.awt.peer.MenuItemPeer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import sun.awt.AWTThreading;
|
||||
import sun.awt.SunToolkit;
|
||||
import sun.lwawt.LWToolkit;
|
||||
|
||||
@@ -61,7 +62,7 @@ public class CMenuItem extends CMenuComponent implements MenuItemPeer {
|
||||
@Override
|
||||
long createModel() {
|
||||
CMenuComponent parent = (CMenuComponent)LWToolkit.targetToPeer(getTarget().getParent());
|
||||
return parent.executeGet(ptr->nativeCreate(ptr, isSeparator()));
|
||||
return AWTThreading.executeWaitToolkit(() -> parent.executeGet(ptr->nativeCreate(ptr, isSeparator())));
|
||||
}
|
||||
@SuppressWarnings("deprecation")
|
||||
public void setLabel(String label, char keyChar, int keyCode, int modifiers) {
|
||||
|
||||
@@ -112,6 +112,7 @@ import sun.lwawt.PlatformComponent;
|
||||
import sun.lwawt.PlatformDropTarget;
|
||||
import sun.lwawt.PlatformWindow;
|
||||
import sun.lwawt.SecurityWarningWindow;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
@SuppressWarnings("serial") // JDK implementation class
|
||||
@@ -141,6 +142,13 @@ public final class LWCToolkit extends LWToolkit {
|
||||
|
||||
private static CInputMethodDescriptor sInputMethodDescriptor;
|
||||
|
||||
// Listens to EDT state in invokeAndWait() and disposes the invocation event
|
||||
// when EDT becomes free but the invocation event is not yet dispatched (considered lost).
|
||||
// This prevents a deadlock and makes the invocation return some default result.
|
||||
@SuppressWarnings("removal")
|
||||
private static final boolean DISPOSE_INVOCATION_ON_EDT_FREE =
|
||||
AccessController.doPrivileged(new GetBooleanAction("sun.lwawt.macosx.LWCToolkit.invokeAndWait.disposeOnEDTFree"));
|
||||
|
||||
static {
|
||||
System.err.flush();
|
||||
|
||||
@@ -187,7 +195,7 @@ public final class LWCToolkit extends LWToolkit {
|
||||
*/
|
||||
private static final boolean inAWT;
|
||||
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger("sun.lwawt.macosx.LWCToolkit");
|
||||
private static final PlatformLogger log = PlatformLogger.getLogger(LWCToolkit.class.getName());
|
||||
|
||||
public LWCToolkit() {
|
||||
final String extraButtons = "sun.awt.enableExtraMouseButtons";
|
||||
@@ -496,7 +504,8 @@ public final class LWCToolkit extends LWToolkit {
|
||||
if (!(gd instanceof CGraphicsDevice)) {
|
||||
return AWTThreading.executeWaitToolkit(() -> super.getScreenInsets(gc));
|
||||
}
|
||||
return AWTThreading.executeWaitToolkit(() -> ((CGraphicsDevice)gd).getScreenInsets());
|
||||
CGraphicsDevice cgd = (CGraphicsDevice) gd;
|
||||
return cgd.getScreenInsets();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -711,30 +720,6 @@ public final class LWCToolkit extends LWToolkit {
|
||||
}
|
||||
}
|
||||
|
||||
private static final AtomicInteger blockingRunLoopCounter = new AtomicInteger(0);
|
||||
private static final AtomicBoolean priorityInvocationPending = new AtomicBoolean(false);
|
||||
|
||||
@Override
|
||||
public void unsafeNonblockingExecute(Runnable runnable) {
|
||||
if (!EventQueue.isDispatchThread()) {
|
||||
throw new Error("the method must be called on the Event Dispatching thread");
|
||||
}
|
||||
if (runnable == null) return;
|
||||
|
||||
synchronized (priorityInvocationPending) {
|
||||
priorityInvocationPending.set(true);
|
||||
}
|
||||
AWTAccessor.getEventQueueAccessor().createSecondaryLoop(
|
||||
getSystemEventQueue(),
|
||||
() -> blockingRunLoopCounter.get() > 0).enter();
|
||||
|
||||
try {
|
||||
runnable.run();
|
||||
} finally {
|
||||
priorityInvocationPending.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Kicks an event over to the appropriate eventqueue and waits for it to
|
||||
* finish To avoid deadlocking, we manually run the NSRunLoop while waiting
|
||||
@@ -766,11 +751,18 @@ public final class LWCToolkit extends LWToolkit {
|
||||
log.fine("invokeAndWait started: " + runnable);
|
||||
}
|
||||
|
||||
boolean nonBlockingRunLoop;
|
||||
|
||||
synchronized (priorityInvocationPending) {
|
||||
nonBlockingRunLoop = priorityInvocationPending.get();
|
||||
if (!nonBlockingRunLoop) blockingRunLoopCounter.incrementAndGet();
|
||||
if (isBlockingEventDispatchThread()) {
|
||||
String msg = "invokeAndWait is discarded as the EventDispatch thread is currently blocked";
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine(msg, new Throwable());
|
||||
log.fine(AWTThreading.getInstance(component).printEventDispatchThreadStackTrace().toString());
|
||||
} else if (log.isLoggable(PlatformLogger.Level.INFO)) {
|
||||
StackTraceElement[] stack = new Throwable().getStackTrace();
|
||||
log.info(msg + ". Originated at " + stack[stack.length - 1]);
|
||||
Thread dispatchThread = AWTThreading.getInstance(component).getEventDispatchThread();
|
||||
log.info(dispatchThread.getName() + " at: " + dispatchThread.getStackTrace()[0].toString());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
AWTThreading.TrackedInvocationEvent invocationEvent =
|
||||
@@ -791,22 +783,21 @@ public final class LWCToolkit extends LWToolkit {
|
||||
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
|
||||
}
|
||||
|
||||
CompletableFuture<Void> eventDispatchThreadFreeFuture =
|
||||
AWTThreading.getInstance(component).onEventDispatchThreadFree(() -> {
|
||||
if (!invocationEvent.isDone()) {
|
||||
// EventQueue is now empty but the posted InvocationEvent is still not dispatched,
|
||||
// consider it lost then.
|
||||
invocationEvent.dispose("InvocationEvent was lost");
|
||||
}
|
||||
});
|
||||
|
||||
invocationEvent.onDone(() -> eventDispatchThreadFreeFuture.cancel(false));
|
||||
|
||||
if (!doAWTRunLoop(mediator, nonBlockingRunLoop, timeoutSeconds)) {
|
||||
invocationEvent.dispose("InvocationEvent has timed out");
|
||||
if (DISPOSE_INVOCATION_ON_EDT_FREE) {
|
||||
CompletableFuture<Void> eventDispatchThreadFreeFuture =
|
||||
AWTThreading.getInstance(component).onEventDispatchThreadFree(() -> {
|
||||
if (!invocationEvent.isCompleted(true)) {
|
||||
// EventQueue is now empty but the posted InvocationEvent is still not dispatched,
|
||||
// consider it lost then.
|
||||
invocationEvent.dispose("InvocationEvent was lost");
|
||||
}
|
||||
});
|
||||
invocationEvent.onDone(() -> eventDispatchThreadFreeFuture.cancel(false));
|
||||
}
|
||||
|
||||
if (!nonBlockingRunLoop) blockingRunLoopCounter.decrementAndGet();
|
||||
if (!doAWTRunLoop(mediator, false, timeoutSeconds)) {
|
||||
invocationEvent.dispose("InvocationEvent has timed out");
|
||||
}
|
||||
|
||||
if (log.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
log.fine("invokeAndWait finished: " + runnable);
|
||||
@@ -815,6 +806,8 @@ public final class LWCToolkit extends LWToolkit {
|
||||
checkException(invocationEvent);
|
||||
}
|
||||
|
||||
private static native boolean isBlockingEventDispatchThread();
|
||||
|
||||
public static void invokeLater(Runnable event, Component component)
|
||||
throws InvocationTargetException {
|
||||
Objects.requireNonNull(component, "Null component provided to invokeLater");
|
||||
@@ -857,6 +850,11 @@ public final class LWCToolkit extends LWToolkit {
|
||||
*/
|
||||
static native void performOnMainThreadAfterDelay(Runnable r, long delay);
|
||||
|
||||
/**
|
||||
* Schedules a {@code Runnable} execution on the Appkit thread and waits for completion.
|
||||
*/
|
||||
public static native void performOnMainThreadAndWait(Runnable r);
|
||||
|
||||
// DnD support
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1653,7 +1653,15 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
// resets the NSWindow's style mask if the mask intersects any of those bits
|
||||
if (mask & MASK(_STYLE_PROP_BITMASK)) {
|
||||
[nsWindow setStyleMask:[AWTWindow styleMaskForStyleBits:newBits]];
|
||||
NSWindowStyleMask styleMask = [AWTWindow styleMaskForStyleBits:newBits];
|
||||
@try {
|
||||
[nsWindow setStyleMask:styleMask];
|
||||
} @catch (NSException *e) {
|
||||
NSLog(@"WARNING: suppressed exception from [NSWindow setStyleMask] in CPlatformWindow"
|
||||
".nativeSetNSWindowStyleBits");
|
||||
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
|
||||
[NSApplicationAWT logException:e forProcess:processInfo];
|
||||
}
|
||||
}
|
||||
|
||||
// calls methods on NSWindow to change other properties, based on the mask
|
||||
|
||||
@@ -237,7 +237,7 @@ static BOOL sNeedsEnter;
|
||||
jobject transferer = [self dataTransferer:env];
|
||||
jbyteArray data = nil;
|
||||
|
||||
if (transferer != NULL) {
|
||||
if (transferer != NULL && fComponent != NULL) {
|
||||
GET_DT_CLASS_RETURN(NULL);
|
||||
DECLARE_METHOD_RETURN(convertDataMethod, DataTransfererClass, "convertData", "(Ljava/lang/Object;Ljava/awt/datatransfer/Transferable;JLjava/util/Map;Z)[B", NULL);
|
||||
data = (*env)->CallObjectMethod(env, transferer, convertDataMethod, fComponent, fTransferable, format, fFormatMap, (jboolean) TRUE);
|
||||
|
||||
@@ -69,6 +69,9 @@ static int* gsButtonEventNumber;
|
||||
static NSTimeInterval gNextKeyEventTime;
|
||||
static NSTimeInterval safeDelay;
|
||||
|
||||
#define KEY_CODE_COUNT 128
|
||||
static CGEventFlags keyOwnFlags[KEY_CODE_COUNT];
|
||||
|
||||
static inline CGKeyCode GetCGKeyCode(jint javaKeyCode);
|
||||
|
||||
static void PostMouseEvent(const CGPoint point, CGMouseButton button,
|
||||
@@ -107,6 +110,20 @@ static inline void autoDelay(BOOL isMove) {
|
||||
gNextKeyEventTime = [[NSDate date] timeIntervalSinceReferenceDate] + safeDelay;
|
||||
}
|
||||
|
||||
static void initKeyFlags() {
|
||||
CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
|
||||
for (CGKeyCode keyCode = 0; keyCode < KEY_CODE_COUNT; keyCode++) {
|
||||
CGEventRef event = CGEventCreateKeyboardEvent(source, keyCode, true);
|
||||
if (event != NULL) {
|
||||
keyOwnFlags[keyCode] = CGEventGetFlags(event);
|
||||
CFRelease(event);
|
||||
}
|
||||
}
|
||||
if (source != NULL) {
|
||||
CFRelease(source);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CRobot
|
||||
* Method: initRobot
|
||||
@@ -155,6 +172,8 @@ Java_sun_lwawt_macosx_CRobot_initRobot
|
||||
for (i = 0; i < gNumberOfButtons; ++i) {
|
||||
gsButtonEventNumber[i] = ROBOT_EVENT_NUMBER_START;
|
||||
}
|
||||
|
||||
initKeyFlags();
|
||||
}];
|
||||
}
|
||||
}
|
||||
@@ -283,6 +302,20 @@ Java_sun_lwawt_macosx_CRobot_mouseWheel
|
||||
}];
|
||||
}
|
||||
|
||||
// CGEventCreateKeyboardEvent incorrectly handles flags pertinent to non-modifier keys
|
||||
// (e.g. F1-F12 keys always Fn flag set, while arrow keys always have Fn and NumPad flags set).
|
||||
// Those flags are not cleared for following key presses automatically, so we need to do it ourselves.
|
||||
// See JBR-4306 for details.
|
||||
static void clearStickyFlags(CGEventRef event, CGKeyCode keyCode, CGEventFlags flagToCheck) {
|
||||
if (keyCode < KEY_CODE_COUNT && (keyOwnFlags[keyCode] & flagToCheck) == 0) {
|
||||
CGEventFlags flags = CGEventGetFlags(event);
|
||||
CGEventFlags updatedFlags = flags & ~flagToCheck;
|
||||
if (updatedFlags != flags) {
|
||||
CGEventSetFlags(event, updatedFlags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_CRobot
|
||||
* Method: keyEvent
|
||||
@@ -298,6 +331,10 @@ Java_sun_lwawt_macosx_CRobot_keyEvent
|
||||
CGKeyCode keyCode = GetCGKeyCode(javaKeyCode);
|
||||
CGEventRef event = CGEventCreateKeyboardEvent(source, keyCode, keyPressed);
|
||||
if (event != NULL) {
|
||||
// this assumes Robot isn't used to generate Fn key presses
|
||||
clearStickyFlags(event, keyCode, kCGEventFlagMaskSecondaryFn);
|
||||
// there is no NumPad key, so this won't hurt in any case
|
||||
clearStickyFlags(event, keyCode, kCGEventFlagMaskNumericPad);
|
||||
CGEventPost(kCGHIDEventTap, event);
|
||||
CFRelease(event);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,51 @@ 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
|
||||
@@ -84,7 +129,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 CGGlyph glyphs[], CGSize advances[], const jint g_gvTXIndicesAsInts[], const jdouble g_gvTransformsAsDoubles[], const CFIndex length)
|
||||
(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)
|
||||
{
|
||||
CGPoint pt = { 0, 0 };
|
||||
|
||||
@@ -92,12 +137,49 @@ 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;
|
||||
@@ -132,6 +214,10 @@ 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
|
||||
@@ -241,16 +327,24 @@ 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, CGGlyph *glyphs, CGSize *advances, size_t length)
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, BOOL useSubstituion, int *uniChars, CGGlyph *glyphs, CGSize *advances, size_t length)
|
||||
{
|
||||
// if we have no per-glyph transformations - strike now!
|
||||
// if we have no character substitution, and 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)
|
||||
{
|
||||
// fast path, straight to CG without per-glyph transforms
|
||||
CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
|
||||
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);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -275,8 +369,8 @@ static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
|
||||
(*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
|
||||
return;
|
||||
}
|
||||
// slowest case, we have per-glyph transforms
|
||||
JavaCT_DrawGlyphVector(qsdo, strike, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
|
||||
// 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);
|
||||
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, g_gtiTXIndicesArray, g_gvTXIndicesAsInts, JNI_ABORT);
|
||||
@@ -285,11 +379,35 @@ 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, CGSize *advances, size_t length, jintArray glyphsArray)
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, int *uniChars, CGSize *advances, size_t length, jintArray glyphsArray)
|
||||
{
|
||||
// fill the glyph buffer
|
||||
jint *glyphsAsInts = (*env)->GetPrimitiveArrayCritical(env, glyphsArray, NULL);
|
||||
@@ -297,10 +415,24 @@ 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++)
|
||||
{
|
||||
glyphs[i] = glyphsAsInts[i];
|
||||
jint code = glyphsAsInts[i];
|
||||
if (code < 0)
|
||||
{
|
||||
complex = YES;
|
||||
uniChars[i] = -code;
|
||||
glyphs[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uniChars[i] = 0;
|
||||
glyphs[i] = code;
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, glyphsArray, glyphsAsInts, JNI_ABORT);
|
||||
@@ -351,10 +483,15 @@ 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, glyphs, advances, length);
|
||||
doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, complex, uniChars, 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,
|
||||
@@ -378,16 +515,18 @@ 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, advances, length, glyphsArray);
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, 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 || advances == NULL)
|
||||
if (glyphs == NULL || uniChars == NULL || advances == NULL)
|
||||
{
|
||||
(*env)->DeleteLocalRef(env, glyphsArray);
|
||||
[NSException raise:NSMallocException format:@"%s-%s:%d", __FILE__, __FUNCTION__, __LINE__];
|
||||
@@ -395,6 +534,10 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
|
||||
{
|
||||
free(glyphs);
|
||||
}
|
||||
if (uniChars)
|
||||
{
|
||||
free(uniChars);
|
||||
}
|
||||
if (advances)
|
||||
{
|
||||
free(advances);
|
||||
@@ -402,9 +545,10 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
|
||||
return;
|
||||
}
|
||||
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, advances, length, glyphsArray);
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
|
||||
|
||||
free(glyphs);
|
||||
free(uniChars);
|
||||
free(advances);
|
||||
}
|
||||
|
||||
|
||||
@@ -620,6 +620,17 @@ JNI_COCOA_EXIT(env);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_LWCToolkit
|
||||
* Method: isBlockingEventDispatchThread
|
||||
* Signature: ()Z
|
||||
*/
|
||||
JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_isBlockingEventDispatchThread
|
||||
(JNIEnv *env, jclass clz)
|
||||
{
|
||||
return ThreadUtilities.blockingEventDispatchThread;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_LWCToolkit
|
||||
* Method: stopAWTRunLoop
|
||||
@@ -659,6 +670,23 @@ JNI_COCOA_ENTER(env);
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_LWCToolkit
|
||||
* Method: performOnMainThreadAndWait
|
||||
* Signature: (Ljava/lang/Runnable)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_performOnMainThreadAndWait
|
||||
(JNIEnv *env, jclass clz, jobject runnable)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
jobject gRunnable = (*env)->NewGlobalRef(env, runnable);
|
||||
CHECK_NULL(gRunnable);
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^() {
|
||||
JavaRunnable* performer = [[JavaRunnable alloc] initWithRunnable:gRunnable];
|
||||
[performer perform];
|
||||
}];
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_lwawt_macosx_LWCToolkit
|
||||
|
||||
@@ -126,7 +126,7 @@ static jobject sAccessibilityClass = NULL;
|
||||
/*
|
||||
* Here we should keep all the mapping between the accessibility roles and implementing classes
|
||||
*/
|
||||
rolesMap = [[NSMutableDictionary alloc] initWithCapacity:51];
|
||||
rolesMap = [[NSMutableDictionary alloc] initWithCapacity:50];
|
||||
|
||||
[rolesMap setObject:@"ButtonAccessibility" forKey:@"pushbutton"];
|
||||
[rolesMap setObject:@"ImageAccessibility" forKey:@"icon"];
|
||||
@@ -158,7 +158,6 @@ static jobject sAccessibilityClass = NULL;
|
||||
[rolesMap setObject:@"TableAccessibility" forKey:@"table"];
|
||||
[rolesMap setObject:@"MenuBarAccessibility" forKey:@"menubar"];
|
||||
[rolesMap setObject:@"MenuAccessibility" forKey:@"menu"];
|
||||
[rolesMap setObject:@"MenuItemAccessibility" forKey:@"menuitem"];
|
||||
[rolesMap setObject:@"MenuAccessibility" forKey:@"popupmenu"];
|
||||
[rolesMap setObject:@"ProgressIndicatorAccessibility" forKey:@"progressbar"];
|
||||
|
||||
@@ -186,10 +185,11 @@ static jobject sAccessibilityClass = NULL;
|
||||
[rolesMap setObject:IgnoreClassName forKey:@"viewport"];
|
||||
[rolesMap setObject:IgnoreClassName forKey:@"window"];
|
||||
|
||||
rowRolesMapForParent = [[NSMutableDictionary alloc] initWithCapacity:2];
|
||||
rowRolesMapForParent = [[NSMutableDictionary alloc] initWithCapacity:3];
|
||||
|
||||
[rowRolesMapForParent setObject:@"ListRowAccessibility" forKey:@"ListAccessibility"];
|
||||
[rowRolesMapForParent setObject:@"OutlineRowAccessibility" forKey:@"OutlineAccessibility"];
|
||||
[rowRolesMapForParent setObject:@"MenuItemAccessibility" forKey:@"MenuAccessibility"];
|
||||
|
||||
/*
|
||||
* Initialize CAccessibility instance
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
|
||||
- (BOOL)isAccessibilityElement
|
||||
{
|
||||
return YES;
|
||||
return [[[self accessibilityParent] accessibilityRole] isEqualToString:NSAccessibilityComboBoxRole];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -1692,6 +1692,10 @@ static NSDictionary* prebuiltFamilyNames() {
|
||||
@"SourceCodePro-BoldIt" : @"Source Code Pro",
|
||||
@"SourceCodePro-It" : @"Source Code Pro",
|
||||
@"SourceCodePro-Regular" : @"Source Code Pro",
|
||||
@"Inter-Bold": @"Inter",
|
||||
@"Inter-BoldItalic": @"Inter",
|
||||
@"Inter-Italic": @"Inter",
|
||||
@"Inter-Regular": @"Inter",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3342,64 +3346,6 @@ 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,6 +28,7 @@
|
||||
#import "sun_font_CStrikeDisposer.h"
|
||||
#import "CGGlyphImages.h"
|
||||
#import "CGGlyphOutlines.h"
|
||||
#import "CoreTextSupport.h"
|
||||
#import "JNIUtilities.h"
|
||||
#include "fontscalerdefs.h"
|
||||
#import "LWCToolkit.h"
|
||||
@@ -159,8 +160,12 @@ JNI_COCOA_ENTER(env);
|
||||
AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
|
||||
AWTFont *awtFont = awtStrike->fAWTFont;
|
||||
|
||||
CGGlyph glyph = glyphCode;
|
||||
CGGlyphImages_GetGlyphMetrics((CTFontRef)awtFont->fFont, &awtStrike->fAltTx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, NULL, &advance, IS_OSX_GT10_14);
|
||||
// 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);
|
||||
advance = CGSizeApplyAffineTransform(advance, awtStrike->fFontTx);
|
||||
if (!JRSFontStyleUsesFractionalMetrics(awtStrike->fStyle)) {
|
||||
advance.width = round(advance.width);
|
||||
@@ -190,9 +195,14 @@ JNI_COCOA_ENTER(env);
|
||||
tx.tx += x;
|
||||
tx.ty += y;
|
||||
|
||||
CGGlyph glyph = glyphCode;
|
||||
// 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);
|
||||
|
||||
CGRect bbox;
|
||||
CGGlyphImages_GetGlyphMetrics((CTFontRef)awtFont->fFont, &tx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, &bbox, NULL, IS_OSX_GT10_14);
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &tx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, &bbox, NULL, IS_OSX_GT10_14);
|
||||
CFRelease(fallback);
|
||||
|
||||
// the origin of this bounding box is relative to the bottom-left corner baseline
|
||||
CGFloat decender = -bbox.origin.y;
|
||||
@@ -241,12 +251,14 @@ AWT_FONT_CLEANUP_CHECK(awtfont);
|
||||
tx.tx += xPos;
|
||||
tx.ty += yPos;
|
||||
|
||||
CGGlyph glyph = glyphCode;
|
||||
NSFont *font = awtfont->fFont;
|
||||
// get the right font and glyph for this "Java GlyphCode"
|
||||
|
||||
CGGlyph glyph;
|
||||
const CTFontRef font = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtfont, glyphCode, &glyph);
|
||||
|
||||
// get the advance of this glyph
|
||||
CGSize advance;
|
||||
CTFontGetAdvancesForGlyphs((CTFontRef)font, kCTFontDefaultOrientation, &glyph, &advance, 1);
|
||||
CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, &glyph, &advance, 1);
|
||||
|
||||
// Create AWTPath
|
||||
path = AWTPathCreate(CGSizeMake(xPos, yPos));
|
||||
@@ -255,7 +267,8 @@ AWT_FONT_CLEANUP_CHECK(path);
|
||||
// Get the paths
|
||||
tx = awtStrike->fTx;
|
||||
tx = CGAffineTransformConcat(tx, sInverseTX);
|
||||
AWTGetGlyphOutline(&glyph, font, &advance, &tx, 0, 1, &path);
|
||||
AWTGetGlyphOutline(&glyph, (NSFont *)font, &advance, &tx, 0, 1, &path);
|
||||
CFRelease(font);
|
||||
|
||||
pointCoords = (*env)->NewFloatArray(env, path->fNumberOfDataElements);
|
||||
AWT_FONT_CLEANUP_CHECK(pointCoords);
|
||||
@@ -309,14 +322,19 @@ JNIEXPORT void JNICALL Java_sun_font_CStrike_getNativeGlyphOutlineBounds
|
||||
AWT_FONT_CLEANUP_SETUP;
|
||||
AWT_FONT_CLEANUP_CHECK(awtfont);
|
||||
|
||||
CGGlyph glyph = glyphCode;
|
||||
// get the right font and glyph for this "Java GlyphCode"
|
||||
CGGlyph glyph;
|
||||
const CTFontRef font = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(
|
||||
awtfont, glyphCode, &glyph);
|
||||
|
||||
CGRect bbox = CTFontGetBoundingRectsForGlyphs(
|
||||
(CTFontRef)awtfont->fFont, kCTFontOrientationDefault, &glyph, NULL, 1);
|
||||
font, kCTFontOrientationDefault, &glyph, NULL, 1);
|
||||
|
||||
CGAffineTransform tx = CGAffineTransformConcat(awtStrike->fTx,
|
||||
sInverseTX);
|
||||
|
||||
bbox = CGRectApplyAffineTransform (bbox, tx);
|
||||
CFRelease(font);
|
||||
jfloat *rawRectData =
|
||||
(*env)->GetPrimitiveArrayCritical(env, rectData, NULL);
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#import "CoreTextSupport.h"
|
||||
|
||||
#import "sun_font_CCharToGlyphMapper.h"
|
||||
#import "sun_font_CCompositeGlyphMapper.h"
|
||||
|
||||
/*
|
||||
* Class: sun_font_CCharToGlyphMapper
|
||||
@@ -113,3 +114,28 @@ 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,6 +27,7 @@
|
||||
|
||||
#import "JNIUtilities.h"
|
||||
#import "CGGlyphImages.h"
|
||||
#import "CoreTextSupport.h"
|
||||
#import "fontscalerdefs.h" // contains the definition of GlyphInfo struct
|
||||
|
||||
#import "sun_awt_SunHints.h"
|
||||
@@ -646,6 +647,16 @@ CGGI_CreateNewGlyphInfoFrom(CGSize advance, CGRect bbox,
|
||||
#define RENDER_GLYPH_BATCH_SIZE 16
|
||||
#define RENDER_GLYPH_ARRAY_INIT_8 glyph,glyph,glyph,glyph,glyph,glyph,glyph,glyph
|
||||
#define RENDER_GLYPH_ARRAY_INIT RENDER_GLYPH_ARRAY_INIT_8,RENDER_GLYPH_ARRAY_INIT_8
|
||||
|
||||
static CTFontRef CopyFontWithSize(CTFontRef originalFont, CGFloat size) {
|
||||
CTFontDescriptorRef descriptor = NULL;
|
||||
CGFontRef cgFont = CTFontCopyGraphicsFont(originalFont, &descriptor);
|
||||
CTFontRef result = CTFontCreateWithGraphicsFont(cgFont, size, NULL, descriptor);
|
||||
if (cgFont) CFRelease(cgFont);
|
||||
if (descriptor) CFRelease(descriptor);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clears the canvas, strikes the glyph with CoreGraphics, and then
|
||||
* copies the struck pixels into the GlyphInfo image.
|
||||
@@ -686,7 +697,7 @@ CGGI_CreateImageForGlyph
|
||||
// Set actual font size from transformation matrix for color glyphs
|
||||
CGFloat fontSize = glyphDescriptor != &argb ? strike->fSize :
|
||||
sqrt(fabs(matrix.a * matrix.d - matrix.b * matrix.c));
|
||||
CTFontRef sizedFont = CTFontCreateCopyWithSymbolicTraits(font, fontSize, NULL, 0, 0);
|
||||
CTFontRef sizedFont = CopyFontWithSize(font, fontSize);
|
||||
|
||||
CGFloat normFactor = 1.0 / fontSize;
|
||||
CGAffineTransform normalizedMatrix = CGAffineTransformScale(matrix, normFactor, normFactor);
|
||||
@@ -738,6 +749,78 @@ 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 ---
|
||||
|
||||
@@ -752,6 +835,7 @@ CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
|
||||
const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
jlong glyphInfos[],
|
||||
const UnicodeScalarValue uniChars[],
|
||||
const CGGlyph glyphs[],
|
||||
const CFIndex len)
|
||||
{
|
||||
@@ -764,8 +848,13 @@ CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
|
||||
CFIndex i;
|
||||
for (i = 0; i < len; i++) {
|
||||
GlyphInfo *info = (GlyphInfo *)jlong_to_ptr(glyphInfos[i]);
|
||||
CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode->mainFontDescriptor,
|
||||
strike, (CTFontRef)strike->fAWTFont->fFont, isMojaveOrAbove);
|
||||
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);
|
||||
}
|
||||
#ifdef CGGI_DEBUG
|
||||
DUMP_GLYPHINFO(info);
|
||||
#endif
|
||||
@@ -800,7 +889,7 @@ static NSString *threadLocalLCDCanvasKey =
|
||||
static inline void
|
||||
CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
const CGGlyph glyphs[],
|
||||
const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
|
||||
const size_t maxWidth, const size_t maxHeight,
|
||||
const CFIndex len)
|
||||
{
|
||||
@@ -810,7 +899,8 @@ 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, glyphs, len);
|
||||
mode, glyphInfos, uniChars,
|
||||
glyphs, len);
|
||||
CGGI_FreeCanvas(tmpCanvas);
|
||||
|
||||
[tmpCanvas release];
|
||||
@@ -830,7 +920,7 @@ CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
|
||||
CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
|
||||
CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
|
||||
glyphInfos, glyphs, len);
|
||||
glyphInfos, uniChars, glyphs, len);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -846,7 +936,7 @@ CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
static inline void
|
||||
CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
const CGGlyph glyphs[],
|
||||
const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
|
||||
CGSize advances[], CGRect bboxes[], const CFIndex len)
|
||||
{
|
||||
AWTFont *font = strike->fAWTFont;
|
||||
@@ -861,6 +951,12 @@ 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];
|
||||
|
||||
@@ -877,29 +973,41 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
glyphInfos[i] = ptr_to_jlong(glyphInfo);
|
||||
}
|
||||
|
||||
CGGI_FillImagesForGlyphs(glyphInfos, strike, mode,
|
||||
CGGI_FillImagesForGlyphs(glyphInfos, strike, mode, uniChars,
|
||||
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_CreateGlyphs(jlong *glyphInfos,
|
||||
const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
jint rawGlyphCodes[],
|
||||
CGGlyph glyphs[],
|
||||
CGSize advances[], CGRect bboxes[],
|
||||
const CFIndex len)
|
||||
CGGI_CreateGlyphsAndScanForComplexities(jlong *glyphInfos,
|
||||
const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
jint rawGlyphCodes[],
|
||||
UnicodeScalarValue uniChars[], CGGlyph glyphs[],
|
||||
CGSize advances[], CGRect bboxes[],
|
||||
const CFIndex len)
|
||||
{
|
||||
CFIndex i;
|
||||
for (i = 0; i < len; i++) {
|
||||
glyphs[i] = rawGlyphCodes[i];
|
||||
jint code = rawGlyphCodes[i];
|
||||
if (code < 0) {
|
||||
glyphs[i] = 0;
|
||||
uniChars[i] = -code;
|
||||
} else {
|
||||
glyphs[i] = code;
|
||||
uniChars[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
CGGI_CreateGlyphInfos(glyphInfos, strike, mode,
|
||||
glyphs, advances, bboxes, len);
|
||||
uniChars, glyphs, advances, bboxes, len);
|
||||
|
||||
#ifdef CGGI_DEBUG_HIT_COUNT
|
||||
static size_t hitCount = 0;
|
||||
@@ -925,29 +1033,31 @@ CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
|
||||
CGRect bboxes[len];
|
||||
CGSize advances[len];
|
||||
CGGlyph glyphs[len];
|
||||
UnicodeScalarValue uniChars[len];
|
||||
|
||||
CGGI_CreateGlyphs(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, glyphs,
|
||||
advances, bboxes, len);
|
||||
CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, uniChars, 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)) *
|
||||
len);
|
||||
void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
|
||||
sizeof(CGGlyph) * sizeof(UnicodeScalarValue) * 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 + len);
|
||||
CGGlyph *glyphs = (CGGlyph *)(advances + len);
|
||||
CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
|
||||
CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
|
||||
UnicodeScalarValue *uniChars = (UnicodeScalarValue *)(glyphs + sizeof(UnicodeScalarValue) * len);
|
||||
|
||||
CGGI_CreateGlyphs(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, glyphs,
|
||||
advances, bboxes, len);
|
||||
CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, uniChars, glyphs,
|
||||
advances, bboxes, len);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
@@ -971,7 +1081,7 @@ CGGlyphImages_GetGlyphMetrics(const CTFontRef font,
|
||||
// The logic here must match the logic in CGGI_CreateImageForGlyph,
|
||||
// which performs glyph drawing.
|
||||
|
||||
CTFontRef sizedFont = CTFontCreateCopyWithSymbolicTraits(font, fontSize, NULL, 0, 0);
|
||||
CTFontRef sizedFont = CopyFontWithSize(font, fontSize);
|
||||
|
||||
if (bboxes) {
|
||||
// JRSFontGetBoundingBoxesForGlyphsAndStyle works incorrectly for AppleColorEmoji font:
|
||||
|
||||
@@ -31,13 +31,37 @@
|
||||
|
||||
#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.
|
||||
* 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.
|
||||
*/
|
||||
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,18 +88,161 @@ 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.
|
||||
* 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.
|
||||
*/
|
||||
void CTS_GetGlyphsAsIntsForCharacters
|
||||
(const AWTFont *font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[], const size_t count)
|
||||
{
|
||||
CTFontGetGlyphsForCharacters((CTFontRef)font->fFont, unicodes, glyphs, count);
|
||||
GetFontsAndGlyphsForCharacters((CTFontRef)font->fFont, (CTFontRef)font->fFallbackBase,
|
||||
unicodes, glyphs, glyphsAsInts, NULL, count);
|
||||
}
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
glyphsAsInts[i] = glyphs[i];
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -127,6 +127,13 @@ do { \
|
||||
__attribute__((visibility("default")))
|
||||
@interface ThreadUtilities : NSObject { } /* Extend NSObject so can call performSelectorOnMainThread */
|
||||
|
||||
/*
|
||||
* When a blocking performSelectorOnMainThread is executed from the EventDispatch thread,
|
||||
* and the executed code triggers an opposite blocking a11y call (via LWCToolkit.invokeAndWait)
|
||||
* this is a deadlock case, and then this property is used to discard LWCToolkit.invokeAndWait.
|
||||
*/
|
||||
@property (class, nonatomic, readonly) BOOL blockingEventDispatchThread;
|
||||
|
||||
+ (JNIEnv*)getJNIEnv;
|
||||
+ (JNIEnv*)getJNIEnvUncached;
|
||||
+ (void)detachCurrentThread;
|
||||
|
||||
@@ -50,6 +50,24 @@ static inline void attachCurrentThread(void** env) {
|
||||
|
||||
@implementation ThreadUtilities
|
||||
|
||||
static BOOL _blockingEventDispatchThread = NO;
|
||||
static long eventDispatchThreadPtr = (long)nil;
|
||||
|
||||
static BOOL isEventDispatchThread() {
|
||||
return (long)[NSThread currentThread] == eventDispatchThreadPtr;
|
||||
}
|
||||
|
||||
// The [blockingEventDispatchThread] property is readonly, so we implement a private setter
|
||||
static void setBlockingEventDispatchThread(BOOL value) {
|
||||
assert([NSThread isMainThread]);
|
||||
_blockingEventDispatchThread = value;
|
||||
}
|
||||
|
||||
+ (BOOL) blockingEventDispatchThread {
|
||||
assert([NSThread isMainThread]);
|
||||
return _blockingEventDispatchThread;
|
||||
}
|
||||
|
||||
+ (void)initialize {
|
||||
/* All the standard modes plus ours */
|
||||
javaModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode,
|
||||
@@ -81,13 +99,6 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
appkitThreadGroup = group;
|
||||
}
|
||||
|
||||
/* This is needed because we can't directly pass a block to
|
||||
* performSelectorOnMainThreadWaiting .. since it expects a selector
|
||||
*/
|
||||
+ (void)invokeBlock:(void (^)())block {
|
||||
block();
|
||||
}
|
||||
|
||||
/*
|
||||
* When running a block where either we don't wait, or it needs to run on another thread
|
||||
* we need to copy it from stack to heap, use the copy in the call and release after use.
|
||||
@@ -103,12 +114,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
if ([NSThread isMainThread] && wait == YES) {
|
||||
block();
|
||||
} else {
|
||||
if (wait == YES) {
|
||||
[self performOnMainThread:@selector(invokeBlock:) on:self withObject:block waitUntilDone:YES];
|
||||
} else {
|
||||
void (^blockCopy)(void) = Block_copy(block);
|
||||
[self performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:blockCopy waitUntilDone:NO];
|
||||
}
|
||||
[self performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block) waitUntilDone:wait];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +122,19 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
if ([NSThread isMainThread] && wait == YES) {
|
||||
[target performSelector:aSelector withObject:arg];
|
||||
} else {
|
||||
[target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait modes:javaModes];
|
||||
if (wait && isEventDispatchThread()) {
|
||||
void (^blockCopy)(void) = Block_copy(^(){
|
||||
setBlockingEventDispatchThread(YES);
|
||||
@try {
|
||||
[target performSelector:aSelector withObject:arg];
|
||||
} @finally {
|
||||
setBlockingEventDispatchThread(NO);
|
||||
}
|
||||
});
|
||||
[self performSelectorOnMainThread:@selector(invokeBlockCopy:) withObject:blockCopy waitUntilDone:YES modes:javaModes];
|
||||
} else {
|
||||
[target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait modes:javaModes];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,3 +161,16 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_CThreading_isMainThread
|
||||
return [NSThread isMainThread];
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_awt_AWTThreading
|
||||
* Method: notifyEventDispatchThreadStartedNative
|
||||
* Signature: ()V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_awt_AWTThreading_notifyEventDispatchThreadStartedNative
|
||||
(JNIEnv *env, jclass c)
|
||||
{
|
||||
@synchronized([ThreadUtilities class]) {
|
||||
eventDispatchThreadPtr = (long)[NSThread currentThread];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import java.awt.event.WindowEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import sun.awt.AWTThreading;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
import sun.awt.dnd.SunDragSourceContextPeer;
|
||||
@@ -86,6 +87,7 @@ class EventDispatchThread extends Thread {
|
||||
}
|
||||
|
||||
public void run() {
|
||||
AWTThreading.getInstance(Thread.currentThread()).notifyEventDispatchThreadStarted();
|
||||
try {
|
||||
pumpEvents(new Conditional() {
|
||||
public boolean evaluate() {
|
||||
@@ -97,6 +99,8 @@ class EventDispatchThread extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
private static native void registerEventDispatchThread();
|
||||
|
||||
void pumpEvents(Conditional cond) {
|
||||
pumpEvents(ANY_EVENT, cond);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,6 @@ 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;
|
||||
@@ -267,11 +266,6 @@ 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;
|
||||
}
|
||||
@@ -549,11 +543,6 @@ 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.
|
||||
@@ -2252,7 +2241,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public boolean canDisplay(char c){
|
||||
return getFont2DWithSubstitution().canDisplay(c);
|
||||
return getFont2D().canDisplay(c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2273,7 +2262,7 @@ public class Font implements java.io.Serializable
|
||||
throw new IllegalArgumentException("invalid code point: " +
|
||||
Integer.toHexString(codePoint));
|
||||
}
|
||||
return getFont2DWithSubstitution().canDisplay(codePoint);
|
||||
return getFont2D().canDisplay(codePoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2294,7 +2283,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public int canDisplayUpTo(String str) {
|
||||
Font2D font2d = getFont2DWithSubstitution();
|
||||
Font2D font2d = getFont2D();
|
||||
int len = str.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = str.charAt(i);
|
||||
@@ -2332,7 +2321,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public int canDisplayUpTo(char[] text, int start, int limit) {
|
||||
Font2D font2d = getFont2DWithSubstitution();
|
||||
Font2D font2d = getFont2D();
|
||||
for (int i = start; i < limit; i++) {
|
||||
char c = text[i];
|
||||
if (font2d.canDisplay(c)) {
|
||||
@@ -2367,7 +2356,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
|
||||
Font2D font2d = getFont2DWithSubstitution();
|
||||
Font2D font2d = getFont2D();
|
||||
char c = iter.setIndex(start);
|
||||
for (int i = start; i < limit; i++, c = iter.next()) {
|
||||
if (font2d.canDisplay(c)) {
|
||||
|
||||
@@ -5,6 +5,8 @@ import sun.util.logging.PlatformLogger;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.InvocationEvent;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
@@ -14,6 +16,7 @@ import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* Used to perform a cross threads (EventDispatch, Toolkit) execution so that the execution does not cause a deadlock.
|
||||
@@ -75,14 +78,25 @@ public class AWTThreading {
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #executeWaitToolkit(Callable)}, but without returning a value. If requested (as indicated by
|
||||
* the passed parameter), the invoked native method is supposed to wait for the result of invocation on AppKit
|
||||
* thread, and vice versa.
|
||||
* A boolean value passed to the consumer indicates whether the consumer should perform
|
||||
* a synchronous invocation on the Toolkit thread and wait, or return immediately.
|
||||
*
|
||||
* @see #executeWaitToolkit(Callable).
|
||||
*/
|
||||
public static void executeWaitToolkit(Task runnable) {
|
||||
public static void executeWaitToolkit(Consumer<Boolean> consumer) {
|
||||
boolean wait = EventQueue.isDispatchThread();
|
||||
executeWaitToolkit(() -> {
|
||||
runnable.run(wait);
|
||||
consumer.accept(wait);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #executeWaitToolkit(Callable).
|
||||
*/
|
||||
public static void executeWaitToolkit(Runnable runnable) {
|
||||
executeWaitToolkit(() -> {
|
||||
runnable.run();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
@@ -102,12 +116,6 @@ public class AWTThreading {
|
||||
}
|
||||
}
|
||||
|
||||
if (!isEDT && logger.isLoggable(PlatformLogger.Level.FINE)) {
|
||||
// this can cause deadlock if calling thread is holding a lock which EDT might require (e.g. AWT tree lock)
|
||||
logger.fine("AWTThreading.executeWaitToolkit invoked from non-EDT thread", new Throwable());
|
||||
}
|
||||
|
||||
// fallback to default
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
@@ -246,8 +254,8 @@ public class AWTThreading {
|
||||
private final Throwable throwable = new Throwable();
|
||||
private final CompletableFuture<Void> futureResult = new CompletableFuture<>();
|
||||
|
||||
// dispatched or disposed
|
||||
private final AtomicBoolean isFinished = new AtomicBoolean(false);
|
||||
// dispatch or dispose has been started or already completed
|
||||
private final AtomicBoolean isCompletionStarted = new AtomicBoolean(false);
|
||||
|
||||
static TrackedInvocationEvent create(Object source,
|
||||
Runnable onDispatch,
|
||||
@@ -265,7 +273,7 @@ public class AWTThreading {
|
||||
TrackedInvocationEvent thisEvent = eventRef.get();
|
||||
if (!thisEvent.isDispatched()) {
|
||||
// If we're here - this {onDone} is being disposed.
|
||||
thisEvent.finishIfNotYet(() ->
|
||||
thisEvent.completeIfNotYet(() ->
|
||||
// If we're here - this {onDone} is called by the outer AWTAccessor.getInvocationEventAccessor().dispose()
|
||||
// which we do not control, so complete here.
|
||||
thisEvent.futureResult.completeExceptionally(new Throwable("InvocationEvent was disposed"))
|
||||
@@ -298,28 +306,42 @@ public class AWTThreading {
|
||||
|
||||
@Override
|
||||
public void dispatch() {
|
||||
finishIfNotYet(super::dispatch);
|
||||
futureResult.complete(null);
|
||||
// Should not complete if competion has already started.
|
||||
if (completeIfNotYet(super::dispatch)) {
|
||||
futureResult.complete(null);
|
||||
}
|
||||
}
|
||||
|
||||
public void dispose(String reason) {
|
||||
finishIfNotYet(() -> AWTAccessor.getInvocationEventAccessor().dispose(this));
|
||||
completeIfNotYet(() -> AWTAccessor.getInvocationEventAccessor().dispose(this));
|
||||
// Should complete exceptionally regardless of whether completetion has alredy started or hasn't.
|
||||
futureResult.completeExceptionally(new Throwable(reason));
|
||||
}
|
||||
|
||||
private void finishIfNotYet(Runnable finish) {
|
||||
if (!isFinished.getAndSet(true)) {
|
||||
finish.run();
|
||||
private boolean completeIfNotYet(Runnable competeRunnable) {
|
||||
if (!isCompletionStarted.getAndSet(true)) {
|
||||
competeRunnable.run();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the event is dispatched or disposed.
|
||||
*/
|
||||
public boolean isDone() {
|
||||
public boolean isCompleted() {
|
||||
return futureResult.isDone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the event is dispatched or disposed.
|
||||
* If {@code isCompletionInProgress} is true then also checks whether the event
|
||||
* dispatching or disposal is in progress and if so returns true.
|
||||
*/
|
||||
public boolean isCompleted(boolean isCompletionInProgress) {
|
||||
return isCompleted() || (isCompletionInProgress && isCompletionStarted.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the runnable when it's done (immediately if it's done).
|
||||
*/
|
||||
@@ -357,6 +379,19 @@ public class AWTThreading {
|
||||
return eventDispatchThread;
|
||||
}
|
||||
|
||||
public StringWriter printEventDispatchThreadStackTrace() {
|
||||
return printEventDispatchThreadStackTrace(new StringWriter());
|
||||
}
|
||||
|
||||
public StringWriter printEventDispatchThreadStackTrace(StringWriter writer) {
|
||||
assert writer != null;
|
||||
var printer = new PrintWriter(writer);
|
||||
Thread dispatchThread = getEventDispatchThread();
|
||||
printer.println(dispatchThread.getName());
|
||||
Arrays.asList(dispatchThread.getStackTrace()).forEach(frame -> printer.append("\tat ").println(frame));
|
||||
return writer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets {@code AWTThreading} instance factory.
|
||||
* WARNING: for testing purpose.
|
||||
@@ -365,6 +400,15 @@ public class AWTThreading {
|
||||
theAWTThreadingFactory.set(factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called on the EventDispatch thread.
|
||||
*/
|
||||
public void notifyEventDispatchThreadStarted() {
|
||||
if (FontUtilities.isMacOSX) notifyEventDispatchThreadStartedNative();
|
||||
}
|
||||
|
||||
private static native void notifyEventDispatchThreadStartedNative();
|
||||
|
||||
public void notifyEventDispatchThreadFree() {
|
||||
List<CompletableFuture<Void>> notifiers = Collections.emptyList();
|
||||
synchronized (eventDispatchThreadStateNotifiers) {
|
||||
@@ -413,8 +457,4 @@ public class AWTThreading {
|
||||
future.complete(null);
|
||||
return future;
|
||||
}
|
||||
|
||||
public interface Task {
|
||||
void run(boolean wait);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 final class CompositeFont extends Font2D {
|
||||
public class CompositeFont extends Font2D {
|
||||
|
||||
private boolean[] deferredInitialisation;
|
||||
String[] componentFileNames;
|
||||
|
||||
@@ -108,7 +108,7 @@ public class CompositeGlyphMapper extends CharToGlyphMapper {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
private int convertToGlyph(int unicode) {
|
||||
protected 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);
|
||||
}
|
||||
|
||||
private FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
|
||||
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,7 +43,6 @@ 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 setWithFallback(Font f);
|
||||
public abstract boolean isCreatedFont(Font f);
|
||||
|
||||
@@ -356,7 +356,7 @@ public final class FontDesignMetrics extends FontMetrics {
|
||||
|
||||
private void initMatrixAndMetrics() {
|
||||
|
||||
Font2D font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
Font2D font2D = FontUtilities.getFont2D(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).createItalicVariant();
|
||||
italic = ((FontWithDerivedItalic)plain).createItalic();
|
||||
}
|
||||
if (bolditalic == null) {
|
||||
Font2D boldItalicPrototype = bold != null ? bold : plain;
|
||||
if (boldItalicPrototype instanceof FontWithDerivedItalic) {
|
||||
bolditalic = ((FontWithDerivedItalic)boldItalicPrototype).createItalicVariant();
|
||||
bolditalic = ((FontWithDerivedItalic)boldItalicPrototype).createItalic();
|
||||
}
|
||||
}
|
||||
fontSequence.clear();
|
||||
|
||||
@@ -168,10 +168,6 @@ 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 createItalicVariant();
|
||||
Font2D createItalic();
|
||||
}
|
||||
@@ -400,7 +400,10 @@ public final class GlyphLayout {
|
||||
|
||||
int lang = -1; // default for now
|
||||
|
||||
Font2D font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
Font2D font2D = FontUtilities.getFont2D(font);
|
||||
if (font2D instanceof FontSubstitution) {
|
||||
font2D = ((FontSubstitution)font2D).getCompositeFont2D();
|
||||
}
|
||||
|
||||
_textRecord.init(text, offset, lim, min, max);
|
||||
int start = offset;
|
||||
|
||||
@@ -197,7 +197,8 @@ 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
|
||||
FontStrike strike = font2D.getStrike(font, frc);
|
||||
Font2D f2d = FontUtilities.getFont2D(font);
|
||||
FontStrike strike = f2d.getStrike(font, frc);
|
||||
|
||||
float[] deltas = { trackPt.x, trackPt.y };
|
||||
for (int j = 0; j < deltas.length; ++j) {
|
||||
@@ -1105,7 +1106,10 @@ public class StandardGlyphVector extends GlyphVector {
|
||||
}
|
||||
|
||||
private void initFontData() {
|
||||
font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
font2D = FontUtilities.getFont2D(font);
|
||||
if (font2D instanceof FontSubstitution) {
|
||||
font2D = ((FontSubstitution)font2D).getCompositeFont2D();
|
||||
}
|
||||
float s = font.getSize2D();
|
||||
if (font.isTransformed()) {
|
||||
ftx = font.getTransform();
|
||||
@@ -1724,7 +1728,12 @@ 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.
|
||||
FontStrike strike = sgv.font2D.handle.font2D.getStrike(desc); // !!! getStrike(desc, false)
|
||||
// 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)
|
||||
|
||||
return new GlyphStrike(sgv, strike, dx, dy);
|
||||
}
|
||||
|
||||
@@ -351,10 +351,25 @@ public abstract class SunFontManager implements FontSupport, FontManagerForSGE {
|
||||
jreFamilyMap.put("Roboto-Light", "Roboto Light");
|
||||
jreFamilyMap.put("Roboto-Thin", "Roboto Thin");
|
||||
|
||||
jreFontMap.put("JetBrainsMono-Bold.ttf", new BundledFontInfo("JetBrainsMono-Bold", 1, 0, 2));
|
||||
jreFontMap.put("JetBrainsMono-Regular.ttf", new BundledFontInfo("JetBrainsMono-Regular", 1, 0, 2));
|
||||
jreFontMap.put("JetBrainsMono-Italic.ttf", new BundledFontInfo("JetBrainsMono-Italic", 1, 0, 2));
|
||||
jreFontMap.put("JetBrainsMono-Bold-Italic.ttf", new BundledFontInfo("JetBrainsMono-BoldItalic", 1, 0, 2));
|
||||
jreFontMap.put("JetBrainsMono-Bold.ttf", new BundledFontInfo("JetBrainsMono-Bold", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-BoldItalic.ttf", new BundledFontInfo("JetBrainsMono-BoldItalic", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-ExtraBold.ttf", new BundledFontInfo("JetBrainsMono-ExtraBold", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-ExtraBoldItalic.ttf", new BundledFontInfo("JetBrainsMono-ExtraBoldItalic", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-ExtraLight.ttf", new BundledFontInfo("JetBrainsMono-ExtraLight", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-ExtraLightItalic.ttf", new BundledFontInfo("JetBrainsMono-ExtraLightItalic", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-Italic.ttf", new BundledFontInfo("JetBrainsMono-Italic", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-Light.ttf", new BundledFontInfo("JetBrainsMono-Light", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-LightItalic.ttf", new BundledFontInfo("JetBrainsMono-LightItalic", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-Medium.ttf", new BundledFontInfo("JetBrainsMono-Medium", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-MediumItalic.ttf", new BundledFontInfo("JetBrainsMono-MediumItalic", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-Regular.ttf", new BundledFontInfo("JetBrainsMono-Regular", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-Thin.ttf", new BundledFontInfo("JetBrainsMono-Thin", 2, 225, 0));
|
||||
jreFontMap.put("JetBrainsMono-ThinItalic.ttf", new BundledFontInfo("JetBrainsMono-ThinItalic", 2, 225, 0));
|
||||
|
||||
jreFontMap.put("Inter-Bold.otf", new BundledFontInfo("Inter-Bold", 3, 19, 0));
|
||||
jreFontMap.put("Inter-Regular.otf", new BundledFontInfo("Inter-Regular", 3, 19, 0));
|
||||
jreFontMap.put("Inter-Italic.otf", new BundledFontInfo("Inter-Italic", 3, 19, 0));
|
||||
jreFontMap.put("Inter-BoldItalic.otf", new BundledFontInfo("Inter-BoldItalic", 3, 19, 0));
|
||||
|
||||
jreBundledFontFiles.addAll(jreFontMap.keySet());
|
||||
}
|
||||
|
||||
@@ -670,7 +670,7 @@ public final class SunGraphics2D
|
||||
info.nonInvertibleTx =
|
||||
(Math.abs(textAt.getDeterminant()) <= Double.MIN_VALUE);
|
||||
|
||||
info.font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
info.font2D = FontUtilities.getFont2D(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.getFont2DWithSubstitution(font);
|
||||
Font2D font2D = FontUtilities.getFont2D(font);
|
||||
if (font2D.handle.font2D != font2D) {
|
||||
/* suspicious, may be a bad font. lets bail */
|
||||
return false;
|
||||
|
||||
BIN
src/java.desktop/share/fonts/Inter-Bold.otf
Normal file
BIN
src/java.desktop/share/fonts/Inter-Bold.otf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/Inter-BoldItalic.otf
Normal file
BIN
src/java.desktop/share/fonts/Inter-BoldItalic.otf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/Inter-Italic.otf
Normal file
BIN
src/java.desktop/share/fonts/Inter-Italic.otf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/Inter-Regular.otf
Normal file
BIN
src/java.desktop/share/fonts/Inter-Regular.otf
Normal file
Binary file not shown.
94
src/java.desktop/share/fonts/Inter_LICENSE.txt
Normal file
94
src/java.desktop/share/fonts/Inter_LICENSE.txt
Normal file
@@ -0,0 +1,94 @@
|
||||
Copyright (c) 2016-2020 The Inter Project Authors.
|
||||
"Inter" is trademark of Rasmus Andersson.
|
||||
https://github.com/rsms/inter
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION AND CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Binary file not shown.
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-BoldItalic.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-ExtraBold.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-ExtraBold.ttf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-ExtraBoldItalic.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-ExtraBoldItalic.ttf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-ExtraLight.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-ExtraLight.ttf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-ExtraLightItalic.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-ExtraLightItalic.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-Light.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Light.ttf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-LightItalic.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-LightItalic.ttf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-Medium.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-Medium.ttf
Normal file
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-MediumItalic.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-MediumItalic.ttf
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
src/java.desktop/share/fonts/JetBrainsMono-ThinItalic.ttf
Normal file
BIN
src/java.desktop/share/fonts/JetBrainsMono-ThinItalic.ttf
Normal file
Binary file not shown.
@@ -1643,7 +1643,6 @@ static jlong
|
||||
int error, imageSize;
|
||||
UInt16 width, height, rowBytes;
|
||||
GlyphInfo *glyphInfo;
|
||||
int target;
|
||||
FT_GlyphSlot ftglyph;
|
||||
FT_Library library;
|
||||
|
||||
@@ -1720,21 +1719,7 @@ static jlong
|
||||
and apply it explicitly after hinting is performed.
|
||||
Or we can disable hinting. */
|
||||
|
||||
/* select appropriate hinting mode */
|
||||
if (context->aaType == TEXT_AA_ON || context->colorFont) {
|
||||
target = FT_LOAD_TARGET_NORMAL;
|
||||
} else if (context->aaType == TEXT_AA_OFF) {
|
||||
target = FT_LOAD_TARGET_MONO;
|
||||
} else if (context->aaType == TEXT_AA_LCD_HRGB ||
|
||||
context->aaType == TEXT_AA_LCD_HBGR) {
|
||||
target = FT_LOAD_TARGET_LCD;
|
||||
} else {
|
||||
target = FT_LOAD_TARGET_LCD_V;
|
||||
}
|
||||
context->loadFlags |= target;
|
||||
|
||||
error = FT_Load_Glyph(scalerInfo->face, glyphCode, context->loadFlags);
|
||||
if (error) {
|
||||
if (FT_Load_Glyph(scalerInfo->face, glyphCode, context->loadFlags)) {
|
||||
//do not destroy scaler yet.
|
||||
//this can be problem of particular context (e.g. with bad transform)
|
||||
return ptr_to_jlong(getNullGlyphImage());
|
||||
@@ -2078,6 +2063,7 @@ Java_sun_font_FreetypeFontScaler_getGlyphCodeNative(
|
||||
static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D,
|
||||
FTScalerContext *context, FTScalerInfo* scalerInfo,
|
||||
jint glyphCode, jfloat xpos, jfloat ypos) {
|
||||
|
||||
FT_Error error;
|
||||
FT_GlyphSlot ftglyph;
|
||||
FT_Int32 loadFlags;
|
||||
@@ -2093,7 +2079,7 @@ static FT_Outline* getFTOutline(JNIEnv* env, jobject font2D,
|
||||
}
|
||||
|
||||
// We cannot get an outline from bitmap version of glyph
|
||||
loadFlags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP;
|
||||
loadFlags = context->loadFlags | FT_LOAD_NO_BITMAP;
|
||||
|
||||
error = FT_Load_Glyph(scalerInfo->face, glyphCode, loadFlags);
|
||||
if (error) {
|
||||
|
||||
@@ -65,6 +65,8 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
|
||||
static final boolean ENABLE_REPARENTING_CHECK
|
||||
= "true".equals(GetPropertyAction.privilegedGetProperty("reparenting.check"));
|
||||
private static final boolean ENABLE_DESKTOP_CHECK
|
||||
= "true".equals(GetPropertyAction.privilegedGetProperty("transients.desktop.check", "true"));
|
||||
|
||||
// should be synchronized on awtLock
|
||||
private static Set<XWindowPeer> windows = new HashSet<XWindowPeer>();
|
||||
@@ -95,6 +97,9 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
|
||||
private static final AtomicBoolean isStartupNotificationRemoved = new AtomicBoolean();
|
||||
|
||||
private Long desktopId; // guarded by AWT lock
|
||||
private boolean desktopIdInvalid; // guarded by AWT lock
|
||||
|
||||
/*
|
||||
* Focus related flags
|
||||
*/
|
||||
@@ -159,6 +164,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
params.put(EVENT_MASK, eventMask);
|
||||
|
||||
XA_NET_WM_STATE = XAtom.get("_NET_WM_STATE");
|
||||
XA_NET_WM_DESKTOP = XAtom.get("_NET_WM_DESKTOP");
|
||||
|
||||
|
||||
params.put(OVERRIDE_REDIRECT, Boolean.valueOf(isOverrideRedirect()));
|
||||
@@ -1730,7 +1736,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
if (!allStates && (window.getWMState() != transientForWindow.getWMState())) {
|
||||
return;
|
||||
}
|
||||
if (window.getScreenNumber() != transientForWindow.getScreenNumber()) {
|
||||
if (screenOrDesktopDiffers(window, transientForWindow)) {
|
||||
return;
|
||||
}
|
||||
long bpw = window.getWindow();
|
||||
@@ -1767,7 +1773,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
void updateTransientFor() {
|
||||
int state = getWMState();
|
||||
XWindowPeer p = prevTransientFor;
|
||||
while ((p != null) && ((p.getWMState() != state) || (p.getScreenNumber() != getScreenNumber()))) {
|
||||
while ((p != null) && ((p.getWMState() != state) || screenOrDesktopDiffers(p, this))) {
|
||||
p = p.prevTransientFor;
|
||||
}
|
||||
if (p != null) {
|
||||
@@ -1776,7 +1782,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
restoreTransientFor(this);
|
||||
}
|
||||
XWindowPeer n = nextTransientFor;
|
||||
while ((n != null) && ((n.getWMState() != state) || (n.getScreenNumber() != getScreenNumber()))) {
|
||||
while ((n != null) && ((n.getWMState() != state) || screenOrDesktopDiffers(n, this))) {
|
||||
n = n.nextTransientFor;
|
||||
}
|
||||
if (n != null) {
|
||||
@@ -1784,6 +1790,43 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
}
|
||||
}
|
||||
|
||||
private Long getDesktopId() {
|
||||
XToolkit.awtLock();
|
||||
try {
|
||||
if (desktopIdInvalid) {
|
||||
desktopIdInvalid = false;
|
||||
desktopId = null;
|
||||
WindowPropertyGetter getter =
|
||||
new WindowPropertyGetter(window, XA_NET_WM_DESKTOP, 0, 1, false, XAtom.XA_CARDINAL);
|
||||
try {
|
||||
if (getter.execute() == XConstants.Success &&
|
||||
getter.getActualType() == XAtom.XA_CARDINAL &&
|
||||
getter.getActualFormat() == 32) {
|
||||
long ptr = getter.getData();
|
||||
if (ptr != 0) {
|
||||
desktopId = Native.getCard32(ptr);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
getter.dispose();
|
||||
}
|
||||
}
|
||||
return desktopId;
|
||||
} finally {
|
||||
XToolkit.awtUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean screenOrDesktopDiffers(XWindowPeer p1, XWindowPeer p2) {
|
||||
if (p1.getScreenNumber() != p2.getScreenNumber()) return true;
|
||||
if (!ENABLE_DESKTOP_CHECK) return false;
|
||||
Long d1 = p1.getDesktopId();
|
||||
if (d1 == null) return false;
|
||||
Long d2 = p2.getDesktopId();
|
||||
if (d2 == null) return false;
|
||||
return !d1.equals(d2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes the TRANSIENT_FOR hint from the given top-level window.
|
||||
* If window or transientForWindow are embedded frames, the containing
|
||||
@@ -2163,6 +2206,7 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
cachedFocusableWindow = isFocusableWindow();
|
||||
}
|
||||
|
||||
XAtom XA_NET_WM_DESKTOP;
|
||||
XAtom XA_NET_WM_STATE;
|
||||
XAtomList net_wm_state;
|
||||
public XAtomList getNETWMState() {
|
||||
@@ -2179,6 +2223,18 @@ class XWindowPeer extends XPanelPeer implements WindowPeer,
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handlePropertyNotify(XEvent xev) {
|
||||
super.handlePropertyNotify(xev);
|
||||
XPropertyEvent ev = xev.get_xproperty();
|
||||
if (ev.get_atom() == XA_NET_WM_DESKTOP.getAtom()) {
|
||||
desktopIdInvalid = true;
|
||||
if (ENABLE_DESKTOP_CHECK) {
|
||||
updateTransientFor();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PropMwmHints getMWMHints() {
|
||||
if (mwm_hints == null) {
|
||||
mwm_hints = new PropMwmHints();
|
||||
|
||||
@@ -1457,6 +1457,7 @@ void X11SD_DisposeXImage(XImage * image) {
|
||||
#ifdef MITSHM
|
||||
if (image->obdata != NULL) {
|
||||
X11SD_DropSharedSegment((XShmSegmentInfo*)image->obdata);
|
||||
free(image->obdata);
|
||||
image->obdata = NULL;
|
||||
}
|
||||
#endif /* MITSHM */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user