diff --git a/.gitignore b/.gitignore index c34d27c8470..cf21c8919cd 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /dist/ /.idea/ /.vscode/ +/nbproject/ nbproject/private/ /webrev /.src-rev @@ -14,3 +15,4 @@ test/nashorn/lib NashornProfile.txt **/JTreport/** **/JTwork/** +/src/utils/LogCompilation/target/ diff --git a/doc/building.html b/doc/building.html index 8774e5562d6..318a24aa840 100644 --- a/doc/building.html +++ b/doc/building.html @@ -629,21 +629,30 @@

Creating And Using Sys

Fortunately, you can create sysroots for foreign architectures with tools provided by your OS. On Debian/Ubuntu systems, one could use qemu-deboostrap to create the target system chroot, which would have the native libraries and headers specific to that target system. After that, we can use the cross-compiler on the build system, pointing into chroot to get the build dependencies right. This allows building for foreign architectures with native compilation speed.

For example, cross-compiling to AArch64 from x86_64 could be done like this:

-
apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu
- -
sudo qemu-debootstrap --arch=arm64 --verbose \
-       --include=fakeroot,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng12-dev \
-       --resolve-deps jessie /chroots/arm64 http://httpredir.debian.org/debian/
- -
CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ sh ./configure --openjdk-target=aarch64-linux-gnu --with-sysroot=/chroots/arm64/ --with-toolchain-path=/chroots/arm64/
+
  • Install cross-compiler on the build system:

    +
    apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu
  • +
  • Create chroot on the build system, configuring it for target system:

    +
    sudo qemu-debootstrap \
    +  --arch=arm64 \
    +  --verbose \
    +  --include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng-dev \
    +  --resolve-deps \
    +  buster \
    +  ~/sysroot-arm64 \
    +  http://httpredir.debian.org/debian/
  • +
  • Make sure the symlinks inside the newly created chroot point to proper locations:

    +
    sudo chroot ~/sysroot-arm64 symlinks -cr .
  • +
  • Configure and build with newly created chroot as sysroot/toolchain-path:

    +
    CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ sh ./configure \
    + --openjdk-target=aarch64-linux-gnu \
    + --with-sysroot=~/sysroot-arm64 \
    + --with-toolchain-path=~/sysroot-arm64 \
    + --with-freetype-lib=~/sysroot-arm64/usr/lib/aarch64-linux-gnu/ \
    + --with-freetype-include=~/sysroot-arm64/usr/include/freetype2/ \
    + --x-libraries=~/sysroot-arm64/usr/lib/aarch64-linux-gnu/
     make images
    -ls build/linux-aarch64-normal-server-release/
    +ls build/linux-aarch64-server-release/
  • +

    The build does not create new files in that chroot, so it can be reused for multiple builds without additional cleanup.

    Architectures that are known to successfully cross-compile like this are:

    diff --git a/doc/building.md b/doc/building.md index fa6b0ae31b6..e0ac5c7b6c7 100644 --- a/doc/building.md +++ b/doc/building.md @@ -1086,23 +1086,39 @@ for foreign architectures with native compilation speed. For example, cross-compiling to AArch64 from x86_64 could be done like this: * Install cross-compiler on the *build* system: -``` -apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu -``` + ``` + apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu + ``` * Create chroot on the *build* system, configuring it for *target* system: -``` -sudo qemu-debootstrap --arch=arm64 --verbose \ - --include=fakeroot,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng12-dev \ - --resolve-deps jessie /chroots/arm64 http://httpredir.debian.org/debian/ -``` + ``` + sudo qemu-debootstrap \ + --arch=arm64 \ + --verbose \ + --include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng-dev \ + --resolve-deps \ + buster \ + ~/sysroot-arm64 \ + http://httpredir.debian.org/debian/ + ``` + + * Make sure the symlinks inside the newly created chroot point to proper locations: + ``` + sudo chroot ~/sysroot-arm64 symlinks -cr . + ``` * Configure and build with newly created chroot as sysroot/toolchain-path: -``` -CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ sh ./configure --openjdk-target=aarch64-linux-gnu --with-sysroot=/chroots/arm64/ --with-toolchain-path=/chroots/arm64/ -make images -ls build/linux-aarch64-normal-server-release/ -``` + ``` + CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ sh ./configure \ + --openjdk-target=aarch64-linux-gnu \ + --with-sysroot=~/sysroot-arm64 \ + --with-toolchain-path=~/sysroot-arm64 \ + --with-freetype-lib=~/sysroot-arm64/usr/lib/aarch64-linux-gnu/ \ + --with-freetype-include=~/sysroot-arm64/usr/include/freetype2/ \ + --x-libraries=~/sysroot-arm64/usr/lib/aarch64-linux-gnu/ + make images + ls build/linux-aarch64-server-release/ + ``` The build does not create new files in that chroot, so it can be reused for multiple builds without additional cleanup. diff --git a/make/data/tzdata/VERSION b/make/data/tzdata/VERSION index f5b7dba32a4..94ba7462f2e 100644 --- a/make/data/tzdata/VERSION +++ b/make/data/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2020c +tzdata2020d diff --git a/make/data/tzdata/asia b/make/data/tzdata/asia index f5336ef4c26..acca6554fa2 100644 --- a/make/data/tzdata/asia +++ b/make/data/tzdata/asia @@ -3244,13 +3244,40 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # From Sharef Mustafa (2019-10-18): # Palestine summer time will end on midnight Oct 26th 2019 ... -# http://www.palestinecabinet.gov.ps/website/ar/ViewDetails?ID=43948 # -# From Paul Eggert (2019-04-10): -# For now, guess spring-ahead transitions are March's last Friday at 00:00. +# From Steffen Thorsen (2020-10-20): +# Some sources such as these say, and display on clocks, that DST ended at +# midnight last year... +# https://www.amad.ps/ar/post/320006 +# +# From Tim Parenti (2020-10-20): +# The report of the Palestinian Cabinet meeting of 2019-10-14 confirms +# a decision on (translated): "The start of the winter time in Palestine, by +# delaying the clock by sixty minutes, starting from midnight on Friday / +# Saturday corresponding to 26/10/2019." +# http://www.palestinecabinet.gov.ps/portal/meeting/details/43948 + +# From Sharef Mustafa (2020-10-20): +# As per the palestinian cabinet announcement yesterday , the day light saving +# shall [end] on Oct 24th 2020 at 01:00AM by delaying the clock by 60 minutes. +# http://www.palestinecabinet.gov.ps/portal/Meeting/Details/51584 + +# From Tim Parenti (2020-10-20): +# Predict future fall transitions at 01:00 on the Saturday preceding October's +# last Sunday (i.e., Sat>=24). This is consistent with our predictions since +# 2016, although the time of the change differed slightly in 2019. + +# From Pierre Cashon (2020-10-20): +# The summer time this year started on March 28 at 00:00. +# https://wafa.ps/ar_page.aspx?id=GveQNZa872839351758aGveQNZ +# http://www.palestinecabinet.gov.ps/portal/meeting/details/50284 +# The winter time in 2015 started on October 23 at 01:00. +# https://wafa.ps/ar_page.aspx?id=CgpCdYa670694628582aCgpCdY +# http://www.palestinecabinet.gov.ps/portal/meeting/details/27583 # -# From Tim Parenti (2016-10-19): -# Predict fall transitions on October's last Saturday at 01:00 from now on. +# From Paul Eggert (2019-04-10): +# For now, guess spring-ahead transitions are at 00:00 on the Saturday +# preceding March's last Sunday (i.e., Sat>=24). # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule EgyptAsia 1957 only - May 10 0:00 1:00 S @@ -3266,10 +3293,10 @@ Rule Palestine 2004 only - Oct 1 1:00 0 - Rule Palestine 2005 only - Oct 4 2:00 0 - Rule Palestine 2006 2007 - Apr 1 0:00 1:00 S Rule Palestine 2006 only - Sep 22 0:00 0 - -Rule Palestine 2007 only - Sep Thu>=8 2:00 0 - +Rule Palestine 2007 only - Sep 13 2:00 0 - Rule Palestine 2008 2009 - Mar lastFri 0:00 1:00 S Rule Palestine 2008 only - Sep 1 0:00 0 - -Rule Palestine 2009 only - Sep Fri>=1 1:00 0 - +Rule Palestine 2009 only - Sep 4 1:00 0 - Rule Palestine 2010 only - Mar 26 0:00 1:00 S Rule Palestine 2010 only - Aug 11 0:00 0 - Rule Palestine 2011 only - Apr 1 0:01 1:00 S @@ -3278,12 +3305,16 @@ Rule Palestine 2011 only - Aug 30 0:00 1:00 S Rule Palestine 2011 only - Sep 30 0:00 0 - Rule Palestine 2012 2014 - Mar lastThu 24:00 1:00 S Rule Palestine 2012 only - Sep 21 1:00 0 - -Rule Palestine 2013 only - Sep Fri>=21 0:00 0 - -Rule Palestine 2014 2015 - Oct Fri>=21 0:00 0 - -Rule Palestine 2015 only - Mar lastFri 24:00 1:00 S +Rule Palestine 2013 only - Sep 27 0:00 0 - +Rule Palestine 2014 only - Oct 24 0:00 0 - +Rule Palestine 2015 only - Mar 28 0:00 1:00 S +Rule Palestine 2015 only - Oct 23 1:00 0 - Rule Palestine 2016 2018 - Mar Sat>=24 1:00 1:00 S -Rule Palestine 2016 max - Oct lastSat 1:00 0 - -Rule Palestine 2019 max - Mar lastFri 0:00 1:00 S +Rule Palestine 2016 2018 - Oct Sat>=24 1:00 0 - +Rule Palestine 2019 only - Mar 29 0:00 1:00 S +Rule Palestine 2019 only - Oct Sat>=24 0:00 0 - +Rule Palestine 2020 max - Mar Sat>=24 0:00 1:00 S +Rule Palestine 2020 max - Oct Sat>=24 1:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct diff --git a/make/data/tzdata/europe b/make/data/tzdata/europe index 2b0c7be51c3..adb260624dc 100644 --- a/make/data/tzdata/europe +++ b/make/data/tzdata/europe @@ -1052,17 +1052,16 @@ Zone Europe/Prague 0:57:44 - LMT 1850 # Denmark, Faroe Islands, and Greenland # From Jesper Nørgaard Welen (2005-04-26): -# http://www.hum.aau.dk/~poe/tid/tine/DanskTid.htm says that the law -# [introducing standard time] was in effect from 1894-01-01.... -# The page http://www.retsinfo.dk/_GETDOCI_/ACCN/A18930008330-REGL +# the law [introducing standard time] was in effect from 1894-01-01.... +# The page https://www.retsinformation.dk/eli/lta/1893/83 # confirms this, and states that the law was put forth 1893-03-29. # # The EU [actually, EEC and Euratom] treaty with effect from 1973: -# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19722110030-REGL +# https://www.retsinformation.dk/eli/lta/1972/21100 # # This provoked a new law from 1974 to make possible summer time changes # in subsequent decrees with the law -# http://www.retsinfo.dk/_GETDOCI_/ACCN/A19740022330-REGL +# https://www.retsinformation.dk/eli/lta/1974/223 # # It seems however that no decree was set forward until 1980. I have # not found any decree, but in another related law, the effecting DST @@ -1074,7 +1073,7 @@ Zone Europe/Prague 0:57:44 - LMT 1850 # The law is about the management of the extra hour, concerning # working hours reported and effect on obligatory-rest rules (which # was suspended on that night): -# http://www.retsinfo.dk/_GETDOCI_/ACCN/C19801120554-REGL +# https://web.archive.org/web/20140104053304/https://www.retsinformation.dk/Forms/R0710.aspx?id=60267 # From Jesper Nørgaard Welen (2005-06-11): # The Herning Folkeblad (1980-09-26) reported that the night between diff --git a/make/hotspot/gensrc/GensrcJvmti.gmk b/make/hotspot/gensrc/GensrcJvmti.gmk index 312c8bc737a..b31a6f52292 100644 --- a/make/hotspot/gensrc/GensrcJvmti.gmk +++ b/make/hotspot/gensrc/GensrcJvmti.gmk @@ -106,17 +106,6 @@ $(eval $(call SetupJvmtiGeneration, jvmti.h, jvmtiH.xsl, \ $(eval $(call SetupJvmtiGeneration, jvmti.html, jvmti.xsl, \ -PARAM majorversion $(VERSION_FEATURE))) -JVMTI_BC_SRCDIR := $(TOPDIR)/src/hotspot/share/interpreter/zero - -ifeq ($(call check-jvm-feature, zero), true) - $(eval $(call SetupXslTransform, bytecodeInterpreterWithChecks.cpp, \ - XML_FILE := $(JVMTI_BC_SRCDIR)/bytecodeInterpreterWithChecks.xml, \ - XSL_FILE := $(JVMTI_BC_SRCDIR)/bytecodeInterpreterWithChecks.xsl, \ - OUTPUT_DIR := $(JVMTI_OUTPUTDIR), \ - DEPS := $(JVMTI_BC_SRCDIR)/bytecodeInterpreter.cpp, \ - )) -endif - ################################################################################ # Copy jvmti.h to include dir diff --git a/make/hotspot/symbols/symbols-aix b/make/hotspot/symbols/symbols-aix index 0efd2dba97f..92703573a5f 100644 --- a/make/hotspot/symbols/symbols-aix +++ b/make/hotspot/symbols/symbols-aix @@ -21,7 +21,7 @@ # questions. # -JVM_handle_linux_signal +JVM_handle_aix_signal numa_error numa_warn sysThreadAvailableStackWithSlack diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk index 7fbd1049f89..3203378d00a 100644 --- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk +++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk @@ -435,7 +435,6 @@ endif ifeq ($(USE_EXTERNAL_HARFBUZZ), true) LIBHARFBUZZ_LIBS := $(HARFBUZZ_LIBS) else - HARFBUZZ_CFLAGS := -DHAVE_OT -DHAVE_FALLBACK -DHAVE_UCDN -DHAVE_ROUND # This is better than adding EXPORT_ALL_SYMBOLS ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), ) @@ -493,7 +492,7 @@ else maybe-uninitialized class-memaccess, \ DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \ tautological-constant-out-of-range-compare int-to-pointer-cast \ - undef missing-field-initializers, \ + undef missing-field-initializers range-loop-analysis, \ DISABLED_WARNINGS_microsoft := 4267 4244 4090 4146 4334 4819 4101 4068 4805 4138, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ diff --git a/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/CMMTests.java b/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/CMMTests.java index 210970f6469..3c0f936358c 100644 --- a/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/CMMTests.java +++ b/src/demo/share/java2d/J2DBench/src/j2dbench/tests/cmm/CMMTests.java @@ -73,14 +73,16 @@ public static void init() { ColorSpace.CS_sRGB, ColorSpace.CS_GRAY, ColorSpace.CS_LINEAR_RGB, - ColorSpace.CS_CIEXYZ + ColorSpace.CS_CIEXYZ, + ColorSpace.CS_PYCC }; String[] csNames = new String[]{ "CS_sRGB", "CS_GRAY", "CS_LINEAR_RGB", - "CS_CIEXYZ" + "CS_CIEXYZ", + "CS_PYCC" }; csList = new Option.IntList(cmmOptRoot, diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 961eb6a9c68..3ccaa0927d0 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -1753,7 +1753,9 @@ int MachCallDynamicJavaNode::ret_addr_offset() int MachCallRuntimeNode::ret_addr_offset() { // for generated stubs the call will be - // far_call(addr) + // bl(addr) + // or with far branches + // bl(trampoline_stub) // for real runtime callouts it will be six instructions // see aarch64_enc_java_to_runtime // adr(rscratch2, retaddr) @@ -1762,7 +1764,7 @@ int MachCallRuntimeNode::ret_addr_offset() { // blr(rscratch1) CodeBlob *cb = CodeCache::find_blob(_entry_point); if (cb) { - return MacroAssembler::far_branch_size(); + return 1 * NativeInstruction::instruction_size; } else { return 6 * NativeInstruction::instruction_size; } @@ -18957,6 +18959,216 @@ instruct vsrl2L_imm(vecX dst, vecX src, immI shift) %{ ins_pipe(vshift128_imm); %} +instruct vsraa8B_imm(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (AddVB dst (RShiftVB src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "ssra $dst, $src, $shift\t# vector (8B)" %} + ins_encode %{ + int sh = (int)$shift$$constant; + if (sh >= 8) sh = 7; + __ ssra(as_FloatRegister($dst$$reg), __ T8B, + as_FloatRegister($src$$reg), sh); + %} + ins_pipe(vshift64_imm); +%} + +instruct vsraa16B_imm(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 16); + match(Set dst (AddVB dst (RShiftVB src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "ssra $dst, $src, $shift\t# vector (16B)" %} + ins_encode %{ + int sh = (int)$shift$$constant; + if (sh >= 8) sh = 7; + __ ssra(as_FloatRegister($dst$$reg), __ T16B, + as_FloatRegister($src$$reg), sh); + %} + ins_pipe(vshift128_imm); +%} + +instruct vsraa4S_imm(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (AddVS dst (RShiftVS src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "ssra $dst, $src, $shift\t# vector (4H)" %} + ins_encode %{ + int sh = (int)$shift$$constant; + if (sh >= 16) sh = 15; + __ ssra(as_FloatRegister($dst$$reg), __ T4H, + as_FloatRegister($src$$reg), sh); + %} + ins_pipe(vshift64_imm); +%} + +instruct vsraa8S_imm(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (AddVS dst (RShiftVS src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "ssra $dst, $src, $shift\t# vector (8H)" %} + ins_encode %{ + int sh = (int)$shift$$constant; + if (sh >= 16) sh = 15; + __ ssra(as_FloatRegister($dst$$reg), __ T8H, + as_FloatRegister($src$$reg), sh); + %} + ins_pipe(vshift128_imm); +%} + +instruct vsraa2I_imm(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AddVI dst (RShiftVI src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "ssra $dst, $src, $shift\t# vector (2S)" %} + ins_encode %{ + __ ssra(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src$$reg), + (int)$shift$$constant); + %} + ins_pipe(vshift64_imm); +%} + +instruct vsraa4I_imm(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (AddVI dst (RShiftVI src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "ssra $dst, $src, $shift\t# vector (4S)" %} + ins_encode %{ + __ ssra(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src$$reg), + (int)$shift$$constant); + %} + ins_pipe(vshift128_imm); +%} + +instruct vsraa2L_imm(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AddVL dst (RShiftVL src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "ssra $dst, $src, $shift\t# vector (2D)" %} + ins_encode %{ + __ ssra(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg), + (int)$shift$$constant); + %} + ins_pipe(vshift128_imm); +%} + +instruct vsrla8B_imm(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (AddVB dst (URShiftVB src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "usra $dst, $src, $shift\t# vector (8B)" %} + ins_encode %{ + int sh = (int)$shift$$constant; + if (sh >= 8) { + __ eor(as_FloatRegister($src$$reg), __ T8B, + as_FloatRegister($src$$reg), + as_FloatRegister($src$$reg)); + } else { + __ usra(as_FloatRegister($dst$$reg), __ T8B, + as_FloatRegister($src$$reg), sh); + } + %} + ins_pipe(vshift64_imm); +%} + +instruct vsrla16B_imm(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 16); + match(Set dst (AddVB dst (URShiftVB src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "usra $dst, $src, $shift\t# vector (16B)" %} + ins_encode %{ + int sh = (int)$shift$$constant; + if (sh >= 8) { + __ eor(as_FloatRegister($src$$reg), __ T16B, + as_FloatRegister($src$$reg), + as_FloatRegister($src$$reg)); + } else { + __ usra(as_FloatRegister($dst$$reg), __ T16B, + as_FloatRegister($src$$reg), sh); + } + %} + ins_pipe(vshift128_imm); +%} + +instruct vsrla4S_imm(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (AddVS dst (URShiftVS src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "usra $dst, $src, $shift\t# vector (4H)" %} + ins_encode %{ + int sh = (int)$shift$$constant; + if (sh >= 16) { + __ eor(as_FloatRegister($src$$reg), __ T8B, + as_FloatRegister($src$$reg), + as_FloatRegister($src$$reg)); + } else { + __ ushr(as_FloatRegister($dst$$reg), __ T4H, + as_FloatRegister($src$$reg), sh); + } + %} + ins_pipe(vshift64_imm); +%} + +instruct vsrla8S_imm(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 8); + match(Set dst (AddVS dst (URShiftVS src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "usra $dst, $src, $shift\t# vector (8H)" %} + ins_encode %{ + int sh = (int)$shift$$constant; + if (sh >= 16) { + __ eor(as_FloatRegister($src$$reg), __ T16B, + as_FloatRegister($src$$reg), + as_FloatRegister($src$$reg)); + } else { + __ usra(as_FloatRegister($dst$$reg), __ T8H, + as_FloatRegister($src$$reg), sh); + } + %} + ins_pipe(vshift128_imm); +%} + +instruct vsrla2I_imm(vecD dst, vecD src, immI shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AddVI dst (URShiftVI src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "usra $dst, $src, $shift\t# vector (2S)" %} + ins_encode %{ + __ usra(as_FloatRegister($dst$$reg), __ T2S, + as_FloatRegister($src$$reg), + (int)$shift$$constant); + %} + ins_pipe(vshift64_imm); +%} + +instruct vsrla4I_imm(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 4); + match(Set dst (AddVI dst (URShiftVI src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "usra $dst, $src, $shift\t# vector (4S)" %} + ins_encode %{ + __ usra(as_FloatRegister($dst$$reg), __ T4S, + as_FloatRegister($src$$reg), + (int)$shift$$constant); + %} + ins_pipe(vshift128_imm); +%} + +instruct vsrla2L_imm(vecX dst, vecX src, immI shift) %{ + predicate(n->as_Vector()->length() == 2); + match(Set dst (AddVL dst (URShiftVL src (RShiftCntV shift)))); + ins_cost(INSN_COST); + format %{ "usra $dst, $src, $shift\t# vector (2D)" %} + ins_encode %{ + __ usra(as_FloatRegister($dst$$reg), __ T2D, + as_FloatRegister($src$$reg), + (int)$shift$$constant); + %} + ins_pipe(vshift128_imm); +%} + instruct vmax2F(vecD dst, vecD src1, vecD src2) %{ predicate(n->as_Vector()->length() == 2 && n->bottom_type()->is_vect()->element_basic_type() == T_FLOAT); diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index ba352461e4a..7ff9c018bef 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -2688,6 +2688,8 @@ void mvnw(Register Rd, Register Rm, INSN(shl, 0, 0b010101, /* isSHR = */ false); INSN(sshr, 0, 0b000001, /* isSHR = */ true); INSN(ushr, 1, 0b000001, /* isSHR = */ true); + INSN(usra, 1, 0b000101, /* isSHR = */ true); + INSN(ssra, 0, 0b000101, /* isSHAR =*/ true); #undef INSN @@ -3220,13 +3222,6 @@ void mvnw(Register Rd, Register Rm, Assembler(CodeBuffer* code) : AbstractAssembler(code) { } - virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset) { - ShouldNotCallThis(); - return RegisterOrConstant(); - } - // Stack overflow checking virtual void bang_stack_with_offset(int offset); diff --git a/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp index 4e4262d5d6d..d2520014ed1 100644 --- a/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_globals_aarch64.hpp @@ -34,8 +34,6 @@ #ifndef TIERED define_pd_global(bool, BackgroundCompilation, true ); -define_pd_global(bool, UseTLAB, true ); -define_pd_global(bool, ResizeTLAB, true ); define_pd_global(bool, InlineIntrinsics, true ); define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, false); diff --git a/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp b/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp index 973cbe740bd..5a019eba6ae 100644 --- a/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c2_globals_aarch64.hpp @@ -33,8 +33,6 @@ // (see c2_globals.hpp). Alpha-sorted. define_pd_global(bool, BackgroundCompilation, true); -define_pd_global(bool, UseTLAB, true); -define_pd_global(bool, ResizeTLAB, true); define_pd_global(bool, CICompileOSR, true); define_pd_global(bool, InlineIntrinsics, true); define_pd_global(bool, PreferInterpreterNativeStubs, false); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 1e5de08315e..fcd50f76f17 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -935,23 +935,6 @@ void MacroAssembler::check_and_handle_earlyret(Register java_thread) { } void MacroAssembler::check_and_handle_popframe(Register java_thread) { } - -RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset) { - intptr_t value = *delayed_value_addr; - if (value != 0) - return RegisterOrConstant(value + offset); - - // load indirectly to solve generation ordering problem - ldr(tmp, ExternalAddress((address) delayed_value_addr)); - - if (offset != 0) - add(tmp, tmp, offset); - - return RegisterOrConstant(tmp); -} - // Look up the method for a megamorphic invokeinterface call. // The target method is determined by . // The receiver klass is in recv_klass. diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index 351b4b143ef..609e763526b 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -1031,10 +1031,6 @@ class MacroAssembler: public Assembler { // Check for reserved stack access in method being exited (for JIT) void reserved_stack_check(); - virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset); - // Arithmetics void addptr(const Address &dst, int32_t src); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index b1e95074942..092a1d9242b 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -5418,6 +5418,150 @@ class StubGenerator: public StubCodeGenerator { return start; } + void generate_base64_encode_simdround(Register src, Register dst, + FloatRegister codec, u8 size) { + + FloatRegister in0 = v4, in1 = v5, in2 = v6; + FloatRegister out0 = v16, out1 = v17, out2 = v18, out3 = v19; + FloatRegister ind0 = v20, ind1 = v21, ind2 = v22, ind3 = v23; + + Assembler::SIMD_Arrangement arrangement = size == 16 ? __ T16B : __ T8B; + + __ ld3(in0, in1, in2, arrangement, __ post(src, 3 * size)); + + __ ushr(ind0, arrangement, in0, 2); + + __ ushr(ind1, arrangement, in1, 2); + __ shl(in0, arrangement, in0, 6); + __ orr(ind1, arrangement, ind1, in0); + __ ushr(ind1, arrangement, ind1, 2); + + __ ushr(ind2, arrangement, in2, 4); + __ shl(in1, arrangement, in1, 4); + __ orr(ind2, arrangement, in1, ind2); + __ ushr(ind2, arrangement, ind2, 2); + + __ shl(ind3, arrangement, in2, 2); + __ ushr(ind3, arrangement, ind3, 2); + + __ tbl(out0, arrangement, codec, 4, ind0); + __ tbl(out1, arrangement, codec, 4, ind1); + __ tbl(out2, arrangement, codec, 4, ind2); + __ tbl(out3, arrangement, codec, 4, ind3); + + __ st4(out0, out1, out2, out3, arrangement, __ post(dst, 4 * size)); + } + + /** + * Arguments: + * + * Input: + * c_rarg0 - src_start + * c_rarg1 - src_offset + * c_rarg2 - src_length + * c_rarg3 - dest_start + * c_rarg4 - dest_offset + * c_rarg5 - isURL + * + */ + address generate_base64_encodeBlock() { + + static const char toBase64[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' + }; + + static const char toBase64URL[64] = { + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' + }; + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "encodeBlock"); + address start = __ pc(); + + Register src = c_rarg0; // source array + Register soff = c_rarg1; // source start offset + Register send = c_rarg2; // source end offset + Register dst = c_rarg3; // dest array + Register doff = c_rarg4; // position for writing to dest array + Register isURL = c_rarg5; // Base64 or URL chracter set + + // c_rarg6 and c_rarg7 are free to use as temps + Register codec = c_rarg6; + Register length = c_rarg7; + + Label ProcessData, Process48B, Process24B, Process3B, SIMDExit, Exit; + + __ add(src, src, soff); + __ add(dst, dst, doff); + __ sub(length, send, soff); + + // load the codec base address + __ lea(codec, ExternalAddress((address) toBase64)); + __ cbz(isURL, ProcessData); + __ lea(codec, ExternalAddress((address) toBase64URL)); + + __ BIND(ProcessData); + + // too short to formup a SIMD loop, roll back + __ cmp(length, (u1)24); + __ br(Assembler::LT, Process3B); + + __ ld1(v0, v1, v2, v3, __ T16B, Address(codec)); + + __ BIND(Process48B); + __ cmp(length, (u1)48); + __ br(Assembler::LT, Process24B); + generate_base64_encode_simdround(src, dst, v0, 16); + __ sub(length, length, 48); + __ b(Process48B); + + __ BIND(Process24B); + __ cmp(length, (u1)24); + __ br(Assembler::LT, SIMDExit); + generate_base64_encode_simdround(src, dst, v0, 8); + __ sub(length, length, 24); + + __ BIND(SIMDExit); + __ cbz(length, Exit); + + __ BIND(Process3B); + // 3 src bytes, 24 bits + __ ldrb(r10, __ post(src, 1)); + __ ldrb(r11, __ post(src, 1)); + __ ldrb(r12, __ post(src, 1)); + __ orrw(r11, r11, r10, Assembler::LSL, 8); + __ orrw(r12, r12, r11, Assembler::LSL, 8); + // codec index + __ ubfmw(r15, r12, 18, 23); + __ ubfmw(r14, r12, 12, 17); + __ ubfmw(r13, r12, 6, 11); + __ andw(r12, r12, 63); + // get the code based on the codec + __ ldrb(r15, Address(codec, r15, Address::uxtw(0))); + __ ldrb(r14, Address(codec, r14, Address::uxtw(0))); + __ ldrb(r13, Address(codec, r13, Address::uxtw(0))); + __ ldrb(r12, Address(codec, r12, Address::uxtw(0))); + __ strb(r15, __ post(dst, 1)); + __ strb(r14, __ post(dst, 1)); + __ strb(r13, __ post(dst, 1)); + __ strb(r12, __ post(dst, 1)); + __ sub(length, length, 3); + __ cbnz(length, Process3B); + + __ BIND(Exit); + __ ret(lr); + + return start; + } + // Continuation point for throwing of implicit exceptions that are // not handled in the current activation. Fabricates an exception // oop and initiates normal exception dispatching in this @@ -6679,6 +6823,10 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_ghash_processBlocks = generate_ghash_processBlocks(); } + if (UseBASE64Intrinsics) { + StubRoutines::_base64_encodeBlock = generate_base64_encodeBlock(); + } + // data cache line writeback StubRoutines::_data_cache_writeback = generate_data_cache_writeback(); StubRoutines::_data_cache_writeback_sync = generate_data_cache_writeback_sync(); diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 18f56a527ab..2a6553d9c21 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -181,10 +181,6 @@ void VM_Version::initialize() { } if (_cpu == CPU_ARM && (_model == 0xd07 || _model2 == 0xd07)) _features |= CPU_STXR_PREFETCH; - // If an olde style /proc/cpuinfo (cores == 1) then if _model is an A57 (0xd07) - // we assume the worst and assume we could be on a big little system and have - // undisclosed A53 cores which we could be swapped to at any stage - if (_cpu == CPU_ARM && os::processor_count() == 1 && _model == 0xd07) _features |= CPU_A53MAC; char buf[512]; sprintf(buf, "0x%02x:0x%x:0x%03x:%d", _cpu, _variant, _model, _revision); @@ -336,6 +332,10 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseGHASHIntrinsics, false); } + if (FLAG_IS_DEFAULT(UseBASE64Intrinsics)) { + UseBASE64Intrinsics = true; + } + if (is_zva_enabled()) { if (FLAG_IS_DEFAULT(UseBlockZeroing)) { FLAG_SET_DEFAULT(UseBlockZeroing, true); diff --git a/src/hotspot/cpu/arm/c1_globals_arm.hpp b/src/hotspot/cpu/arm/c1_globals_arm.hpp index 8141870536b..7077a87092c 100644 --- a/src/hotspot/cpu/arm/c1_globals_arm.hpp +++ b/src/hotspot/cpu/arm/c1_globals_arm.hpp @@ -35,8 +35,6 @@ #ifndef COMPILER2 // avoid duplicated definitions, favoring C2 version define_pd_global(bool, BackgroundCompilation, true ); -define_pd_global(bool, UseTLAB, true ); -define_pd_global(bool, ResizeTLAB, true ); define_pd_global(bool, InlineIntrinsics, false); // TODO: ARM define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, false); diff --git a/src/hotspot/cpu/arm/c2_globals_arm.hpp b/src/hotspot/cpu/arm/c2_globals_arm.hpp index 3708e38da2e..525af8b1edc 100644 --- a/src/hotspot/cpu/arm/c2_globals_arm.hpp +++ b/src/hotspot/cpu/arm/c2_globals_arm.hpp @@ -54,8 +54,6 @@ define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); // (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.) //define_pd_global(intx, OptoLoopAlignment, 16); // = 4*wordSize define_pd_global(intx, RegisterCostAreaRatio, 16000); -define_pd_global(bool, UseTLAB, true); -define_pd_global(bool, ResizeTLAB, true); define_pd_global(intx, LoopUnrollLimit, 60); // Design center runs on 1.3.1 define_pd_global(intx, LoopPercentProfileLimit, 10); define_pd_global(intx, MinJumpTableSize, 16); diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index a819c0fa848..01ff3a5d39c 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -983,7 +983,7 @@ void InterpreterMacroAssembler::lock_object(Register Rlock) { // Unlocks an object. Used in monitorexit bytecode and remove_activation. // -// Argument: R1: Points to BasicObjectLock structure for lock +// Argument: R0: Points to BasicObjectLock structure for lock // Throw an IllegalMonitorException if object is not locked by current thread // Blows volatile registers R0-R3, Rtemp, LR. Calls VM. void InterpreterMacroAssembler::unlock_object(Register Rlock) { @@ -996,8 +996,7 @@ void InterpreterMacroAssembler::unlock_object(Register Rlock) { const Register Robj = R2; const Register Rmark = R3; - const Register Rresult = R0; - assert_different_registers(Robj, Rmark, Rlock, R0, Rtemp); + assert_different_registers(Robj, Rmark, Rlock, Rtemp); const int obj_offset = BasicObjectLock::obj_offset_in_bytes(); const int lock_offset = BasicObjectLock::lock_offset_in_bytes (); diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.cpp b/src/hotspot/cpu/arm/macroAssembler_arm.cpp index bb984d53d60..067ec704376 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp @@ -85,20 +85,6 @@ void AddressLiteral::set_rspec(relocInfo::relocType rtype) { } } -// Initially added to the Assembler interface as a pure virtual: -// RegisterConstant delayed_value(..) -// for: -// 6812678 macro assembler needs delayed binding of a few constants (for 6655638) -// this was subsequently modified to its present name and return type -RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset) { - ShouldNotReachHere(); - return RegisterOrConstant(-1); -} - - - // virtual method calling void MacroAssembler::lookup_virtual_method(Register recv_klass, diff --git a/src/hotspot/cpu/arm/macroAssembler_arm.hpp b/src/hotspot/cpu/arm/macroAssembler_arm.hpp index de40c5741a7..a07ca65d99e 100644 --- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp +++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp @@ -222,14 +222,6 @@ class MacroAssembler: public Assembler { // returning false to preserve all relocation information. inline bool ignore_non_patchable_relocations() { return true; } - // Initially added to the Assembler interface as a pure virtual: - // RegisterConstant delayed_value(..) - // for: - // 6812678 macro assembler needs delayed binding of a few constants (for 6655638) - // this was subsequently modified to its present name and return type - virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset); - - void align(int modulus); // Support for VM calls diff --git a/src/hotspot/cpu/ppc/c1_globals_ppc.hpp b/src/hotspot/cpu/ppc/c1_globals_ppc.hpp index 60b0005e034..f90c1e8b1d2 100644 --- a/src/hotspot/cpu/ppc/c1_globals_ppc.hpp +++ b/src/hotspot/cpu/ppc/c1_globals_ppc.hpp @@ -43,9 +43,7 @@ define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 1000); define_pd_global(intx, OnStackReplacePercentage, 1400); -define_pd_global(bool, UseTLAB, true); define_pd_global(bool, ProfileInterpreter, false); -define_pd_global(bool, ResizeTLAB, true); define_pd_global(uintx, ReservedCodeCacheSize, 32*M); define_pd_global(uintx, NonProfiledCodeHeapSize, 13*M ); define_pd_global(uintx, ProfiledCodeHeapSize, 14*M ); diff --git a/src/hotspot/cpu/ppc/c2_globals_ppc.hpp b/src/hotspot/cpu/ppc/c2_globals_ppc.hpp index 7a0c311e719..c576ddc95c4 100644 --- a/src/hotspot/cpu/ppc/c2_globals_ppc.hpp +++ b/src/hotspot/cpu/ppc/c2_globals_ppc.hpp @@ -51,8 +51,6 @@ define_pd_global(intx, INTPRESSURE, 26); define_pd_global(intx, InteriorEntryAlignment, 16); define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, RegisterCostAreaRatio, 16000); -define_pd_global(bool, UseTLAB, true); -define_pd_global(bool, ResizeTLAB, true); define_pd_global(intx, LoopUnrollLimit, 60); define_pd_global(intx, LoopPercentProfileLimit, 10); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 4872e036d2b..ca1c0c24987 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -382,25 +382,6 @@ AddressLiteral MacroAssembler::constant_oop_address(jobject obj) { return AddressLiteral(address(obj), oop_Relocation::spec(oop_index)); } -RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, int offset) { - intptr_t value = *delayed_value_addr; - if (value != 0) { - return RegisterOrConstant(value + offset); - } - - // Load indirectly to solve generation ordering problem. - // static address, no relocation - int simm16_offset = load_const_optimized(tmp, delayed_value_addr, noreg, true); - ld(tmp, simm16_offset, tmp); // must be aligned ((xa & 3) == 0) - - if (offset != 0) { - addi(tmp, tmp, offset); - } - - return RegisterOrConstant(tmp); -} - #ifndef PRODUCT void MacroAssembler::pd_print_patched_instruction(address branch) { Unimplemented(); // TODO: PPC port diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index a8e43cabdc4..1859483c470 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -152,12 +152,6 @@ class MacroAssembler: public Assembler { // Same as load_address. inline void set_oop (AddressLiteral obj_addr, Register d); - // Read runtime constant: Issue load if constant not yet established, - // else use real constant. - virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset); - // // branch, jump // diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp index fbe956322a6..1134ed0366b 100644 --- a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp @@ -197,7 +197,11 @@ intptr_t NativeMovConstReg::data() const { CodeBlob* cb = CodeCache::find_blob_unsafe(addr); if (MacroAssembler::is_set_narrow_oop(addr, cb->content_begin())) { narrowOop no = MacroAssembler::get_narrow_oop(addr, cb->content_begin()); - return cast_from_oop(CompressedOops::decode(no)); + // We can reach here during GC with 'no' pointing to new object location + // while 'heap()->is_in' still reports false (e.g. with SerialGC). + // Therefore we use raw decoding. + if (CompressedOops::is_null(no)) return 0; + return cast_from_oop(CompressedOops::decode_raw(no)); } else { assert(MacroAssembler::is_load_const_from_method_toc_at(addr), "must be load_const_from_pool"); diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index 2588f7a211c..b8f4f26995f 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -3888,7 +3888,7 @@ frame %{ // The `sig' array is to be updated. sig[j] represents the location // of the j-th argument, either a register or a stack slot. - // Comment taken from i486.ad: + // Comment taken from x86_32.ad: // Body of function which returns an integer array locating // arguments either in registers or in stack slots. Passed an array // of ideal registers called "sig" and a "length" count. Stack-slot @@ -3900,7 +3900,7 @@ frame %{ SharedRuntime::java_calling_convention(sig_bt, regs, length, false); %} - // Comment taken from i486.ad: + // Comment taken from x86_32.ad: // Body of function which returns an integer array locating // arguments either in registers or in stack slots. Passed an array // of ideal registers called "sig" and a "length" count. Stack-slot diff --git a/src/hotspot/cpu/s390/c1_globals_s390.hpp b/src/hotspot/cpu/s390/c1_globals_s390.hpp index 99e26e5e3f8..7fcb1ee0617 100644 --- a/src/hotspot/cpu/s390/c1_globals_s390.hpp +++ b/src/hotspot/cpu/s390/c1_globals_s390.hpp @@ -43,9 +43,7 @@ define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 1000); define_pd_global(intx, OnStackReplacePercentage, 1400); -define_pd_global(bool, UseTLAB, true); define_pd_global(bool, ProfileInterpreter, false); -define_pd_global(bool, ResizeTLAB, true); define_pd_global(uintx, ReservedCodeCacheSize, 32*M); define_pd_global(uintx, NonProfiledCodeHeapSize, 13*M); define_pd_global(uintx, ProfiledCodeHeapSize, 14*M); diff --git a/src/hotspot/cpu/s390/c2_globals_s390.hpp b/src/hotspot/cpu/s390/c2_globals_s390.hpp index 2f44fa73a2e..64d5585d616 100644 --- a/src/hotspot/cpu/s390/c2_globals_s390.hpp +++ b/src/hotspot/cpu/s390/c2_globals_s390.hpp @@ -51,8 +51,6 @@ define_pd_global(intx, INTPRESSURE, 10); // Medium size registe define_pd_global(intx, InteriorEntryAlignment, 2); define_pd_global(size_t, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, RegisterCostAreaRatio, 12000); -define_pd_global(bool, UseTLAB, true); -define_pd_global(bool, ResizeTLAB, true); define_pd_global(intx, LoopUnrollLimit, 60); define_pd_global(intx, LoopPercentProfileLimit, 10); define_pd_global(intx, MinJumpTableSize, 18); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index ffba110d388..d7c95ee96ee 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -1810,34 +1810,6 @@ void MacroAssembler::c2bool(Register r, Register t) { z_srl(r, 31); // Yields 0 if r was 0, 1 otherwise. } -RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset) { - intptr_t value = *delayed_value_addr; - if (value != 0) { - return RegisterOrConstant(value + offset); - } - - BLOCK_COMMENT("delayed_value {"); - // Load indirectly to solve generation ordering problem. - load_absolute_address(tmp, (address) delayed_value_addr); // tmp = a; - z_lg(tmp, 0, tmp); // tmp = *tmp; - -#ifdef ASSERT - NearLabel L; - compare64_and_branch(tmp, (intptr_t)0L, Assembler::bcondNotEqual, L); - z_illtrap(); - bind(L); -#endif - - if (offset != 0) { - z_agfi(tmp, offset); // tmp = tmp + offset; - } - - BLOCK_COMMENT("} delayed_value"); - return RegisterOrConstant(tmp); -} - // Patch instruction `inst' at offset `inst_pos' to refer to `dest_pos' // and return the resulting instruction. // Dest_pos and inst_pos are 32 bit only. These parms can only designate diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 41294b0fe87..113a1a3db2a 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -350,9 +350,6 @@ class MacroAssembler: public Assembler { // Uses constant_metadata_address. inline bool set_metadata_constant(Metadata* md, Register d); - virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset); // // branch, jump // diff --git a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp index 401501a6631..3acf53496fb 100644 --- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp @@ -1990,20 +1990,28 @@ void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) { // We are loading/storing from/to an array that *may* be flattened (the // declared type is Object[], abstract[], interface[] or VT.ref[]). // If this array is flattened, take the slow path. - Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); Register klass = op->tmp()->as_register(); - __ load_klass(klass, op->array()->as_register(), tmp_load_klass); - __ movl(klass, Address(klass, Klass::layout_helper_offset())); - __ testl(klass, Klass::_lh_array_tag_vt_value_bit_inplace); - __ jcc(Assembler::notZero, *op->stub()->entry()); + if (UseArrayMarkWordCheck) { + __ test_flattened_array_oop(op->array()->as_register(), op->tmp()->as_register(), *op->stub()->entry()); + } else { + Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); + __ load_klass(klass, op->array()->as_register(), tmp_load_klass); + __ movl(klass, Address(klass, Klass::layout_helper_offset())); + __ testl(klass, Klass::_lh_array_tag_vt_value_bit_inplace); + __ jcc(Assembler::notZero, *op->stub()->entry()); + } if (!op->value()->is_illegal()) { // The array is not flattened, but it might be null-free. If we are storing // a null into a null-free array, take the slow path (which will throw NPE). Label skip; __ cmpptr(op->value()->as_register(), (int32_t)NULL_WORD); __ jcc(Assembler::notEqual, skip); - __ testl(klass, Klass::_lh_null_free_bit_inplace); - __ jcc(Assembler::notZero, *op->stub()->entry()); + if (UseArrayMarkWordCheck) { + __ test_null_free_array_oop(op->array()->as_register(), op->tmp()->as_register(), *op->stub()->entry()); + } else { + __ testl(klass, Klass::_lh_null_free_bit_inplace); + __ jcc(Assembler::notZero, *op->stub()->entry()); + } __ bind(skip); } } @@ -2011,11 +2019,22 @@ void LIR_Assembler::emit_opFlattenedArrayCheck(LIR_OpFlattenedArrayCheck* op) { void LIR_Assembler::emit_opNullFreeArrayCheck(LIR_OpNullFreeArrayCheck* op) { // We are storing into an array that *may* be null-free (the declared type is // Object[], abstract[], interface[] or VT.ref[]). - Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); - Register klass = op->tmp()->as_register(); - __ load_klass(klass, op->array()->as_register(), tmp_load_klass); - __ movl(klass, Address(klass, Klass::layout_helper_offset())); - __ testl(klass, Klass::_lh_null_free_bit_inplace); + if (UseArrayMarkWordCheck) { + Label test_mark_word; + Register tmp = op->tmp()->as_register(); + __ movptr(tmp, Address(op->array()->as_register(), oopDesc::mark_offset_in_bytes())); + __ testl(tmp, markWord::unlocked_value); + __ jccb(Assembler::notZero, test_mark_word); + __ load_prototype_header(tmp, op->array()->as_register(), rscratch1); + __ bind(test_mark_word); + __ testl(tmp, markWord::nullfree_array_bit_in_place); + } else { + Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); + Register klass = op->tmp()->as_register(); + __ load_klass(klass, op->array()->as_register(), tmp_load_klass); + __ movl(klass, Address(klass, Klass::layout_helper_offset())); + __ testl(klass, Klass::_lh_null_free_bit_inplace); + } } void LIR_Assembler::emit_opSubstitutabilityCheck(LIR_OpSubstitutabilityCheck* op) { @@ -3252,17 +3271,24 @@ void LIR_Assembler::arraycopy_inlinetype_check(Register obj, Register tmp, CodeS __ testptr(obj, obj); __ jcc(Assembler::zero, *slow_path->entry()); } - Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); - __ load_klass(tmp, obj, tmp_load_klass); - __ movl(tmp, Address(tmp, Klass::layout_helper_offset())); - if (is_dest) { - // We also take slow path if it's a null_free destination array, just in case the source array - // contains NULLs. - __ testl(tmp, Klass::_lh_null_free_bit_inplace); + if (UseArrayMarkWordCheck) { + if (is_dest) { + __ test_null_free_array_oop(obj, tmp, *slow_path->entry()); + } else { + __ test_flattened_array_oop(obj, tmp, *slow_path->entry()); + } } else { - __ testl(tmp, Klass::_lh_array_tag_vt_value_bit_inplace); + Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg); + __ load_klass(tmp, obj, tmp_load_klass); + __ movl(tmp, Address(tmp, Klass::layout_helper_offset())); + if (is_dest) { + // Take the slow path if it's a null_free destination array, in case the source array contains NULLs. + __ testl(tmp, Klass::_lh_null_free_bit_inplace); + } else { + __ testl(tmp, Klass::_lh_array_tag_vt_value_bit_inplace); + } + __ jcc(Assembler::notZero, *slow_path->entry()); } - __ jcc(Assembler::notZero, *slow_path->entry()); } diff --git a/src/hotspot/cpu/x86/c1_globals_x86.hpp b/src/hotspot/cpu/x86/c1_globals_x86.hpp index 281cc916b94..ba0ac8131c9 100644 --- a/src/hotspot/cpu/x86/c1_globals_x86.hpp +++ b/src/hotspot/cpu/x86/c1_globals_x86.hpp @@ -33,8 +33,6 @@ #ifndef TIERED define_pd_global(bool, BackgroundCompilation, true ); -define_pd_global(bool, UseTLAB, true ); -define_pd_global(bool, ResizeTLAB, true ); define_pd_global(bool, InlineIntrinsics, true ); define_pd_global(bool, PreferInterpreterNativeStubs, false); define_pd_global(bool, ProfileTraps, false); diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 34ca854bb3e..17806dbf902 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -883,6 +883,7 @@ void C2_MacroAssembler::vabsnegf(int opcode, XMMRegister dst, XMMRegister src, i void C2_MacroAssembler::pminmax(int opcode, BasicType elem_bt, XMMRegister dst, XMMRegister src, XMMRegister tmp) { assert(opcode == Op_MinV || opcode == Op_MaxV, "sanity"); + assert(tmp == xnoreg || elem_bt == T_LONG, "unused"); if (opcode == Op_MinV) { if (elem_bt == T_BYTE) { @@ -894,6 +895,7 @@ void C2_MacroAssembler::pminmax(int opcode, BasicType elem_bt, XMMRegister dst, } else { assert(elem_bt == T_LONG, "required"); assert(tmp == xmm0, "required"); + assert_different_registers(dst, src, tmp); movdqu(xmm0, dst); pcmpgtq(xmm0, src); blendvpd(dst, src); // xmm0 as mask @@ -908,6 +910,7 @@ void C2_MacroAssembler::pminmax(int opcode, BasicType elem_bt, XMMRegister dst, } else { assert(elem_bt == T_LONG, "required"); assert(tmp == xmm0, "required"); + assert_different_registers(dst, src, tmp); movdqu(xmm0, src); pcmpgtq(xmm0, dst); blendvpd(dst, src); // xmm0 as mask @@ -932,6 +935,7 @@ void C2_MacroAssembler::vpminmax(int opcode, BasicType elem_bt, if (UseAVX > 2 && (vlen_enc == Assembler::AVX_512bit || VM_Version::supports_avx512vl())) { vpminsq(dst, src1, src2, vlen_enc); } else { + assert_different_registers(dst, src1, src2); vpcmpgtq(dst, src1, src2, vlen_enc); vblendvpd(dst, src1, src2, dst, vlen_enc); } @@ -948,6 +952,7 @@ void C2_MacroAssembler::vpminmax(int opcode, BasicType elem_bt, if (UseAVX > 2 && (vlen_enc == Assembler::AVX_512bit || VM_Version::supports_avx512vl())) { vpmaxsq(dst, src1, src2, vlen_enc); } else { + assert_different_registers(dst, src1, src2); vpcmpgtq(dst, src1, src2, vlen_enc); vblendvpd(dst, src2, src1, dst, vlen_enc); } @@ -965,6 +970,7 @@ void C2_MacroAssembler::vminmax_fp(int opcode, BasicType elem_bt, assert(opcode == Op_MinV || opcode == Op_MinReductionV || opcode == Op_MaxV || opcode == Op_MaxReductionV, "sanity"); assert(elem_bt == T_FLOAT || elem_bt == T_DOUBLE, "sanity"); + assert_different_registers(a, b, tmp, atmp, btmp); bool is_min = (opcode == Op_MinV || opcode == Op_MinReductionV); bool is_double_word = is_double_word_type(elem_bt); @@ -1005,6 +1011,7 @@ void C2_MacroAssembler::evminmax_fp(int opcode, BasicType elem_bt, assert(opcode == Op_MinV || opcode == Op_MinReductionV || opcode == Op_MaxV || opcode == Op_MaxReductionV, "sanity"); assert(elem_bt == T_FLOAT || elem_bt == T_DOUBLE, "sanity"); + assert_different_registers(dst, a, b, atmp, btmp); bool is_min = (opcode == Op_MinV || opcode == Op_MinReductionV); bool is_double_word = is_double_word_type(elem_bt); diff --git a/src/hotspot/cpu/x86/c2_globals_x86.hpp b/src/hotspot/cpu/x86/c2_globals_x86.hpp index 6513be7b53e..31e77b52568 100644 --- a/src/hotspot/cpu/x86/c2_globals_x86.hpp +++ b/src/hotspot/cpu/x86/c2_globals_x86.hpp @@ -31,8 +31,6 @@ // Sets the default values for platform dependent flags used by the server compiler. // (see c2_globals.hpp). Alpha-sorted. define_pd_global(bool, BackgroundCompilation, true); -define_pd_global(bool, UseTLAB, true); -define_pd_global(bool, ResizeTLAB, true); define_pd_global(bool, CICompileOSR, true); define_pd_global(bool, InlineIntrinsics, true); define_pd_global(bool, PreferInterpreterNativeStubs, false); diff --git a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp index 01b53c5266a..2aac0608207 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/c1/shenandoahBarrierSetC1_x86.cpp @@ -111,7 +111,8 @@ LIR_Opr ShenandoahBarrierSetC1::atomic_xchg_at_resolved(LIRAccess& access, LIRIt __ xchg(access.resolved_addr(), result, result, LIR_OprFact::illegalOpr); if (access.is_oop()) { - result = load_reference_barrier(access.gen(), result, LIR_OprFact::addressConst(0), ShenandoahBarrierSet::AccessKind::NORMAL); + ShenandoahBarrierSet::AccessKind kind = ShenandoahBarrierSet::access_kind(access.decorators(), access.type()); + result = load_reference_barrier(access.gen(), result, LIR_OprFact::addressConst(0), kind); LIR_Opr tmp = gen->new_register(type); __ move(result, tmp); result = tmp; diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 474416c977f..336afa5d325 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -4262,44 +4262,6 @@ void MacroAssembler::vallones(XMMRegister dst, int vector_len) { } } -RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset) { - intptr_t value = *delayed_value_addr; - if (value != 0) - return RegisterOrConstant(value + offset); - - // load indirectly to solve generation ordering problem - movptr(tmp, ExternalAddress((address) delayed_value_addr)); - -#ifdef ASSERT - { Label L; - testptr(tmp, tmp); - if (WizardMode) { - const char* buf = NULL; - { - ResourceMark rm; - stringStream ss; - ss.print("DelayedValue=" INTPTR_FORMAT, delayed_value_addr[1]); - buf = code_string(ss.as_string()); - } - jcc(Assembler::notZero, L); - STOP(buf); - } else { - jccb(Assembler::notZero, L); - hlt(); - } - bind(L); - } -#endif - - if (offset != 0) - addptr(tmp, offset); - - return RegisterOrConstant(tmp); -} - - Address MacroAssembler::argument_address(RegisterOrConstant arg_slot, int extra_slot_offset) { // cf. TemplateTable::prepare_invoke(), if (load_receiver). diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 23e8de560a2..08ae7256948 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -708,10 +708,6 @@ class MacroAssembler: public Assembler { // Check for reserved stack access in method being exited (for JIT) void reserved_stack_check(); - virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset); - void safepoint_poll(Label& slow_path, Register thread_reg, bool at_return, bool in_nmethod); void verify_tlab(); diff --git a/src/hotspot/cpu/x86/methodHandles_x86.hpp b/src/hotspot/cpu/x86/methodHandles_x86.hpp index bf2c8d72d05..444d0495666 100644 --- a/src/hotspot/cpu/x86/methodHandles_x86.hpp +++ b/src/hotspot/cpu/x86/methodHandles_x86.hpp @@ -27,7 +27,7 @@ // Adapters enum /* platform_dependent_constants */ { - adapter_code_size = 3000 DEBUG_ONLY(+ 6000) + adapter_code_size = 4000 DEBUG_ONLY(+ 6000) }; // Additional helper methods for MethodHandles code generation: diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp index c0b2219dcec..4bc3b0340b5 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp @@ -3669,7 +3669,7 @@ class StubGenerator: public StubCodeGenerator { __ pusha(); // xmm0 and xmm1 may be used for passing float/double arguments - const int xmm_size = wordSize * 2; + const int xmm_size = wordSize * 4; const int xmm_spill_size = xmm_size * 2; __ subptr(rsp, xmm_spill_size); __ movdqu(Address(rsp, xmm_size * 1), xmm1); diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index c6c8c172b0a..7551dfaa0fc 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -5787,7 +5787,7 @@ instruct evminmaxFP_reg_eavx(vec dst, vec a, vec b, vec atmp, vec btmp) %{ is_floating_point_type(vector_element_basic_type(n))); // T_FLOAT, T_DOUBLE match(Set dst (MinV a b)); match(Set dst (MaxV a b)); - effect(USE a, USE b, TEMP atmp, TEMP btmp); + effect(TEMP dst, USE a, USE b, TEMP atmp, TEMP btmp); format %{ "vector_minmaxFP $dst,$a,$b\t!using $atmp, $btmp as TEMP" %} ins_encode %{ assert(UseAVX > 2, "required"); diff --git a/src/hotspot/cpu/zero/assembler_zero.cpp b/src/hotspot/cpu/zero/assembler_zero.cpp index b23048bb82b..706e020123a 100644 --- a/src/hotspot/cpu/zero/assembler_zero.cpp +++ b/src/hotspot/cpu/zero/assembler_zero.cpp @@ -66,12 +66,6 @@ void MacroAssembler::advance(int bytes) { code_section()->set_end(code_section()->end() + bytes); } -RegisterOrConstant MacroAssembler::delayed_value_impl( - intptr_t* delayed_value_addr, Register tmpl, int offset) { - ShouldNotCallThis(); - return RegisterOrConstant(); -} - void MacroAssembler::store_oop(jobject obj) { code_section()->relocate(pc(), oop_Relocation::spec_for_immediate()); emit_address((address) obj); diff --git a/src/hotspot/cpu/zero/assembler_zero.hpp b/src/hotspot/cpu/zero/assembler_zero.hpp index 1edf2c7df49..ae4c58e8ac7 100644 --- a/src/hotspot/cpu/zero/assembler_zero.hpp +++ b/src/hotspot/cpu/zero/assembler_zero.hpp @@ -54,9 +54,6 @@ class MacroAssembler : public Assembler { void bang_stack_with_offset(int offset); bool needs_explicit_null_check(intptr_t offset); bool uses_implicit_null_check(void* address); - RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, int offset); - public: void advance(int bytes); void store_oop(jobject obj); void store_Metadata(Metadata* obj); diff --git a/src/hotspot/cpu/zero/interp_masm_zero.hpp b/src/hotspot/cpu/zero/interp_masm_zero.hpp index 5d8aa9a3bdc..a109b12dec0 100644 --- a/src/hotspot/cpu/zero/interp_masm_zero.hpp +++ b/src/hotspot/cpu/zero/interp_masm_zero.hpp @@ -35,14 +35,6 @@ class InterpreterMacroAssembler : public MacroAssembler { public: InterpreterMacroAssembler(CodeBuffer* code) : MacroAssembler(code) {} - - public: - RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, - Register tmp, - int offset) { - ShouldNotCallThis(); - return RegisterOrConstant(); - } }; #endif // CPU_ZERO_INTERP_MASM_ZERO_HPP diff --git a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp index 909f6caa266..a865ef37a2f 100644 --- a/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp +++ b/src/hotspot/cpu/zero/zeroInterpreter_zero.cpp @@ -70,10 +70,11 @@ void ZeroInterpreter::initialize_code() { // Allow c++ interpreter to do one initialization now that switches are set, etc. BytecodeInterpreter start_msg(BytecodeInterpreter::initialize); - if (JvmtiExport::can_post_interpreter_events()) - BytecodeInterpreter::runWithChecks(&start_msg); - else - BytecodeInterpreter::run(&start_msg); + if (JvmtiExport::can_post_interpreter_events()) { + BytecodeInterpreter::run(&start_msg); + } else { + BytecodeInterpreter::run(&start_msg); + } } void ZeroInterpreter::invoke_method(Method* method, address entry_point, TRAPS) { @@ -169,10 +170,11 @@ void ZeroInterpreter::main_loop(int recurse, TRAPS) { thread->set_last_Java_frame(); // Call the interpreter - if (JvmtiExport::can_post_interpreter_events()) - BytecodeInterpreter::runWithChecks(istate); - else - BytecodeInterpreter::run(istate); + if (JvmtiExport::can_post_interpreter_events()) { + BytecodeInterpreter::run(istate); + } else { + BytecodeInterpreter::run(istate); + } fixup_after_potential_safepoint(); // Clear the frame anchor diff --git a/src/hotspot/os/aix/globals_aix.hpp b/src/hotspot/os/aix/globals_aix.hpp index b6b67a4f3bb..1203b09c883 100644 --- a/src/hotspot/os/aix/globals_aix.hpp +++ b/src/hotspot/os/aix/globals_aix.hpp @@ -88,7 +88,6 @@ // Use Use64KPages or Use16MPages instead. define_pd_global(bool, UseLargePages, false); define_pd_global(bool, UseLargePagesIndividualAllocation, false); -define_pd_global(bool, UseOSErrorReporting, false); define_pd_global(bool, UseThreadPriorities, true) ; #endif // OS_AIX_GLOBALS_AIX_HPP diff --git a/src/hotspot/os/bsd/globals_bsd.hpp b/src/hotspot/os/bsd/globals_bsd.hpp index 6c8939a6dc0..b36173655df 100644 --- a/src/hotspot/os/bsd/globals_bsd.hpp +++ b/src/hotspot/os/bsd/globals_bsd.hpp @@ -44,7 +44,6 @@ // define_pd_global(bool, UseLargePages, false); define_pd_global(bool, UseLargePagesIndividualAllocation, false); -define_pd_global(bool, UseOSErrorReporting, false); define_pd_global(bool, UseThreadPriorities, true) ; #endif // OS_BSD_GLOBALS_BSD_HPP diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 047901c6efa..a37fd28f0e4 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -92,7 +92,6 @@ // define_pd_global(bool, UseLargePages, false); define_pd_global(bool, UseLargePagesIndividualAllocation, false); -define_pd_global(bool, UseOSErrorReporting, false); define_pd_global(bool, UseThreadPriorities, true) ; #endif // OS_LINUX_GLOBALS_LINUX_HPP diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index 6b248a96981..94251da145d 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -26,6 +26,7 @@ #include "jvm.h" #include "logging/log.hpp" +#include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/os.hpp" @@ -71,10 +72,6 @@ extern "C" { static sigset_t check_signal_done; static bool check_signals = true; -// This boolean allows users to forward their own non-matching signals -// to JVM_handle_bsd_signal/JVM_handle_linux_signal, harmlessly. -static bool signal_handlers_are_installed = false; - debug_only(static bool signal_sets_initialized = false); static sigset_t unblocked_sigs, vm_sigs, preinstalled_sigs; struct sigaction sigact[NSIG]; @@ -261,6 +258,8 @@ static const struct { { -1, NULL } }; +static const char* get_signal_name(int sig, char* out, size_t outlen); + //////////////////////////////////////////////////////////////////////////////// // sun.misc.Signal support @@ -313,6 +312,8 @@ static int check_pending_signals() { } } while (threadIsSuspended); } + ShouldNotReachHere(); + return 0; // Satisfy compiler } int os::signal_wait() { @@ -408,50 +409,6 @@ bool PosixSignals::chained_handler(int sig, siginfo_t* siginfo, void* context) { return chained; } -//////////////////////////////////////////////////////////////////////////////// -// signal handling (except suspend/resume) - -// This routine may be used by user applications as a "hook" to catch signals. -// The user-defined signal handler must pass unrecognized signals to this -// routine, and if it returns true (non-zero), then the signal handler must -// return immediately. If the flag "abort_if_unrecognized" is true, then this -// routine will never retun false (zero), but instead will execute a VM panic -// routine kill the process. -// -// If this routine returns false, it is OK to call it again. This allows -// the user-defined signal handler to perform checks either before or after -// the VM performs its own checks. Naturally, the user code would be making -// a serious error if it tried to handle an exception (such as a null check -// or breakpoint) that the VM was generating for its own correct operation. -// -// This routine may recognize any of the following kinds of signals: -// SIGBUS, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGPIPE, SIGXFSZ, SIGUSR1. -// It should be consulted by handlers for any of those signals. -// -// The caller of this routine must pass in the three arguments supplied -// to the function referred to in the "sa_sigaction" (not the "sa_handler") -// field of the structure passed to sigaction(). This routine assumes that -// the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART. -// -// Note that the VM will print warnings if it detects conflicting signal -// handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers". -// - -#if defined(BSD) -extern "C" JNIEXPORT int JVM_handle_bsd_signal(int signo, siginfo_t* siginfo, - void* ucontext, - int abort_if_unrecognized); -#elif defined(AIX) -extern "C" JNIEXPORT int JVM_handle_aix_signal(int signo, siginfo_t* siginfo, - void* ucontext, - int abort_if_unrecognized); -#else -extern "C" JNIEXPORT int JVM_handle_linux_signal(int signo, siginfo_t* siginfo, - void* ucontext, - int abort_if_unrecognized); -#endif - - ///// Synchronous (non-deferrable) error signals (ILL, SEGV, FPE, BUS, TRAP): // These signals are special because they cannot be deferred and, if they @@ -502,21 +459,151 @@ void PosixSignals::unblock_error_signals() { ::pthread_sigmask(SIG_UNBLOCK, &set, NULL); } -// Renamed from 'signalHandler' to avoid collision with other shared libs. -static void javaSignalHandler(int sig, siginfo_t* info, void* uc) { - assert(info != NULL && uc != NULL, "it must be old kernel"); +class ErrnoPreserver: public StackObj { + const int _saved; +public: + ErrnoPreserver() : _saved(errno) {} + ~ErrnoPreserver() { errno = _saved; } +}; - PosixSignals::unblock_error_signals(); +//////////////////////////////////////////////////////////////////////////////// +// JVM_handle_(linux|aix|bsd)_signal() + +// This routine is the shared part of the central hotspot signal handler. It can +// also be called by a user application, if a user application prefers to do +// signal handling itself - in that case it needs to pass signals the VM +// internally uses on to the VM first. +// +// The user-defined signal handler must pass unrecognized signals to this +// routine, and if it returns true (non-zero), then the signal handler must +// return immediately. If the flag "abort_if_unrecognized" is true, then this +// routine will never return false (zero), but instead will execute a VM panic +// routine to kill the process. +// +// If this routine returns false, it is OK to call it again. This allows +// the user-defined signal handler to perform checks either before or after +// the VM performs its own checks. Naturally, the user code would be making +// a serious error if it tried to handle an exception (such as a null check +// or breakpoint) that the VM was generating for its own correct operation. +// +// This routine may recognize any of the following kinds of signals: +// SIGBUS, SIGSEGV, SIGILL, SIGFPE, SIGQUIT, SIGPIPE, SIGXFSZ, SIGUSR1. +// It should be consulted by handlers for any of those signals. +// +// The caller of this routine must pass in the three arguments supplied +// to the function referred to in the "sa_sigaction" (not the "sa_handler") +// field of the structure passed to sigaction(). This routine assumes that +// the sa_flags field passed to sigaction() includes SA_SIGINFO and SA_RESTART. +// +// Note that the VM will print warnings if it detects conflicting signal +// handlers, unless invoked with the option "-XX:+AllowUserSignalHandlers". +// - int orig_errno = errno; // Preserve errno value over signal handler. #if defined(BSD) - JVM_handle_bsd_signal(sig, info, uc, true); +#define JVM_HANDLE_XXX_SIGNAL JVM_handle_bsd_signal #elif defined(AIX) - JVM_handle_aix_signal(sig, info, uc, true); +#define JVM_HANDLE_XXX_SIGNAL JVM_handle_aix_signal +#elif defined(LINUX) +#define JVM_HANDLE_XXX_SIGNAL JVM_handle_linux_signal +#else +#error who are you? +#endif + +extern "C" JNIEXPORT +int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info, + void* ucVoid, int abort_if_unrecognized) +{ + assert(info != NULL && ucVoid != NULL, "sanity"); + + // Note: it's not uncommon that JNI code uses signal/sigset to install, + // then restore certain signal handler (e.g. to temporarily block SIGPIPE, + // or have a SIGILL handler when detecting CPU type). When that happens, + // this handler might be invoked with junk info/ucVoid. To avoid unnecessary + // crash when libjsig is not preloaded, try handle signals that do not require + // siginfo/ucontext first. + + // Preserve errno value over signal handler. + // (note: RAII ok here, even with JFR thread crash protection, see below). + ErrnoPreserver ep; + + // Unblock all synchronous error signals (see JDK-8252533) + PosixSignals::unblock_error_signals(); + + ucontext_t* const uc = (ucontext_t*) ucVoid; + Thread* const t = Thread::current_or_null_safe(); + + // Handle JFR thread crash protection. + // Note: this may cause us to longjmp away. Do not use any code before this + // point which really needs any form of epilogue code running, eg RAII objects. + os::ThreadCrashProtection::check_crash_protection(sig, t); + + bool signal_was_handled = false; + + // Handle assertion poison page accesses. +#ifdef CAN_SHOW_REGISTERS_ON_ASSERT + if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) { + signal_was_handled = handle_assert_poison_fault(ucVoid, info->si_addr); + } +#endif + + // Ignore SIGPIPE and SIGXFSZ (4229104, 6499219). + if (sig == SIGPIPE || sig == SIGXFSZ) { + PosixSignals::chained_handler(sig, info, ucVoid); + signal_was_handled = true; // unconditionally. + } + + // Call platform dependent signal handler. + if (!signal_was_handled) { + JavaThread* const jt = (t != NULL && t->is_Java_thread()) ? (JavaThread*) t : NULL; + signal_was_handled = PosixSignals::pd_hotspot_signal_handler(sig, info, uc, jt); + } + + // From here on, if the signal had not been handled, it is a fatal error. + + // Give the chained signal handler - should it exist - a shot. + if (!signal_was_handled) { + signal_was_handled = PosixSignals::chained_handler(sig, info, ucVoid); + } + + // Invoke fatal error handling. + if (!signal_was_handled && abort_if_unrecognized) { + // Extract pc from context for the error handler to display. + address pc = NULL; + if (uc != NULL) { + // prepare fault pc address for error reporting. + if (S390_ONLY(sig == SIGILL || sig == SIGFPE) NOT_S390(false)) { + pc = (address)info->si_addr; + } else { + pc = PosixSignals::ucontext_get_pc(uc); + } + } +#if defined(ZERO) && !defined(PRODUCT) + char buf[64]; + VMError::report_and_die(t, sig, pc, info, ucVoid, + "\n#" + "\n# /--------------------\\" + "\n# | %-7s |" + "\n# \\---\\ /--------------/" + "\n# /" + "\n# [-] |\\_/| " + "\n# (+)=C |o o|__ " + "\n# | | =-*-=__\\ " + "\n# OOO c_c_(___)", + get_signal_name(sig, buf, sizeof(buf))); #else - JVM_handle_linux_signal(sig, info, uc, true); + VMError::report_and_die(t, sig, pc, info, ucVoid); #endif - errno = orig_errno; + // VMError should not return. + ShouldNotReachHere(); + } + return signal_was_handled; +} + +// Entry point for the hotspot signal handler. +static void javaSignalHandler(int sig, siginfo_t* info, void* ucVoid) { + // Do not add any code here! + // Only add code to either JVM_HANDLE_XXX_SIGNAL or PosixSignals::pd_hotspot_signal_handler. + (void)JVM_HANDLE_XXX_SIGNAL(sig, info, ucVoid, true); } static void UserHandler(int sig, void *siginfo, void *context) { @@ -766,9 +853,7 @@ void os::run_periodic_checks() { do_signal_check(SIGBUS); do_signal_check(SIGPIPE); do_signal_check(SIGXFSZ); -#if defined(PPC64) - do_signal_check(SIGTRAP); -#endif + PPC64_ONLY(do_signal_check(SIGTRAP);) // ReduceSignalUsage allows the user to override these handlers // see comments at the very top and jvm_md.h @@ -935,7 +1020,6 @@ static bool is_valid_signal(int sig) { #endif } -// Returned string is a constant. For unknown signals "UNKNOWN" is returned. static const char* get_signal_name(int sig, char* out, size_t outlen) { const char* ret = NULL; @@ -1075,7 +1159,7 @@ int os::get_signal_number(const char* signal_name) { return -1; } -void set_signal_handler(int sig, bool set_installed) { +void set_signal_handler(int sig) { // Check for overwrite. struct sigaction oldAct; sigaction(sig, (struct sigaction*)NULL, &oldAct); @@ -1086,7 +1170,7 @@ void set_signal_handler(int sig, bool set_installed) { if (oldhand != CAST_FROM_FN_PTR(void*, SIG_DFL) && oldhand != CAST_FROM_FN_PTR(void*, SIG_IGN) && oldhand != CAST_FROM_FN_PTR(void*, (sa_sigaction_t)javaSignalHandler)) { - if (AllowUserSignalHandlers || !set_installed) { + if (AllowUserSignalHandlers) { // Do not overwrite; user takes responsibility to forward to us. return; } else if (UseSignalChaining) { @@ -1103,13 +1187,8 @@ void set_signal_handler(int sig, bool set_installed) { struct sigaction sigAct; sigfillset(&(sigAct.sa_mask)); remove_error_signals_from_set(&(sigAct.sa_mask)); - sigAct.sa_handler = SIG_DFL; - if (!set_installed) { - sigAct.sa_flags = SA_SIGINFO|SA_RESTART; - } else { - sigAct.sa_sigaction = javaSignalHandler; - sigAct.sa_flags = SA_SIGINFO|SA_RESTART; - } + sigAct.sa_sigaction = javaSignalHandler; + sigAct.sa_flags = SA_SIGINFO|SA_RESTART; #if defined(__APPLE__) // Needed for main thread as XNU (Mac OS X kernel) will only deliver SIGSEGV // (which starts as SIGBUS) on main thread with faulting address inside "stack+guard pages" @@ -1136,87 +1215,75 @@ void set_signal_handler(int sig, bool set_installed) { assert(oldhand2 == oldhand, "no concurrent signal handler installation"); } -// install signal handlers for signals that HotSpot needs to -// handle in order to support Java-level exception handling. - -bool PosixSignals::are_signal_handlers_installed() { - return signal_handlers_are_installed; -} - // install signal handlers for signals that HotSpot needs to // handle in order to support Java-level exception handling. void PosixSignals::install_signal_handlers() { - if (!signal_handlers_are_installed) { - signal_handlers_are_installed = true; - - // signal-chaining - typedef void (*signal_setting_t)(); - signal_setting_t begin_signal_setting = NULL; - signal_setting_t end_signal_setting = NULL; - begin_signal_setting = CAST_TO_FN_PTR(signal_setting_t, - dlsym(RTLD_DEFAULT, "JVM_begin_signal_setting")); - if (begin_signal_setting != NULL) { - end_signal_setting = CAST_TO_FN_PTR(signal_setting_t, - dlsym(RTLD_DEFAULT, "JVM_end_signal_setting")); - get_signal_action = CAST_TO_FN_PTR(get_signal_t, - dlsym(RTLD_DEFAULT, "JVM_get_signal_action")); - libjsig_is_loaded = true; - assert(UseSignalChaining, "should enable signal-chaining"); - } - if (libjsig_is_loaded) { - // Tell libjsig jvm is setting signal handlers - (*begin_signal_setting)(); - } - set_signal_handler(SIGSEGV, true); - set_signal_handler(SIGPIPE, true); - set_signal_handler(SIGBUS, true); - set_signal_handler(SIGILL, true); - set_signal_handler(SIGFPE, true); -#if defined(PPC64) || defined(AIX) - set_signal_handler(SIGTRAP, true); -#endif - set_signal_handler(SIGXFSZ, true); + // signal-chaining + typedef void (*signal_setting_t)(); + signal_setting_t begin_signal_setting = NULL; + signal_setting_t end_signal_setting = NULL; + begin_signal_setting = CAST_TO_FN_PTR(signal_setting_t, + dlsym(RTLD_DEFAULT, "JVM_begin_signal_setting")); + if (begin_signal_setting != NULL) { + end_signal_setting = CAST_TO_FN_PTR(signal_setting_t, + dlsym(RTLD_DEFAULT, "JVM_end_signal_setting")); + get_signal_action = CAST_TO_FN_PTR(get_signal_t, + dlsym(RTLD_DEFAULT, "JVM_get_signal_action")); + libjsig_is_loaded = true; + assert(UseSignalChaining, "should enable signal-chaining"); + } + if (libjsig_is_loaded) { + // Tell libjsig jvm is setting signal handlers + (*begin_signal_setting)(); + } + + set_signal_handler(SIGSEGV); + set_signal_handler(SIGPIPE); + set_signal_handler(SIGBUS); + set_signal_handler(SIGILL); + set_signal_handler(SIGFPE); + PPC64_ONLY(set_signal_handler(SIGTRAP);) + set_signal_handler(SIGXFSZ); #if defined(__APPLE__) - // In Mac OS X 10.4, CrashReporter will write a crash log for all 'fatal' signals, including - // signals caught and handled by the JVM. To work around this, we reset the mach task - // signal handler that's placed on our process by CrashReporter. This disables - // CrashReporter-based reporting. - // - // This work-around is not necessary for 10.5+, as CrashReporter no longer intercedes - // on caught fatal signals. - // - // Additionally, gdb installs both standard BSD signal handlers, and mach exception - // handlers. By replacing the existing task exception handler, we disable gdb's mach - // exception handling, while leaving the standard BSD signal handlers functional. - kern_return_t kr; - kr = task_set_exception_ports(mach_task_self(), - EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC, - MACH_PORT_NULL, - EXCEPTION_STATE_IDENTITY, - MACHINE_THREAD_STATE); - - assert(kr == KERN_SUCCESS, "could not set mach task signal handler"); + // In Mac OS X 10.4, CrashReporter will write a crash log for all 'fatal' signals, including + // signals caught and handled by the JVM. To work around this, we reset the mach task + // signal handler that's placed on our process by CrashReporter. This disables + // CrashReporter-based reporting. + // + // This work-around is not necessary for 10.5+, as CrashReporter no longer intercedes + // on caught fatal signals. + // + // Additionally, gdb installs both standard BSD signal handlers, and mach exception + // handlers. By replacing the existing task exception handler, we disable gdb's mach + // exception handling, while leaving the standard BSD signal handlers functional. + kern_return_t kr; + kr = task_set_exception_ports(mach_task_self(), + EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC, + MACH_PORT_NULL, + EXCEPTION_STATE_IDENTITY, + MACHINE_THREAD_STATE); + + assert(kr == KERN_SUCCESS, "could not set mach task signal handler"); #endif + if (libjsig_is_loaded) { + // Tell libjsig jvm finishes setting signal handlers + (*end_signal_setting)(); + } + + // We don't activate signal checker if libjsig is in place, we trust ourselves + // and if UserSignalHandler is installed all bets are off. + // Log that signal checking is off only if -verbose:jni is specified. + if (CheckJNICalls) { if (libjsig_is_loaded) { - // Tell libjsig jvm finishes setting signal handlers - (*end_signal_setting)(); + log_debug(jni, resolve)("Info: libjsig is activated, all active signal checking is disabled"); + check_signals = false; } - - // We don't activate signal checker if libjsig is in place, we trust ourselves - // and if UserSignalHandler is installed all bets are off. - // Log that signal checking is off only if -verbose:jni is specified. - if (CheckJNICalls) { - if (libjsig_is_loaded) { - log_debug(jni, resolve)("Info: libjsig is activated, all active signal checking is disabled"); - check_signals = false; - } - if (AllowUserSignalHandlers) { - log_debug(jni, resolve)("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled"); - check_signals = false; - } + if (AllowUserSignalHandlers) { + log_debug(jni, resolve)("Info: AllowUserSignalHandlers is activated, all active signal checking is disabled"); + check_signals = false; } } } @@ -1354,9 +1421,7 @@ void PosixSignals::signal_sets_init() { sigaddset(&unblocked_sigs, SIGSEGV); sigaddset(&unblocked_sigs, SIGBUS); sigaddset(&unblocked_sigs, SIGFPE); - #if defined(PPC64) || defined(AIX) - sigaddset(&unblocked_sigs, SIGTRAP); - #endif + PPC64_ONLY(sigaddset(&unblocked_sigs, SIGTRAP);) sigaddset(&unblocked_sigs, SR_signum); if (!ReduceSignalUsage) { diff --git a/src/hotspot/os/posix/signals_posix.hpp b/src/hotspot/os/posix/signals_posix.hpp index 7194bd6c573..7f0f1b55884 100644 --- a/src/hotspot/os/posix/signals_posix.hpp +++ b/src/hotspot/os/posix/signals_posix.hpp @@ -38,7 +38,11 @@ class PosixSignals : public AllStatic { public: - static bool are_signal_handlers_installed(); + // The platform dependent parts of the central hotspot signal handler. + // Returns true if the signal had been recognized and handled, false if not. If true, caller should + // return from signal handling. + static bool pd_hotspot_signal_handler(int sig, siginfo_t* info, ucontext_t* uc, JavaThread* thread); + static void install_signal_handlers(); static bool is_sig_ignored(int sig); diff --git a/src/hotspot/os/windows/globals_windows.hpp b/src/hotspot/os/windows/globals_windows.hpp index a712e102a76..61157041f88 100644 --- a/src/hotspot/os/windows/globals_windows.hpp +++ b/src/hotspot/os/windows/globals_windows.hpp @@ -28,24 +28,25 @@ // // Declare Windows specific flags. They are not available on other platforms. // -#define RUNTIME_OS_FLAGS(develop, \ - develop_pd, \ - product, \ - product_pd, \ - notproduct, \ - range, \ - constraint) +#define RUNTIME_OS_FLAGS(develop, \ + develop_pd, \ + product, \ + product_pd, \ + notproduct, \ + range, \ + constraint) \ + \ +product(bool, UseOSErrorReporting, false, \ + "Let VM fatal error propagate to the OS (ie. WER on Windows)") // end of RUNTIME_OS_FLAGS - // // Defines Windows-specific default values. The flags are available on all // platforms, but they may have different default values on other platforms. // define_pd_global(bool, UseLargePages, false); define_pd_global(bool, UseLargePagesIndividualAllocation, true); -define_pd_global(bool, UseOSErrorReporting, false); // for now. define_pd_global(bool, UseThreadPriorities, true) ; #endif // OS_WINDOWS_GLOBALS_WINDOWS_HPP diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 99ac2c074f3..3b829cddac7 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -2144,6 +2144,8 @@ static int check_pending_signals() { } } while (threadIsSuspended); } + ShouldNotReachHere(); + return 0; // Satisfy compiler } int os::signal_wait() { @@ -2354,7 +2356,7 @@ static inline void report_error(Thread* t, DWORD exception_code, address addr, void* siginfo, void* context) { VMError::report_and_die(t, exception_code, addr, siginfo, context); - // If UseOsErrorReporting, this will return here and save the error file + // If UseOSErrorReporting, this will return here and save the error file // somewhere where we can find it in the minidump. } diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index ca1c74aeee2..f214eee454a 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -168,43 +168,8 @@ frame os::current_frame() { return os::get_sender_for_C_frame(&tmp); } -// Utility functions - -extern "C" JNIEXPORT int -JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrecognized) { - - ucontext_t* uc = (ucontext_t*) ucVoid; - - Thread* t = Thread::current_or_null_safe(); - - // Note: it's not uncommon that JNI code uses signal/sigset to install - // then restore certain signal handler (e.g. to temporarily block SIGPIPE, - // or have a SIGILL handler when detecting CPU type). When that happens, - // JVM_handle_aix_signal() might be invoked with junk info/ucVoid. To - // avoid unnecessary crash when libjsig is not preloaded, try handle signals - // that do not require siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return 1; - } else { - // Ignoring SIGPIPE - see bugs 4229104 - return 1; - } - } - - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (PosixSignals::are_signal_handlers_installed()) { - if (t != NULL) { - if(t->is_Java_thread()) { - thread = t->as_Java_thread(); - } - else if(t->is_VM_thread()) { - vmthread = (VMThread *)t; - } - } - } +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { // Decide if this trap can be handled by a stub. address stub = NULL; @@ -226,8 +191,8 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec } } - if (info == NULL || uc == NULL || thread == NULL && vmthread == NULL) { - goto run_chained_handler; + if (info == NULL || uc == NULL) { + return false; // Fatal error } // If we are a java thread... @@ -237,11 +202,11 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec if (sig == SIGSEGV && thread->is_in_full_stack(addr)) { // stack overflow if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { - return 1; // continue + return true; // continue } else if (stub != NULL) { goto run_stub; } else { - goto report_and_die; + return false; // Fatal error } } // end handle SIGSEGV inside stack boundaries @@ -281,17 +246,6 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec // happens rarely. In heap based and disjoint base compressd oop modes also loads // are used for null checks. - // A VM-related SIGILL may only occur if we are not in the zero page. - // On AIX, we get a SIGILL if we jump to 0x0 or to somewhere else - // in the zero page, because it is filled with 0x0. We ignore - // explicit SIGILLs in the zero page. - if (sig == SIGILL && (pc < (address) 0x200)) { - if (TraceTraps) { - tty->print_raw_cr("SIGILL happened inside zero page."); - } - goto report_and_die; - } - int stop_type = -1; // Handle signal from NativeJump::patch_verified_entry(). if (sig == SIGILL && nativeInstruction_at(pc)->is_sigill_zombie_not_entrant()) { @@ -384,10 +338,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type); } - va_list detail_args; - VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread, - pc, info, ucVoid, NULL, 0, 0); - va_end(detail_args); + return false; // Fatal error } else if (sig == SIGBUS) { @@ -403,7 +354,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec } next_pc = SharedRuntime::handle_unsafe_access(thread, next_pc); os::Aix::ucontext_set_pc(uc, next_pc); - return 1; + return true; } } } @@ -428,7 +379,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec } next_pc = SharedRuntime::handle_unsafe_access(thread, next_pc); os::Aix::ucontext_set_pc(uc, next_pc); - return 1; + return true; } } @@ -450,32 +401,10 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec // Save all thread context in case we need to restore it. if (thread != NULL) thread->set_saved_exception_pc(pc); os::Aix::ucontext_set_pc(uc, stub); - return 1; - } - -run_chained_handler: - - // signal-chaining - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return 1; + return true; } - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return 0; - } - -report_and_die: - // Use sigthreadmask instead of sigprocmask on AIX and unmask current signal. - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigthreadmask(SIG_UNBLOCK, &newset, NULL); - - VMError::report_and_die(t, sig, pc, info, ucVoid); - - ShouldNotReachHere(); - return 0; + return false; // Fatal error } void os::Aix::init_thread_fpu_state(void) { diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp index c714640f73b..0b1a2424d2b 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -385,56 +385,14 @@ frame os::current_frame() { } } -// Utility functions - // From IA32 System Programming Guide enum { trap_page_fault = 0xE }; -extern "C" JNIEXPORT int -JVM_handle_bsd_signal(int sig, - siginfo_t* info, - void* ucVoid, - int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; - - Thread* t = Thread::current_or_null_safe(); - - // If crash protection is installed we may longjmp away and no destructors - // for objects in this scope will be run. - // So don't use any RAII utilities before crash protection is checked. - os::ThreadCrashProtection::check_crash_protection(sig, t); - - // Note: it's not uncommon that JNI code uses signal/sigset to install - // then restore certain signal handler (e.g. to temporarily block SIGPIPE, - // or have a SIGILL handler when detecting CPU type). When that happens, - // JVM_handle_bsd_signal() might be invoked with junk info/ucVoid. To - // avoid unnecessary crash when libjsig is not preloaded, try handle signals - // that do not require siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - // allow chained handler to go first - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 - return true; - } - } +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (PosixSignals::are_signal_handlers_installed()) { - if (t != NULL ){ - if(t->is_Java_thread()) { - thread = t->as_Java_thread(); - } - else if(t->is_VM_thread()){ - vmthread = (VMThread *)t; - } - } - } /* NOTE: does not seem to work on bsd. if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { @@ -455,7 +413,7 @@ JVM_handle_bsd_signal(int sig, if (StubRoutines::is_safefetch_fault(pc)) { os::Bsd::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return 1; + return true; } // Handle ALL stack overflow variations here @@ -466,7 +424,7 @@ JVM_handle_bsd_signal(int sig, if (thread->is_in_full_stack(addr)) { // stack overflow if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { - return 1; // continue + return true; // continue } } } @@ -549,7 +507,7 @@ JVM_handle_bsd_signal(int sig, int op = pc[0]; if (op == 0xDB) { // FIST - // TODO: The encoding of D2I in i486.ad can cause an exception + // TODO: The encoding of D2I in x86_32.ad can cause an exception // prior to the fist instruction if there was an invalid operation // pending. We want to dismiss that exception. From the win_32 // side it also seems that if it really was the fist causing @@ -678,29 +636,6 @@ JVM_handle_bsd_signal(int sig, return true; } - // signal-chaining - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - - if (pc == NULL && uc != NULL) { - pc = os::Bsd::ucontext_get_pc(uc); - } - - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); - - VMError::report_and_die(t, sig, pc, info, ucVoid); - - ShouldNotReachHere(); return false; } diff --git a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp index ec7d8e78970..1ab2001f5ab 100644 --- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp @@ -115,16 +115,10 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(); } -extern "C" JNIEXPORT int -JVM_handle_bsd_signal(int sig, - siginfo_t* info, - void* ucVoid, - int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { - Thread* t = Thread::current_or_null_safe(); - - // handle SafeFetch faults + // handle SafeFetch faults the zero way if (sig == SIGSEGV || sig == SIGBUS) { sigjmp_buf* const pjb = get_jmp_buf_for_continuation(); if (pjb) { @@ -132,37 +126,6 @@ JVM_handle_bsd_signal(int sig, } } - // Note: it's not uncommon that JNI code uses signal/sigset to - // install then restore certain signal handler (e.g. to temporarily - // block SIGPIPE, or have a SIGILL handler when detecting CPU - // type). When that happens, JVM_handle_bsd_signal() might be - // invoked with junk info/ucVoid. To avoid unnecessary crash when - // libjsig is not preloaded, try handle signals that do not require - // siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - // allow chained handler to go first - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 - return true; - } - } - - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (PosixSignals::are_signal_handlers_installed()) { - if (t != NULL ){ - if(t->is_Java_thread()) { - thread = t->as_Java_thread(); - } - else if(t->is_VM_thread()){ - vmthread = (VMThread *)t; - } - } - } - if (info != NULL && thread != NULL) { // Handle ALL stack overflow variations here if (sig == SIGSEGV || sig == SIGBUS) { @@ -202,36 +165,6 @@ JVM_handle_bsd_signal(int sig, }*/ } - // signal-chaining - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - -#ifndef PRODUCT - if (sig == SIGSEGV) { - fatal("\n#" - "\n# /--------------------\\" - "\n# | segmentation fault |" - "\n# \\---\\ /--------------/" - "\n# /" - "\n# [-] |\\_/| " - "\n# (+)=C |o o|__ " - "\n# | | =-*-=__\\ " - "\n# OOO c_c_(___)"); - } -#endif // !PRODUCT - - const char *fmt = - "caught unhandled signal " INT32_FORMAT " at address " PTR_FORMAT; - char buf[128]; - - sprintf(buf, fmt, sig, info->si_addr); - fatal(buf); return false; } diff --git a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp index 935ab39ad86..9ba2179a80c 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -164,57 +164,9 @@ NOINLINE frame os::current_frame() { } } -extern "C" JNIEXPORT int -JVM_handle_linux_signal(int sig, - siginfo_t* info, - void* ucVoid, - int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; - - Thread* t = Thread::current_or_null_safe(); - - // If crash protection is installed we may longjmp away and no destructors - // for objects in this scope will be run. - // So don't use any RAII utilities before crash protection is checked. - os::ThreadCrashProtection::check_crash_protection(sig, t); - - // Note: it's not uncommon that JNI code uses signal/sigset to install - // then restore certain signal handler (e.g. to temporarily block SIGPIPE, - // or have a SIGILL handler when detecting CPU type). When that happens, - // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To - // avoid unnecessary crash when libjsig is not preloaded, try handle signals - // that do not require siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - // allow chained handler to go first - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 - return true; - } - } - -#ifdef CAN_SHOW_REGISTERS_ON_ASSERT - if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) { - if (handle_assert_poison_fault(ucVoid, info->si_addr)) { - return 1; - } - } -#endif +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (PosixSignals::are_signal_handlers_installed()) { - if (t != NULL ){ - if(t->is_Java_thread()) { - thread = t->as_Java_thread(); - } - else if(t->is_VM_thread()){ - vmthread = (VMThread *)t; - } - } - } /* NOTE: does not seem to work on linux. if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { @@ -235,7 +187,7 @@ JVM_handle_linux_signal(int sig, if (StubRoutines::is_safefetch_fault(pc)) { os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return 1; + return true; } address addr = (address) info->si_addr; @@ -250,7 +202,7 @@ JVM_handle_linux_signal(int sig, // check if fault address is within thread stack if (thread->is_in_full_stack(addr)) { if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { - return 1; // continue + return true; // continue } } } @@ -293,10 +245,7 @@ JVM_handle_linux_signal(int sig, tty->print_cr("trap: %s: (SIGILL)", msg); } - va_list detail_args; - VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread, - pc, info, ucVoid, NULL, 0, 0); - va_end(detail_args); + return false; // Fatal error } else @@ -342,30 +291,8 @@ JVM_handle_linux_signal(int sig, return true; } - // signal-chaining - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - - if (pc == NULL && uc != NULL) { - pc = os::Linux::ucontext_get_pc(uc); - } - - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); - - VMError::report_and_die(t, sig, pc, info, ucVoid); + return false; // Mute compiler - ShouldNotReachHere(); - return true; // Mute compiler } void os::Linux::init_thread_fpu_state(void) { diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp index 271d1194720..41733be6ca3 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -241,18 +241,9 @@ address check_vfp3_32_fault_instr = NULL; address check_simd_fault_instr = NULL; address check_mp_ext_fault_instr = NULL; -// Utility functions -extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info, - void* ucVoid, int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; - - Thread* t = Thread::current_or_null_safe(); - - // If crash protection is installed we may longjmp away and no destructors - // for objects in this scope will be run. - // So don't use any RAII utilities before crash protection is checked. - os::ThreadCrashProtection::check_crash_protection(sig, t); +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { if (sig == SIGILL && ((info->si_addr == (caddr_t)check_simd_fault_instr) @@ -266,44 +257,6 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info, return true; } - // Note: it's not uncommon that JNI code uses signal/sigset to install - // then restore certain signal handler (e.g. to temporarily block SIGPIPE, - // or have a SIGILL handler when detecting CPU type). When that happens, - // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To - // avoid unnecessary crash when libjsig is not preloaded, try handle signals - // that do not require siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - // allow chained handler to go first - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 - return true; - } - } - -#ifdef CAN_SHOW_REGISTERS_ON_ASSERT - if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) { - if (handle_assert_poison_fault(ucVoid, info->si_addr)) { - return 1; - } - } -#endif - - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (PosixSignals::are_signal_handlers_installed()) { - if (t != NULL ){ - if(t->is_Java_thread()) { - thread = t->as_Java_thread(); - } - else if(t->is_VM_thread()){ - vmthread = (VMThread *)t; - } - } - } - address stub = NULL; address pc = NULL; bool unsafe_access = false; @@ -317,7 +270,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info, if (StubRoutines::is_safefetch_fault(pc)) { os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return 1; + return true; } // check if fault address is within thread stack if (thread->is_in_full_stack(addr)) { @@ -331,7 +284,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info, stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); } else { // Thread was in the vm or native code. Return and try to finish. - return 1; + return true; } } else if (overflow_state->in_stack_red_zone(addr)) { // Fatal red zone violation. Disable the guard pages and fall through @@ -347,7 +300,7 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info, thread->osthread()->set_expanding_stack(); if (os::Linux::manually_expand_stack(thread, addr)) { thread->osthread()->clear_expanding_stack(); - return 1; + return true; } thread->osthread()->clear_expanding_stack(); } else { @@ -440,30 +393,8 @@ extern "C" int JVM_handle_linux_signal(int sig, siginfo_t* info, return true; } - // signal-chaining - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - - if (pc == NULL && uc != NULL) { - pc = os::Linux::ucontext_get_pc(uc); - } - - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); - - VMError::report_and_die(t, sig, pc, info, ucVoid); - - ShouldNotReachHere(); return false; + } void os::Linux::init_thread_fpu_state(void) { diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp index 288e2a3ece6..ac4d1b72eb3 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp @@ -188,32 +188,8 @@ frame os::current_frame() { return os::get_sender_for_C_frame(&tmp); } -// Utility functions - -extern "C" JNIEXPORT int -JVM_handle_linux_signal(int sig, - siginfo_t* info, - void* ucVoid, - int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; - - Thread* t = Thread::current_or_null_safe(); - - // Note: it's not uncommon that JNI code uses signal/sigset to install - // then restore certain signal handler (e.g. to temporarily block SIGPIPE, - // or have a SIGILL handler when detecting CPU type). When that happens, - // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To - // avoid unnecessary crash when libjsig is not preloaded, try handle signals - // that do not require siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE - see bugs 4229104 - return true; - } - } +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { // Make the signal handler transaction-aware by checking the existence of a // second (transactional) context with MSR TS bits active. If the signal is @@ -237,26 +213,6 @@ JVM_handle_linux_signal(int sig, } } -#ifdef CAN_SHOW_REGISTERS_ON_ASSERT - if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) { - if (handle_assert_poison_fault(ucVoid, info->si_addr)) { - return 1; - } - } -#endif - - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (PosixSignals::are_signal_handlers_installed()) { - if (t != NULL) { - if(t->is_Java_thread()) { - thread = t->as_Java_thread(); - } else if(t->is_VM_thread()) { - vmthread = (VMThread *)t; - } - } - } - // Moved SafeFetch32 handling outside thread!=NULL conditional block to make // it work if no associated JavaThread object exists. if (uc) { @@ -297,7 +253,7 @@ JVM_handle_linux_signal(int sig, if (thread->is_in_full_stack(addr)) { // stack overflow if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { - return 1; // continue + return true; // continue } } } @@ -306,17 +262,6 @@ JVM_handle_linux_signal(int sig, // Java thread running in Java code => find exception handler if any // a fault inside compiled code, the interpreter, or a stub - // A VM-related SIGILL may only occur if we are not in the zero page. - // On AIX, we get a SIGILL if we jump to 0x0 or to somewhere else - // in the zero page, because it is filled with 0x0. We ignore - // explicit SIGILLs in the zero page. - if (sig == SIGILL && (pc < (address) 0x200)) { - if (TraceTraps) { - tty->print_raw_cr("SIGILL happened inside zero page."); - } - goto report_and_die; - } - CodeBlob *cb = NULL; int stop_type = -1; // Handle signal from NativeJump::patch_verified_entry(). @@ -404,10 +349,7 @@ JVM_handle_linux_signal(int sig, tty->print_cr("trap: %s: %s (SIGTRAP, stop type %d)", msg, detail_msg, stop_type); } - va_list detail_args; - VMError::report_and_die(INTERNAL_ERROR, msg, detail_msg, detail_args, thread, - pc, info, ucVoid, NULL, 0, 0); - va_end(detail_args); + return false; // Fatal error } else if (sig == SIGBUS) { @@ -465,31 +407,8 @@ JVM_handle_linux_signal(int sig, return true; } - // signal-chaining - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - - if (pc == NULL && uc != NULL) { - pc = os::Linux::ucontext_get_pc(uc); - } - -report_and_die: - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); - - VMError::report_and_die(t, sig, pc, info, ucVoid); - - ShouldNotReachHere(); return false; + } void os::Linux::init_thread_fpu_state(void) { diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index 64d5fd8d512..d3d73053089 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -204,59 +204,8 @@ frame os::current_frame() { } } -// Utility functions - -extern "C" JNIEXPORT int -JVM_handle_linux_signal(int sig, - siginfo_t* info, - void* ucVoid, - int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; - - Thread* t = Thread::current_or_null_safe(); - - // If crash protection is installed we may longjmp away and no destructors - // for objects in this scope will be run. - // So don't use any RAII utilities before crash protection is checked. - os::ThreadCrashProtection::check_crash_protection(sig, t); - - // Note: it's not uncommon that JNI code uses signal/sigset to install - // then restore certain signal handler (e.g. to temporarily block SIGPIPE, - // or have a SIGILL handler when detecting CPU type). When that happens, - // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To - // avoid unnecessary crash when libjsig is not preloaded, try handle signals - // that do not require siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } else { - if (PrintMiscellaneous && (WizardMode || Verbose)) { - warning("Ignoring SIGPIPE - see bug 4229104"); - } - return true; - } - } - -#ifdef CAN_SHOW_REGISTERS_ON_ASSERT - if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) { - if (handle_assert_poison_fault(ucVoid, info->si_addr)) { - return 1; - } - } -#endif - - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (PosixSignals::are_signal_handlers_installed()) { - if (t != NULL) { - if(t->is_Java_thread()) { - thread = t->as_Java_thread(); - } else if(t->is_VM_thread()) { - vmthread = (VMThread *)t; - } - } - } +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { // Moved SafeFetch32 handling outside thread!=NULL conditional block to make // it work if no associated JavaThread object exists. @@ -294,7 +243,7 @@ JVM_handle_linux_signal(int sig, if (thread->is_in_full_stack(addr)) { // stack overflow if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { - return 1; // continue + return true; // continue } } } @@ -418,38 +367,8 @@ JVM_handle_linux_signal(int sig, return true; } - // signal-chaining - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - - if (pc == NULL && uc != NULL) { - pc = os::Linux::ucontext_get_pc(uc); - } - - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); - - // Hand down correct pc for SIGILL, SIGFPE. pc from context - // usually points to the instruction after the failing instruction. - // Note: this should be combined with the trap_pc handling above, - // because it handles the same issue. - if (sig == SIGILL || sig == SIGFPE) { - pc = (address)info->si_addr; - } - - VMError::report_and_die(t, sig, pc, info, ucVoid); - - ShouldNotReachHere(); return false; + } void os::Linux::init_thread_fpu_state(void) { diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index 4204cbc50bd..6c977fc96f1 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -200,58 +200,10 @@ enum { trap_page_fault = 0xE }; -extern "C" JNIEXPORT int -JVM_handle_linux_signal(int sig, - siginfo_t* info, - void* ucVoid, - int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; - - Thread* t = Thread::current_or_null_safe(); - - // If crash protection is installed we may longjmp away and no destructors - // for objects in this scope will be run. - // So don't use any RAII utilities before crash protection is checked. - os::ThreadCrashProtection::check_crash_protection(sig, t); - - // Note: it's not uncommon that JNI code uses signal/sigset to install - // then restore certain signal handler (e.g. to temporarily block SIGPIPE, - // or have a SIGILL handler when detecting CPU type). When that happens, - // JVM_handle_linux_signal() might be invoked with junk info/ucVoid. To - // avoid unnecessary crash when libjsig is not preloaded, try handle signals - // that do not require siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - // allow chained handler to go first - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 - return true; - } - } - -#ifdef CAN_SHOW_REGISTERS_ON_ASSERT - if ((sig == SIGSEGV || sig == SIGBUS) && info != NULL && info->si_addr == g_assert_poison) { - if (handle_assert_poison_fault(ucVoid, info->si_addr)) { - return 1; - } - } -#endif +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (PosixSignals::are_signal_handlers_installed()) { - if (t != NULL ){ - if(t->is_Java_thread()) { - thread = t->as_Java_thread(); - } - else if(t->is_VM_thread()){ - vmthread = (VMThread *)t; - } - } - } -/* + /* NOTE: does not seem to work on linux. if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { // can't decode this kind of signal @@ -271,7 +223,7 @@ JVM_handle_linux_signal(int sig, if (StubRoutines::is_safefetch_fault(pc)) { os::Linux::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc)); - return 1; + return true; } #ifndef AMD64 @@ -292,7 +244,7 @@ JVM_handle_linux_signal(int sig, if (thread->is_in_full_stack(addr)) { // stack overflow if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { - return 1; // continue + return true; // continue } } } @@ -340,7 +292,7 @@ JVM_handle_linux_signal(int sig, int op = pc[0]; if (op == 0xDB) { // FIST - // TODO: The encoding of D2I in i486.ad can cause an exception + // TODO: The encoding of D2I in x86_32.ad can cause an exception // prior to the fist instruction if there was an invalid operation // pending. We want to dismiss that exception. From the win_32 // side it also seems that if it really was the fist causing @@ -469,30 +421,7 @@ JVM_handle_linux_signal(int sig, return true; } - // signal-chaining - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - - if (pc == NULL && uc != NULL) { - pc = os::Linux::ucontext_get_pc(uc); - } - - // unmask current signal - sigset_t newset; - sigemptyset(&newset); - sigaddset(&newset, sig); - sigprocmask(SIG_UNBLOCK, &newset, NULL); - - VMError::report_and_die(t, sig, pc, info, ucVoid); - - ShouldNotReachHere(); - return true; // Mute compiler + return false; } void os::Linux::init_thread_fpu_state(void) { diff --git a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp index 8f2c8b8bc16..8ff5ac61c5c 100644 --- a/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp +++ b/src/hotspot/os_cpu/linux_zero/os_linux_zero.cpp @@ -111,14 +111,8 @@ frame os::fetch_frame_from_context(const void* ucVoid) { return frame(NULL, NULL); // silence compile warnings } -extern "C" JNIEXPORT int -JVM_handle_linux_signal(int sig, - siginfo_t* info, - void* ucVoid, - int abort_if_unrecognized) { - ucontext_t* uc = (ucontext_t*) ucVoid; - - Thread* t = Thread::current_or_null_safe(); +bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, + ucontext_t* uc, JavaThread* thread) { // handle SafeFetch faults if (sig == SIGSEGV || sig == SIGBUS) { @@ -128,37 +122,6 @@ JVM_handle_linux_signal(int sig, } } - // Note: it's not uncommon that JNI code uses signal/sigset to - // install then restore certain signal handler (e.g. to temporarily - // block SIGPIPE, or have a SIGILL handler when detecting CPU - // type). When that happens, JVM_handle_linux_signal() might be - // invoked with junk info/ucVoid. To avoid unnecessary crash when - // libjsig is not preloaded, try handle signals that do not require - // siginfo/ucontext first. - - if (sig == SIGPIPE || sig == SIGXFSZ) { - // allow chained handler to go first - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } else { - // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219 - return true; - } - } - - JavaThread* thread = NULL; - VMThread* vmthread = NULL; - if (PosixSignals::are_signal_handlers_installed()) { - if (t != NULL ){ - if(t->is_Java_thread()) { - thread = t->as_Java_thread(); - } - else if(t->is_VM_thread()){ - vmthread = (VMThread *)t; - } - } - } - if (info != NULL && thread != NULL) { // Handle ALL stack overflow variations here if (sig == SIGSEGV) { @@ -216,47 +179,8 @@ JVM_handle_linux_signal(int sig, }*/ } - // signal-chaining - if (PosixSignals::chained_handler(sig, info, ucVoid)) { - return true; - } - - if (!abort_if_unrecognized) { - // caller wants another chance, so give it to him - return false; - } - -#ifndef PRODUCT - if (sig == SIGSEGV) { - fatal("\n#" - "\n# /--------------------\\" - "\n# | segmentation fault |" - "\n# \\---\\ /--------------/" - "\n# /" - "\n# [-] |\\_/| " - "\n# (+)=C |o o|__ " - "\n# | | =-*-=__\\ " - "\n# OOO c_c_(___)"); - } -#endif // !PRODUCT - - char buf[128]; - char exc_buf[32]; - - if (os::exception_name(sig, exc_buf, sizeof(exc_buf))) { - bool sent_by_kill = (info != NULL && os::signal_sent_by_kill(info)); - snprintf(buf, sizeof(buf), "caught unhandled signal: %s %s", - exc_buf, sent_by_kill ? "(sent by kill)" : ""); - } else { - snprintf(buf, sizeof(buf), "caught unhandled signal: %d", sig); - } + return false; // Fatal error -// Silence -Wformat-security warning for fatal() -PRAGMA_DIAG_PUSH -PRAGMA_FORMAT_NONLITERAL_IGNORED - fatal(buf); -PRAGMA_DIAG_POP - return true; // silence compiler warnings } void os::Linux::init_thread_fpu_state(void) { diff --git a/src/hotspot/share/adlc/output_c.cpp b/src/hotspot/share/adlc/output_c.cpp index f4e6e295603..c6083533b58 100644 --- a/src/hotspot/share/adlc/output_c.cpp +++ b/src/hotspot/share/adlc/output_c.cpp @@ -3000,7 +3000,7 @@ void ArchDesc::define_oper_interface(FILE *fp, OperandForm &oper, FormDict &glob // Provide a non-NULL return for disp_as_type() that will allow adr_type() // to correctly compute the access type for alias analysis. // - // See BugId 4796752, operand indOffset32X in i486.ad + // See BugId 4796752, operand indOffset32X in x86_32.ad int idx = rep_var_to_constant_index(disp, oper, globals); fprintf(fp," virtual const TypePtr *disp_as_type() const { return _c%d; }\n", idx); } diff --git a/src/hotspot/share/asm/assembler.hpp b/src/hotspot/share/asm/assembler.hpp index a4c5d7d4554..8f76130522e 100644 --- a/src/hotspot/share/asm/assembler.hpp +++ b/src/hotspot/share/asm/assembler.hpp @@ -431,22 +431,6 @@ class AbstractAssembler : public ResourceObj { return ptr; } - // Bootstrapping aid to cope with delayed determination of constants. - // Returns a static address which will eventually contain the constant. - // The value zero (NULL) stands instead of a constant which is still uncomputed. - // Thus, the eventual value of the constant must not be zero. - // This is fine, since this is designed for embedding object field - // offsets in code which must be generated before the object class is loaded. - // Field offsets are never zero, since an object's header (mark word) - // is located at offset zero. - RegisterOrConstant delayed_value(int(*value_fn)(), Register tmp, int offset = 0); - RegisterOrConstant delayed_value(address(*value_fn)(), Register tmp, int offset = 0); - virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset) = 0; - // Last overloading is platform-dependent; look in assembler_.cpp. - static intptr_t* delayed_value_addr(int(*constant_fn)()); - static intptr_t* delayed_value_addr(address(*constant_fn)()); - static void update_delayed_values(); - // Bang stack to trigger StackOverflowError at a safe location // implementation delegates to machine-specific bang_stack_with_offset void generate_stack_overflow_check( int frame_size_in_bytes ); diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 95f16ce9fc8..59beb8d497a 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -1627,14 +1627,13 @@ class ClassFileParser::FieldAllocationCount : public ResourceObj { } } - FieldAllocationType update(bool is_static, BasicType type, bool is_inline_type) { + void update(bool is_static, BasicType type, bool is_inline_type) { FieldAllocationType atype = basic_type_to_atype(is_static, type, is_inline_type); if (atype != BAD_ALLOCATION_TYPE) { // Make sure there is no overflow with injected fields. assert(count[atype] < 0xFFFF, "More than 65535 fields"); count[atype]++; } - return atype; } }; @@ -1802,7 +1801,7 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, const BasicType type = cp->basic_type_for_signature_at(signature_index); - // // Remember how many oops we encountered + // Update FieldAllocationCount for this kind of field fac->update(is_static, type, type == T_INLINE_TYPE); // After field is initialized with type, we can augment it with aux info @@ -1846,7 +1845,7 @@ void ClassFileParser::parse_fields(const ClassFileStream* const cfs, const BasicType type = Signature::basic_type(injected[n].signature()); - // Remember how many oops we encountered + // Update FieldAllocationCount for this kind of field fac->update(false, type, false); index++; _restricted_field_info->append(0); diff --git a/src/hotspot/share/classfile/classListParser.cpp b/src/hotspot/share/classfile/classListParser.cpp index c978b8b8e25..4db3b7e132a 100644 --- a/src/hotspot/share/classfile/classListParser.cpp +++ b/src/hotspot/share/classfile/classListParser.cpp @@ -487,7 +487,6 @@ bool ClassListParser::is_matching_cp_entry(constantPoolHandle &pool, int cp_inde } void ClassListParser::resolve_indy(Symbol* class_name_symbol, TRAPS) { - Handle class_loader(THREAD, SystemDictionary::java_system_loader()); Handle protection_domain; Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, protection_domain, true, THREAD); // FIXME should really be just a lookup @@ -508,8 +507,8 @@ void ClassListParser::resolve_indy(Symbol* class_name_symbol, TRAPS) { BootstrapInfo bootstrap_specifier(pool, pool_index, indy_index); Handle bsm = bootstrap_specifier.resolve_bsm(THREAD); if (!SystemDictionaryShared::is_supported_invokedynamic(&bootstrap_specifier)) { - tty->print_cr("is_supported_invokedynamic check failed for cp_index %d", pool_index); - continue; + log_debug(cds, lambda)("is_supported_invokedynamic check failed for cp_index %d", pool_index); + continue; } if (is_matching_cp_entry(pool, pool_index, THREAD)) { found = true; diff --git a/src/hotspot/share/classfile/lambdaFormInvokers.cpp b/src/hotspot/share/classfile/lambdaFormInvokers.cpp index ca7dc211e32..5d3a0316582 100644 --- a/src/hotspot/share/classfile/lambdaFormInvokers.cpp +++ b/src/hotspot/share/classfile/lambdaFormInvokers.cpp @@ -147,5 +147,5 @@ void LambdaFormInvokers::reload_class(char* name, ClassFileStream& st, TRAPS) { // exclude the existing class from dump SystemDictionaryShared::set_excluded(InstanceKlass::cast(klass)); - log_info(cds)("Replaced class %s, old: %p new: %p", name, klass, result); + log_info(cds, lambda)("Replaced class %s, old: %p new: %p", name, klass, result); } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index 2cd54604d5b..37236801927 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -40,6 +40,7 @@ #include "interpreter/bootstrapInfo.hpp" #include "jfr/jfrEvents.hpp" #include "logging/log.hpp" +#include "logging/logStream.hpp" #include "memory/allocation.hpp" #include "memory/archiveUtils.hpp" #include "memory/dynamicArchive.hpp" @@ -1924,26 +1925,28 @@ bool SystemDictionaryShared::check_linking_constraints(InstanceKlass* klass, TRA } bool SystemDictionaryShared::is_supported_invokedynamic(BootstrapInfo* bsi) { + LogTarget(Debug, cds, lambda) log; if (bsi->arg_values() == NULL || !bsi->arg_values()->is_objArray()) { - DEBUG_ONLY( - tty->print_cr("bsi check failed"); - tty->print_cr(" bsi->arg_values().not_null() %d", bsi->arg_values().not_null()); + if (log.is_enabled()) { + LogStream log_stream(log); + log.print("bsi check failed"); + log.print(" bsi->arg_values().not_null() %d", bsi->arg_values().not_null()); if (bsi->arg_values().not_null()) { - tty->print_cr(" bsi->arg_values()->is_objArray() %d", bsi->arg_values()->is_objArray()); - bsi->print(); + log.print(" bsi->arg_values()->is_objArray() %d", bsi->arg_values()->is_objArray()); + bsi->print_msg_on(&log_stream); } - ) + } return false; } Handle bsm = bsi->bsm(); if (bsm.is_null() || !java_lang_invoke_DirectMethodHandle::is_instance(bsm())) { - DEBUG_ONLY( - tty->print_cr("bsm check failed"); - tty->print_cr(" bsm.is_null() %d", bsm.is_null()); - tty->print_cr(" java_lang_invoke_DirectMethodHandle::is_instance(bsm()) %d", + if (log.is_enabled()) { + log.print("bsm check failed"); + log.print(" bsm.is_null() %d", bsm.is_null()); + log.print(" java_lang_invoke_DirectMethodHandle::is_instance(bsm()) %d", java_lang_invoke_DirectMethodHandle::is_instance(bsm())); - ) + } return false; } @@ -1954,13 +1957,13 @@ bool SystemDictionaryShared::is_supported_invokedynamic(BootstrapInfo* bsi) { method->signature()->equals("(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;")) { return true; } else { - DEBUG_ONLY( + if (log.is_enabled()) { ResourceMark rm; - tty->print_cr("method check failed"); - tty->print_cr(" klass_name() %s", method->klass_name()->as_C_string()); - tty->print_cr(" name() %s", method->name()->as_C_string()); - tty->print_cr(" signature() %s", method->signature()->as_C_string()); - ) + log.print("method check failed"); + log.print(" klass_name() %s", method->klass_name()->as_C_string()); + log.print(" name() %s", method->name()->as_C_string()); + log.print(" signature() %s", method->signature()->as_C_string()); + } } return false; diff --git a/src/hotspot/share/compiler/compiler_globals.hpp b/src/hotspot/share/compiler/compiler_globals.hpp index 51ac7179bb0..c28c0e86eb5 100644 --- a/src/hotspot/share/compiler/compiler_globals.hpp +++ b/src/hotspot/share/compiler/compiler_globals.hpp @@ -38,7 +38,6 @@ #if !defined(COMPILER1) && !defined(COMPILER2) && !INCLUDE_JVMCI define_pd_global(bool, BackgroundCompilation, false); -define_pd_global(bool, UseTLAB, false); define_pd_global(bool, CICompileOSR, false); define_pd_global(bool, UseTypeProfile, false); define_pd_global(bool, UseOnStackReplacement, false); @@ -51,7 +50,6 @@ define_pd_global(bool, TieredCompilation, false); define_pd_global(intx, CompileThreshold, 0); define_pd_global(intx, OnStackReplacePercentage, 0); -define_pd_global(bool, ResizeTLAB, false); define_pd_global(size_t, NewSizeThreadIncrease, 4*K); define_pd_global(bool, InlineClassNatives, true); define_pd_global(bool, InlineUnsafeOps, true); diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index c20b4400cad..1bf55c51579 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -398,15 +398,8 @@ size_t G1PLABAllocator::undo_waste() const { return result; } -bool G1ArchiveAllocator::_archive_check_enabled = false; -G1ArchiveRegionMap G1ArchiveAllocator::_archive_region_map; - G1ArchiveAllocator* G1ArchiveAllocator::create_allocator(G1CollectedHeap* g1h, bool open) { - // Create the archive allocator, and also enable archive object checking - // in mark-sweep, since we will be creating archive regions. - G1ArchiveAllocator* result = new G1ArchiveAllocator(g1h, open); - enable_archive_object_check(); - return result; + return new G1ArchiveAllocator(g1h, open); } bool G1ArchiveAllocator::alloc_new_region() { @@ -434,9 +427,6 @@ bool G1ArchiveAllocator::alloc_new_region() { _bottom = hr->bottom(); _max = _bottom + HeapRegion::min_region_size_in_words(); - // Tell mark-sweep that objects in this region are not to be marked. - set_range_archive(MemRegion(_bottom, HeapRegion::GrainWords), _open); - // Since we've modified the old set, call update_sizes. _g1h->g1mm()->update_sizes(); return true; diff --git a/src/hotspot/share/gc/g1/g1Allocator.hpp b/src/hotspot/share/gc/g1/g1Allocator.hpp index 4346171466f..fdd3f90d4a2 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.hpp @@ -192,19 +192,6 @@ class G1PLABAllocator : public CHeapObj { void undo_allocation(G1HeapRegionAttr dest, HeapWord* obj, size_t word_sz, uint node_index); }; -// G1ArchiveRegionMap is an array used to mark G1 regions as -// archive regions. This allows a quick check for whether an object -// should not be marked because it is in an archive region. -class G1ArchiveRegionMap : public G1BiasedMappedArray { -public: - static const uint8_t NoArchive = 0; - static const uint8_t OpenArchive = 1; - static const uint8_t ClosedArchive = 2; - -protected: - uint8_t default_value() const { return NoArchive; } -}; - // G1ArchiveAllocator is used to allocate memory in archive // regions. Such regions are not scavenged nor compacted by GC. // There are two types of archive regions, which are @@ -278,33 +265,6 @@ class G1ArchiveAllocator : public CHeapObj { void clear_used() { _summary_bytes_used = 0; } - - // Create the _archive_region_map which is used to identify archive objects. - static inline void enable_archive_object_check(); - - // Mark regions containing the specified address range as archive/non-archive. - static inline void set_range_archive(MemRegion range, bool open); - static inline void clear_range_archive(MemRegion range); - - // Check if the object is in closed archive - static inline bool is_closed_archive_object(oop object); - // Check if the object is in open archive - static inline bool is_open_archive_object(oop object); - // Check if the object is either in closed archive or open archive - static inline bool is_archived_object(oop object); - -private: - static bool _archive_check_enabled; - static G1ArchiveRegionMap _archive_region_map; - - // Check if an object is in a closed archive region using the _closed_archive_region_map. - static inline bool in_closed_archive_range(oop object); - // Check if an object is in open archive region using the _open_archive_region_map. - static inline bool in_open_archive_range(oop object); - - // Check if archive object checking is enabled, to avoid calling in_open/closed_archive_range - // unnecessarily. - static inline bool archive_check_enabled(); }; #endif // SHARE_GC_G1_G1ALLOCATOR_HPP diff --git a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp index 6d484292051..73a07828378 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp @@ -119,63 +119,4 @@ inline HeapWord* G1PLABAllocator::allocate(G1HeapRegionAttr dest, return allocate_direct_or_new_plab(dest, word_sz, refill_failed, node_index); } -// Create the maps which is used to identify archive objects. -inline void G1ArchiveAllocator::enable_archive_object_check() { - if (_archive_check_enabled) { - return; - } - - _archive_check_enabled = true; - _archive_region_map.initialize(G1CollectedHeap::heap()->reserved(), - HeapRegion::GrainBytes); -} - -// Set the regions containing the specified address range as archive. -inline void G1ArchiveAllocator::set_range_archive(MemRegion range, bool open) { - assert(_archive_check_enabled, "archive range check not enabled"); - log_info(gc, cds)("Mark %s archive regions in map: [" PTR_FORMAT ", " PTR_FORMAT "]", - open ? "open" : "closed", - p2i(range.start()), - p2i(range.last())); - uint8_t const value = open ? G1ArchiveRegionMap::OpenArchive : G1ArchiveRegionMap::ClosedArchive; - _archive_region_map.set_by_address(range, value); -} - -// Clear the archive regions map containing the specified address range. -inline void G1ArchiveAllocator::clear_range_archive(MemRegion range) { - assert(_archive_check_enabled, "archive range check not enabled"); - log_info(gc, cds)("Clear archive regions in map: [" PTR_FORMAT ", " PTR_FORMAT "]", - p2i(range.start()), - p2i(range.last())); - _archive_region_map.set_by_address(range, G1ArchiveRegionMap::NoArchive); -} - -// Check if an object is in a closed archive region using the _archive_region_map. -inline bool G1ArchiveAllocator::in_closed_archive_range(oop object) { - return _archive_region_map.get_by_address(cast_from_oop(object)) == G1ArchiveRegionMap::ClosedArchive; -} - -inline bool G1ArchiveAllocator::in_open_archive_range(oop object) { - return _archive_region_map.get_by_address(cast_from_oop(object)) == G1ArchiveRegionMap::OpenArchive; -} - -// Check if archive object checking is enabled, to avoid calling in_open/closed_archive_range -// unnecessarily. -inline bool G1ArchiveAllocator::archive_check_enabled() { - return _archive_check_enabled; -} - -inline bool G1ArchiveAllocator::is_closed_archive_object(oop object) { - return (archive_check_enabled() && in_closed_archive_range(object)); -} - -inline bool G1ArchiveAllocator::is_open_archive_object(oop object) { - return (archive_check_enabled() && in_open_archive_range(object)); -} - -inline bool G1ArchiveAllocator::is_archived_object(oop object) { - return archive_check_enabled() && - (_archive_region_map.get_by_address(cast_from_oop(object)) != G1ArchiveRegionMap::NoArchive); -} - #endif // SHARE_GC_G1_G1ALLOCATOR_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index d4400135b92..70b534b6ff1 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -570,10 +570,6 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, // when mmap'ing archived heap data in, so pre-touching is wasted. FlagSetting fs(AlwaysPreTouch, false); - // Enable archive object checking used by G1MarkSweep. We have to let it know - // about each archive range, so that objects in those ranges aren't marked. - G1ArchiveAllocator::enable_archive_object_check(); - // For each specified MemRegion range, allocate the corresponding G1 // regions and mark them as archive regions. We expect the ranges // in ascending starting address order, without overlap. @@ -649,9 +645,6 @@ bool G1CollectedHeap::alloc_archive_regions(MemRegion* ranges, curr_region->set_top(top); curr_region = next_region; } - - // Notify mark-sweep of the archive - G1ArchiveAllocator::set_range_archive(curr_range, open); } return true; } @@ -802,9 +795,6 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion* ranges, size_t count) { _hrm->shrink_at(curr_index, 1); uncommitted_regions++; } - - // Notify mark-sweep that this is no longer an archive range. - G1ArchiveAllocator::clear_range_archive(ranges[i]); } if (uncommitted_regions != 0) { @@ -815,8 +805,7 @@ void G1CollectedHeap::dealloc_archive_regions(MemRegion* ranges, size_t count) { } oop G1CollectedHeap::materialize_archived_object(oop obj) { - assert(obj != NULL, "archived obj is NULL"); - assert(G1ArchiveAllocator::is_archived_object(obj), "must be archived object"); + assert(is_archived_object(obj), "not an archived obj"); // Loading an archived object makes it strongly reachable. If it is // loaded during concurrent marking, it must be enqueued to the SATB @@ -1016,8 +1005,7 @@ void G1CollectedHeap::prepare_heap_for_full_collection() { // after this full GC. abandon_collection_set(collection_set()); - tear_down_region_sets(false /* free_list_only */); - + hrm()->remove_all_free_regions(); hrm()->prepare_for_full_collection_start(); } @@ -1073,17 +1061,7 @@ void G1CollectedHeap::verify_after_full_collection() { _hrm->verify_optional(); _verifier->verify_region_sets_optional(); _verifier->verify_after_gc(G1HeapVerifier::G1VerifyFull); - // Clear the previous marking bitmap, if needed for bitmap verification. - // Note we cannot do this when we clear the next marking bitmap in - // G1ConcurrentMark::abort() above since VerifyDuringGC verifies the - // objects marked during a full GC against the previous bitmap. - // But we need to clear it before calling check_bitmaps below since - // the full GC has compacted objects and updated TAMS but not updated - // the prev bitmap. - if (G1VerifyBitmaps) { - GCTraceTime(Debug, gc) tm("Clear Prev Bitmap for Verification"); - _cm->clear_prev_bitmap(workers()); - } + // This call implicitly verifies that the next bitmap is clear after Full GC. _verifier->check_bitmaps("Full GC End"); @@ -1347,7 +1325,7 @@ void G1CollectedHeap::shrink(size_t shrink_bytes) { // Instead of tearing down / rebuilding the free lists here, we // could instead use the remove_all_pending() method on free_list to // remove only the ones that we need to remove. - tear_down_region_sets(true /* free_list_only */); + hrm()->remove_all_free_regions(); shrink_helper(shrink_bytes); rebuild_region_sets(true /* free_list_only */); @@ -2395,6 +2373,10 @@ bool G1CollectedHeap::is_heterogeneous_heap() const { return G1Arguments::is_heterogeneous_heap(); } +bool G1CollectedHeap::is_archived_object(oop object) const { + return object != NULL && heap_region_containing(object)->is_archive(); +} + class PrintRegionClosure: public HeapRegionClosure { outputStream* _st; public: @@ -2437,10 +2419,11 @@ void G1CollectedHeap::print_heap_regions() const { } void G1CollectedHeap::print_on(outputStream* st) const { + size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked(); st->print(" %-20s", "garbage-first heap"); if (_hrm != NULL) { st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K", - capacity()/K, used_unlocked()/K); + capacity()/K, heap_used/K); st->print(" [" PTR_FORMAT ", " PTR_FORMAT ")", p2i(_hrm->reserved().start()), p2i(_hrm->reserved().end())); @@ -4564,45 +4547,23 @@ bool G1CollectedHeap::check_young_list_empty() { #endif // ASSERT -class TearDownRegionSetsClosure : public HeapRegionClosure { - HeapRegionSet *_old_set; - -public: - TearDownRegionSetsClosure(HeapRegionSet* old_set) : _old_set(old_set) { } - - bool do_heap_region(HeapRegion* r) { - if (r->is_old()) { - _old_set->remove(r); - } else if(r->is_young()) { - r->uninstall_surv_rate_group(); - } else { - // We ignore free regions, we'll empty the free list afterwards. - // We ignore humongous and archive regions, we're not tearing down these - // sets. - assert(r->is_archive() || r->is_free() || r->is_humongous(), - "it cannot be another type"); - } - return false; - } - - ~TearDownRegionSetsClosure() { - assert(_old_set->is_empty(), "post-condition"); - } -}; - -void G1CollectedHeap::tear_down_region_sets(bool free_list_only) { - assert_at_safepoint_on_vm_thread(); - - if (!free_list_only) { - TearDownRegionSetsClosure cl(&_old_set); - heap_region_iterate(&cl); - + // Remove the given HeapRegion from the appropriate region set. +void G1CollectedHeap::prepare_region_for_full_compaction(HeapRegion* hr) { + if (hr->is_old()) { + _old_set.remove(hr); + } else if (hr->is_young()) { // Note that emptying the _young_list is postponed and instead done as // the first step when rebuilding the regions sets again. The reason for // this is that during a full GC string deduplication needs to know if // a collected region was young or old when the full GC was initiated. + hr->uninstall_surv_rate_group(); + } else { + // We ignore free regions, we'll empty the free list afterwards. + // We ignore humongous and archive regions, we're not tearing down these + // sets. + assert(hr->is_archive() || hr->is_free() || hr->is_humongous(), + "it cannot be another type"); } - _hrm->remove_all_free_regions(); } void G1CollectedHeap::increase_used(size_t bytes) { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 83f982f7c86..3048f9ceae1 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -177,20 +177,14 @@ class G1CollectedHeap : public CollectedHeap { // The block offset table for the G1 heap. G1BlockOffsetTable* _bot; - // Tears down the region sets / lists so that they are empty and the - // regions on the heap do not belong to a region set / list. The - // only exception is the humongous set which we leave unaltered. If - // free_list_only is true, it will only tear down the master free - // list. It is called before a Full GC (free_list_only == false) or - // before heap shrinking (free_list_only == true). - void tear_down_region_sets(bool free_list_only); +public: + void prepare_region_for_full_compaction(HeapRegion* hr); +private: // Rebuilds the region sets / lists so that they are repopulated to // reflect the contents of the heap. The only exception is the // humongous set which was not torn down in the first place. If - // free_list_only is true, it will only rebuild the master free - // list. It is called after a Full GC (free_list_only == false) or - // after heap shrinking (free_list_only == true). + // free_list_only is true, it will only rebuild the free list. void rebuild_region_sets(bool free_list_only); // Callback for region mapping changed events. @@ -1424,6 +1418,8 @@ class G1CollectedHeap : public CollectedHeap { virtual WorkGang* safepoint_workers() { return _workers; } + virtual bool is_archived_object(oop object) const; + // The methods below are here for convenience and dispatch the // appropriate method depending on value of the given VerifyOption // parameter. The values for that parameter, and their meanings, diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 310cb7bc066..d9904f2fc8f 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,12 @@ void G1CollectionSetCandidates::verify() const { for (; idx < _num_regions; idx++) { HeapRegion *cur = _regions[idx]; guarantee(cur != NULL, "Regions after _front_idx %u cannot be NULL but %u is", _front_idx, idx); - guarantee(G1CollectionSetChooser::should_add(cur), "Region %u should be eligible for addition.", cur->hrm_index()); + // The first disjunction filters out regions with objects that were explicitly + // pinned after being added to the collection set candidates. Archive regions + // should never have been added to the collection set though. + guarantee((cur->is_pinned() && !cur->is_archive()) || + G1CollectionSetChooser::should_add(cur), + "Region %u should be eligible for addition.", cur->hrm_index()); if (prev != NULL) { guarantee(prev->gc_efficiency() >= cur->gc_efficiency(), "GC efficiency for region %u: %1.4f smaller than for region %u: %1.4f", diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 35519e92fff..eca44ecdff9 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -675,9 +675,9 @@ void G1ConcurrentMark::cleanup_for_next_mark() { guarantee(!_g1h->collector_state()->mark_or_rebuild_in_progress(), "invariant"); } -void G1ConcurrentMark::clear_prev_bitmap(WorkGang* workers) { +void G1ConcurrentMark::clear_next_bitmap(WorkGang* workers) { assert_at_safepoint_on_vm_thread(); - clear_bitmap(_prev_mark_bitmap, workers, false); + clear_bitmap(_next_mark_bitmap, workers, false); } class NoteStartOfMarkHRClosure : public HeapRegionClosure { @@ -1132,6 +1132,8 @@ void G1ConcurrentMark::remark() { // Install newly created mark bitmap as "prev". swap_mark_bitmaps(); + + _g1h->collector_state()->set_clearing_next_bitmap(true); { GCTraceTime(Debug, gc, phases) debug("Update Remembered Set Tracking Before Rebuild", _gc_timer_cm); @@ -1696,7 +1698,6 @@ void G1ConcurrentMark::swap_mark_bitmaps() { G1CMBitMap* temp = _prev_mark_bitmap; _prev_mark_bitmap = _next_mark_bitmap; _next_mark_bitmap = temp; - _g1h->collector_state()->set_clearing_next_bitmap(true); } // Closure for marking entries in SATB buffers. @@ -1975,7 +1976,7 @@ void G1ConcurrentMark::concurrent_cycle_abort() { // concurrent bitmap clearing. { GCTraceTime(Debug, gc) debug("Clear Next Bitmap"); - clear_bitmap(_next_mark_bitmap, _g1h->workers(), false); + clear_next_bitmap(_g1h->workers()); } // Note we cannot clear the previous marking bitmap here // since VerifyDuringGC verifies the objects marked during diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp index 6ac83ba4953..2e0171a72ee 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp @@ -374,8 +374,6 @@ class G1ConcurrentMark : public CHeapObj { void report_object_count(bool mark_completed); - void swap_mark_bitmaps(); - void reclaim_empty_regions(); // After reclaiming empty regions, update heap sizes. @@ -539,8 +537,8 @@ class G1ConcurrentMark : public CHeapObj { // to be called concurrently to the mutator. It will yield to safepoint requests. void cleanup_for_next_mark(); - // Clear the previous marking bitmap during safepoint. - void clear_prev_bitmap(WorkGang* workers); + // Clear the next marking bitmap during safepoint. + void clear_next_bitmap(WorkGang* workers); // These two methods do the work that needs to be done at the start and end of the // concurrent start pause. @@ -563,6 +561,8 @@ class G1ConcurrentMark : public CHeapObj { void remark(); + void swap_mark_bitmaps(); + void cleanup(); // Mark in the previous bitmap. Caution: the prev bitmap is usually read-only, so use // this carefully. diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 9846ba62593..33cd49fff3d 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" #include "gc/g1/g1CollectedHeap.hpp" -#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullCollector.inline.hpp" #include "gc/g1/g1FullGCAdjustTask.hpp" #include "gc/g1/g1FullGCCompactTask.hpp" #include "gc/g1/g1FullGCMarker.inline.hpp" @@ -111,21 +111,23 @@ G1FullCollector::G1FullCollector(G1CollectedHeap* heap, bool explicit_gc, bool c _array_queue_set(_num_workers), _preserved_marks_set(true), _serial_compaction_point(), - _is_alive(heap->concurrent_mark()->next_mark_bitmap()), + _is_alive(this, heap->concurrent_mark()->next_mark_bitmap()), _is_alive_mutator(heap->ref_processor_stw(), &_is_alive), _always_subject_to_discovery(), - _is_subject_mutator(heap->ref_processor_stw(), &_always_subject_to_discovery) { + _is_subject_mutator(heap->ref_processor_stw(), &_always_subject_to_discovery), + _region_attr_table() { assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); _preserved_marks_set.init(_num_workers); _markers = NEW_C_HEAP_ARRAY(G1FullGCMarker*, _num_workers, mtGC); _compaction_points = NEW_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _num_workers, mtGC); for (uint i = 0; i < _num_workers; i++) { - _markers[i] = new G1FullGCMarker(i, _preserved_marks_set.get(i), mark_bitmap()); + _markers[i] = new G1FullGCMarker(this, i, _preserved_marks_set.get(i)); _compaction_points[i] = new G1FullGCCompactionPoint(); _oop_queue_set.register_queue(i, marker(i)->oop_stack()); _array_queue_set.register_queue(i, marker(i)->objarray_stack()); } + _region_attr_table.initialize(heap->reserved(), HeapRegion::GrainBytes); } G1FullCollector::~G1FullCollector() { @@ -137,6 +139,19 @@ G1FullCollector::~G1FullCollector() { FREE_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _compaction_points); } +class PrepareRegionsClosure : public HeapRegionClosure { + G1FullCollector* _collector; + +public: + PrepareRegionsClosure(G1FullCollector* collector) : _collector(collector) { } + + bool do_heap_region(HeapRegion* hr) { + G1CollectedHeap::heap()->prepare_region_for_full_compaction(hr); + _collector->update_attribute_table(hr); + return false; + } +}; + void G1FullCollector::prepare_collection() { _heap->policy()->record_full_collection_start(); @@ -149,6 +164,9 @@ void G1FullCollector::prepare_collection() { _heap->gc_prologue(true); _heap->prepare_heap_for_full_collection(); + PrepareRegionsClosure cl(this); + _heap->heap_region_iterate(&cl); + reference_processor()->enable_discovery(); reference_processor()->setup_policy(scope()->should_clear_soft_refs()); @@ -184,6 +202,10 @@ void G1FullCollector::complete_collection() { BiasedLocking::restore_marks(); + _heap->concurrent_mark()->swap_mark_bitmaps(); + // Prepare the bitmap for the next (potentially concurrent) marking. + _heap->concurrent_mark()->clear_next_bitmap(_heap->workers()); + _heap->prepare_heap_for_mutators(); _heap->policy()->record_full_collection_end(); @@ -194,6 +216,19 @@ void G1FullCollector::complete_collection() { _heap->print_heap_after_full_collection(scope()->heap_transition()); } +void G1FullCollector::update_attribute_table(HeapRegion* hr) { + if (hr->is_free()) { + return; + } + if (hr->is_closed_archive()) { + _region_attr_table.set_closed_archive(hr->hrm_index()); + } else if (hr->is_pinned()) { + _region_attr_table.set_pinned(hr->hrm_index()); + } else { + _region_attr_table.set_normal(hr->hrm_index()); + } +} + void G1FullCollector::phase1_mark_live_objects() { // Recursively traverse all live objects and mark them. GCTraceTime(Info, gc, phases) info("Phase 1: Mark live objects", scope()->timer()); diff --git a/src/hotspot/share/gc/g1/g1FullCollector.hpp b/src/hotspot/share/gc/g1/g1FullCollector.hpp index 9c21f65fc21..66b97ad40a7 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.hpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #define SHARE_GC_G1_G1FULLCOLLECTOR_HPP #include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCHeapRegionAttr.hpp" #include "gc/g1/g1FullGCMarker.hpp" #include "gc/g1/g1FullGCOopClosures.hpp" #include "gc/g1/g1FullGCScope.hpp" @@ -33,6 +34,7 @@ #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/taskqueue.hpp" #include "memory/allocation.hpp" +#include "oops/oopsHierarchy.hpp" class AbstractGangTask; class G1CMBitMap; @@ -71,6 +73,8 @@ class G1FullCollector : StackObj { G1FullGCSubjectToDiscoveryClosure _always_subject_to_discovery; ReferenceProcessorSubjectToDiscoveryMutator _is_subject_mutator; + G1FullGCHeapRegionAttr _region_attr_table; + public: G1FullCollector(G1CollectedHeap* heap, bool explicit_gc, bool clear_soft_refs); ~G1FullCollector(); @@ -90,6 +94,12 @@ class G1FullCollector : StackObj { G1CMBitMap* mark_bitmap(); ReferenceProcessor* reference_processor(); + void update_attribute_table(HeapRegion* hr); + + inline bool is_in_pinned_or_closed(oop obj) const; + inline bool is_in_pinned(oop obj) const; + inline bool is_in_closed(oop obj) const; + private: void phase1_mark_live_objects(); void phase2_prepare_compaction(); diff --git a/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp new file mode 100644 index 00000000000..1d45f67ed1a --- /dev/null +++ b/src/hotspot/share/gc/g1/g1FullCollector.inline.hpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_G1_G1FULLCOLLECTOR_INLINE_HPP +#define SHARE_GC_G1_G1FULLCOLLECTOR_INLINE_HPP + +#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullGCHeapRegionAttr.hpp" +#include "oops/oopsHierarchy.hpp" + +bool G1FullCollector::is_in_pinned_or_closed(oop obj) const { + return _region_attr_table.is_pinned_or_closed(cast_from_oop(obj)); +} + +bool G1FullCollector::is_in_pinned(oop obj) const { + return _region_attr_table.is_pinned(cast_from_oop(obj)); +} + +bool G1FullCollector::is_in_closed(oop obj) const { + return _region_attr_table.is_closed_archive(cast_from_oop(obj)); +} + +#endif // SHARE_GC_G1_G1FULLCOLLECTOR_INLINE_HPP + diff --git a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp index 3dfd30f67b2..ac5ba8834fb 100644 --- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,7 @@ #include "classfile/classLoaderDataGraph.hpp" #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" -#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullCollector.inline.hpp" #include "gc/g1/g1FullGCAdjustTask.hpp" #include "gc/g1/g1FullGCCompactionPoint.hpp" #include "gc/g1/g1FullGCMarker.hpp" @@ -51,27 +51,26 @@ class G1AdjustLiveClosure : public StackObj { }; class G1AdjustRegionClosure : public HeapRegionClosure { + G1FullCollector* _collector; G1CMBitMap* _bitmap; uint _worker_id; public: - G1AdjustRegionClosure(G1CMBitMap* bitmap, uint worker_id) : - _bitmap(bitmap), + G1AdjustRegionClosure(G1FullCollector* collector, uint worker_id) : + _collector(collector), + _bitmap(collector->mark_bitmap()), _worker_id(worker_id) { } bool do_heap_region(HeapRegion* r) { - G1AdjustClosure cl; + G1AdjustClosure cl(_collector); if (r->is_humongous()) { + // Special handling for humongous regions to get somewhat better + // work distribution. oop obj = oop(r->humongous_start_region()->bottom()); obj->oop_iterate(&cl, MemRegion(r->bottom(), r->top())); - } else if (r->is_open_archive()) { - // Only adjust the open archive regions, the closed ones - // never change. - G1AdjustLiveClosure adjust(&cl); - r->apply_to_marked_objects(_bitmap, &adjust); - // Open archive regions will not be compacted and the marking information is - // no longer needed. Clear it here to avoid having to do it later. - _bitmap->clear_region(r); - } else { + } else if (!r->is_closed_archive() && !r->is_free()) { + // Closed archive regions never change references and only contain + // references into other closed regions and are always live. Free + // regions do not contain objects to iterate. So skip both. G1AdjustLiveClosure adjust(&cl); r->apply_to_marked_objects(_bitmap, &adjust); } @@ -85,7 +84,7 @@ G1FullGCAdjustTask::G1FullGCAdjustTask(G1FullCollector* collector) : _references_done(0), _weak_proc_task(collector->workers()), _hrclaimer(collector->workers()), - _adjust(), + _adjust(collector), _string_dedup_cleaning_task(NULL, &_adjust, false) { // Need cleared claim bits for the roots processing ClassLoaderDataGraph::clear_claimed_marks(); @@ -116,7 +115,7 @@ void G1FullGCAdjustTask::work(uint worker_id) { _string_dedup_cleaning_task.work(worker_id); // Now adjust pointers region by region - G1AdjustRegionClosure blk(collector()->mark_bitmap(), worker_id); + G1AdjustRegionClosure blk(collector(), worker_id); G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&blk, &_hrclaimer, worker_id); log_task("Adjust task", worker_id, start); } diff --git a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp index be35978ba17..8a0a5c4c0eb 100644 --- a/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,27 +34,19 @@ #include "oops/oop.inline.hpp" #include "utilities/ticks.hpp" -class G1ResetHumongousClosure : public HeapRegionClosure { +class G1ResetPinnedClosure : public HeapRegionClosure { G1CMBitMap* _bitmap; public: - G1ResetHumongousClosure(G1CMBitMap* bitmap) : - _bitmap(bitmap) { } + G1ResetPinnedClosure(G1CMBitMap* bitmap) : _bitmap(bitmap) { } - bool do_heap_region(HeapRegion* current) { - if (current->is_humongous()) { - if (current->is_starts_humongous()) { - oop obj = oop(current->bottom()); - if (_bitmap->is_marked(obj)) { - // Clear bitmap and fix mark word. - _bitmap->clear(obj); - obj->init_mark(); - } else { - assert(current->is_empty(), "Should have been cleared in phase 2."); - } - } - current->reset_humongous_during_compaction(); + bool do_heap_region(HeapRegion* r) { + if (!r->is_pinned()) { + return false; } + assert(!r->is_starts_humongous() || _bitmap->is_marked((oop)r->bottom()), + "must be, otherwise reclaimed earlier"); + r->reset_pinned_after_full_gc(); return false; } }; @@ -78,13 +70,16 @@ size_t G1FullGCCompactTask::G1CompactRegionClosure::apply(oop obj) { } void G1FullGCCompactTask::compact_region(HeapRegion* hr) { + assert(!hr->is_pinned(), "Should be no pinned region in compaction queue"); assert(!hr->is_humongous(), "Should be no humongous regions in compaction queue"); G1CompactRegionClosure compact(collector()->mark_bitmap()); hr->apply_to_marked_objects(collector()->mark_bitmap(), &compact); - // Once all objects have been moved the liveness information - // needs be cleared. - collector()->mark_bitmap()->clear_region(hr); - hr->complete_compaction(); + // Clear the liveness information for this region if necessary i.e. if we actually look at it + // for bitmap verification. Otherwise it is sufficient that we move the TAMS to bottom(). + if (G1VerifyBitmaps) { + collector()->mark_bitmap()->clear_region(hr); + } + hr->reset_compacted_after_full_gc(); } void G1FullGCCompactTask::work(uint worker_id) { @@ -96,7 +91,7 @@ void G1FullGCCompactTask::work(uint worker_id) { compact_region(*it); } - G1ResetHumongousClosure hc(collector()->mark_bitmap()); + G1ResetPinnedClosure hc(collector()->mark_bitmap()); G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&hc, &_claimer, worker_id); log_task("Compaction task", worker_id, start); } diff --git a/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp new file mode 100644 index 00000000000..8297bd03811 --- /dev/null +++ b/src/hotspot/share/gc/g1/g1FullGCHeapRegionAttr.hpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCHEAPREGIONATTR_HPP +#define SHARE_GC_G1_G1FULLGCHEAPREGIONATTR_HPP + +#include "gc/g1/g1BiasedArray.hpp" + +// This table is used to store attribute values of all HeapRegions that need +// fast access during the full collection. In particular some parts of the region +// type information is encoded in these per-region bytes. +// Value encoding has been specifically chosen to make required accesses fast. +class G1FullGCHeapRegionAttr : public G1BiasedMappedArray { + static const uint8_t Normal = 0; // Other kind of region + static const uint8_t Pinned = 1; // Region is a pinned (non-Closed Archive) region + static const uint8_t ClosedArchive = 2; // Region is a (pinned) Closed Archive region + + STATIC_ASSERT(ClosedArchive > Pinned); + + static const uint8_t Invalid = 255; + + bool is_invalid(HeapWord* obj) const { + return get_by_address(obj) == Invalid; + } + +protected: + uint8_t default_value() const { return Invalid; } + +public: + void set_closed_archive(uint idx) { set_by_index(idx, ClosedArchive); } + + bool is_closed_archive(HeapWord* obj) const { + assert(!is_invalid(obj), "not initialized yet"); + return get_by_address(obj) == ClosedArchive; + } + + void set_pinned(uint idx) { set_by_index(idx, Pinned); } + + bool is_pinned_or_closed(HeapWord* obj) const { + assert(!is_invalid(obj), "not initialized yet"); + return get_by_address(obj) >= Pinned; + } + + bool is_pinned(HeapWord* obj) const { + assert(!is_invalid(obj), "not initialized yet"); + return get_by_address(obj) == Pinned; + } + + void set_normal(uint idx) { set_by_index(idx, Normal); } + + bool is_normal(HeapWord* obj) const { + assert(!is_invalid(obj), "not initialized yet"); + return get_by_address(obj) == Normal; + } +}; + +#endif // SHARE_GC_G1_G1FULLGCHEAPREGIONATTR_HPP diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp index 3bbf74adfc6..ed97bbfe949 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp @@ -30,9 +30,12 @@ #include "gc/shared/verifyOption.hpp" #include "memory/iterator.inline.hpp" -G1FullGCMarker::G1FullGCMarker(uint worker_id, PreservedMarks* preserved_stack, G1CMBitMap* bitmap) : +G1FullGCMarker::G1FullGCMarker(G1FullCollector* collector, + uint worker_id, + PreservedMarks* preserved_stack) : + _collector(collector), _worker_id(worker_id), - _bitmap(bitmap), + _bitmap(collector->mark_bitmap()), _oop_stack(), _objarray_stack(), _preserved_stack(preserved_stack), diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.hpp index fc130fdc66f..28b4946c359 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.hpp @@ -43,8 +43,11 @@ typedef GenericTaskQueueSet OopQueueSet; typedef GenericTaskQueueSet ObjArrayTaskQueueSet; class G1CMBitMap; +class G1FullCollector; class G1FullGCMarker : public CHeapObj { + G1FullCollector* _collector; + uint _worker_id; // Backing mark bitmap G1CMBitMap* _bitmap; @@ -71,7 +74,7 @@ class G1FullGCMarker : public CHeapObj { inline void follow_array(objArrayOop array); inline void follow_array_chunk(objArrayOop array, int index); public: - G1FullGCMarker(uint worker_id, PreservedMarks* preserved_stack, G1CMBitMap* bitmap); + G1FullGCMarker(G1FullCollector* collector, uint worker_id, PreservedMarks* preserved_stack); ~G1FullGCMarker(); // Stack getters diff --git a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp index 11a66dea934..75d8f656305 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp @@ -28,6 +28,7 @@ #include "classfile/javaClasses.inline.hpp" #include "gc/g1/g1Allocator.inline.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" +#include "gc/g1/g1FullCollector.inline.hpp" #include "gc/g1/g1FullGCMarker.hpp" #include "gc/g1/g1FullGCOopClosures.inline.hpp" #include "gc/g1/g1StringDedup.hpp" @@ -39,8 +40,7 @@ #include "utilities/debug.hpp" inline bool G1FullGCMarker::mark_object(oop obj) { - // Not marking closed archive objects. - if (G1ArchiveAllocator::is_closed_archive_object(obj)) { + if (_collector->is_in_closed(obj)) { return false; } @@ -53,7 +53,9 @@ inline bool G1FullGCMarker::mark_object(oop obj) { // Marked by us, preserve if needed. markWord mark = obj->mark(); if (obj->mark_must_be_preserved(mark) && - !G1ArchiveAllocator::is_open_archive_object(obj)) { + // It is not necessary to preserve marks for objects in pinned regions because + // we do not change their headers (i.e. forward them). + !_collector->is_in_pinned(obj)) { preserved_stack()->push(obj, mark); } @@ -73,7 +75,7 @@ template inline void G1FullGCMarker::mark_and_push(T* p) { _oop_stack.push(obj); assert(_bitmap->is_marked(obj), "Must be marked now - map self"); } else { - assert(_bitmap->is_marked(obj) || G1ArchiveAllocator::is_closed_archive_object(obj), + assert(_bitmap->is_marked(obj) || _collector->is_in_closed(obj), "Must be marked by other or closed archive object"); } } diff --git a/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp b/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp index 876def6f550..ba3b50e5a96 100644 --- a/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1FullCollector.hpp" #include "gc/g1/g1FullGCMarker.inline.hpp" #include "gc/g1/g1FullGCOopClosures.inline.hpp" #include "logging/logStream.hpp" @@ -32,6 +33,9 @@ #include "oops/compressedOops.inline.hpp" #include "oops/oop.inline.hpp" +G1IsAliveClosure::G1IsAliveClosure(G1FullCollector* collector) : + G1IsAliveClosure(collector, collector->mark_bitmap()) { } + void G1FollowStackClosure::do_void() { _marker->drain_stack(); } void G1FullKeepAliveClosure::do_oop(oop* p) { do_oop_work(p); } diff --git a/src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp b/src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp index baca67dabd2..1690c99ea24 100644 --- a/src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,10 +35,13 @@ class G1FullGCMarker; // Below are closures used by the G1 Full GC. class G1IsAliveClosure : public BoolObjectClosure { + G1FullCollector* _collector; G1CMBitMap* _bitmap; public: - G1IsAliveClosure(G1CMBitMap* bitmap) : _bitmap(bitmap) { } + G1IsAliveClosure(G1FullCollector* collector); + G1IsAliveClosure(G1FullCollector* collector, G1CMBitMap* bitmap) : + _collector(collector), _bitmap(bitmap) { } virtual bool do_object_b(oop p); }; @@ -75,8 +78,11 @@ class G1MarkAndPushClosure : public OopIterateClosure { }; class G1AdjustClosure : public BasicOopIterateClosure { - template static inline void adjust_pointer(T* p); + G1FullCollector* _collector; + + template inline void adjust_pointer(T* p); public: + G1AdjustClosure(G1FullCollector* collector) : _collector(collector) { } template void do_oop_work(T* p) { adjust_pointer(p); } virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); diff --git a/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp b/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp index 16c34eace8d..dfb56d50ca4 100644 --- a/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #define SHARE_GC_G1_G1FULLGCOOPCLOSURES_INLINE_HPP #include "gc/g1/g1Allocator.inline.hpp" +#include "gc/g1/g1FullCollector.inline.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" #include "gc/g1/g1FullGCMarker.inline.hpp" #include "gc/g1/g1FullGCOopClosures.hpp" @@ -69,8 +70,9 @@ template inline void G1AdjustClosure::adjust_pointer(T* p) { oop obj = CompressedOops::decode_not_null(heap_oop); assert(Universe::heap()->is_in(obj), "should be in heap"); - if (G1ArchiveAllocator::is_archived_object(obj)) { - // We never forward archive objects. + if (_collector->is_in_pinned_or_closed(obj)) { + // We never forward objects in pinned regions so there is no need to + // process them further. return; } @@ -94,7 +96,7 @@ inline void G1AdjustClosure::do_oop(oop* p) { do_oop_work(p); } inline void G1AdjustClosure::do_oop(narrowOop* p) { do_oop_work(p); } inline bool G1IsAliveClosure::do_object_b(oop p) { - return _bitmap->is_marked(p) || G1ArchiveAllocator::is_closed_archive_object(p); + return _bitmap->is_marked(p) || _collector->is_in_closed(p); } template diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp index 3658ae200d9..732a040ffb0 100644 --- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,22 +40,28 @@ #include "utilities/ticks.hpp" bool G1FullGCPrepareTask::G1CalculatePointersClosure::do_heap_region(HeapRegion* hr) { - if (hr->is_humongous()) { - oop obj = oop(hr->humongous_start_region()->bottom()); - if (_bitmap->is_marked(obj)) { - if (hr->is_starts_humongous()) { - obj->forward_to(obj); + if (hr->is_pinned()) { + // There is no need to iterate and forward objects in pinned regions ie. + // prepare them for compaction. The adjust pointers phase will skip + // work for them. + if (hr->is_humongous()) { + oop obj = oop(hr->humongous_start_region()->bottom()); + if (!_bitmap->is_marked(obj)) { + free_humongous_region(hr); } } else { - free_humongous_region(hr); + assert(hr->is_archive(), "Only archive regions can also be pinned."); } - } else if (!hr->is_pinned()) { + } else { + assert(!hr->is_humongous(), "moving humongous objects not supported."); prepare_for_compaction(hr); } // Reset data structures not valid after Full GC. reset_region_metadata(hr); + _collector->update_attribute_table(hr); + return false; } @@ -78,7 +84,7 @@ bool G1FullGCPrepareTask::has_freed_regions() { void G1FullGCPrepareTask::work(uint worker_id) { Ticks start = Ticks::now(); G1FullGCCompactionPoint* compaction_point = collector()->compaction_point(worker_id); - G1CalculatePointersClosure closure(collector()->mark_bitmap(), compaction_point); + G1CalculatePointersClosure closure(collector(), compaction_point); G1CollectedHeap::heap()->heap_region_par_iterate_from_start(&closure, &_hrclaimer); // Update humongous region sets @@ -92,15 +98,18 @@ void G1FullGCPrepareTask::work(uint worker_id) { log_task("Prepare compaction task", worker_id, start); } -G1FullGCPrepareTask::G1CalculatePointersClosure::G1CalculatePointersClosure(G1CMBitMap* bitmap, +G1FullGCPrepareTask::G1CalculatePointersClosure::G1CalculatePointersClosure(G1FullCollector* collector, G1FullGCCompactionPoint* cp) : _g1h(G1CollectedHeap::heap()), - _bitmap(bitmap), + _collector(collector), + _bitmap(collector->mark_bitmap()), _cp(cp), _humongous_regions_removed(0) { } void G1FullGCPrepareTask::G1CalculatePointersClosure::free_humongous_region(HeapRegion* hr) { - FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); + assert(hr->is_humongous(), "must be but region %u is %s", hr->hrm_index(), hr->get_short_type_str()); + + FreeRegionList dummy_free_list("Humongous Dummy Free List for G1MarkSweep"); hr->set_containing_set(NULL); _humongous_regions_removed++; diff --git a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp index fcaf797a12f..124fb619c8e 100644 --- a/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,7 @@ #include "gc/shared/referenceProcessor.hpp" class G1CMBitMap; +class G1FullCollector; class G1FullGCPrepareTask : public G1FullGCTask { protected: @@ -52,6 +53,7 @@ class G1FullGCPrepareTask : public G1FullGCTask { class G1CalculatePointersClosure : public HeapRegionClosure { protected: G1CollectedHeap* _g1h; + G1FullCollector* _collector; G1CMBitMap* _bitmap; G1FullGCCompactionPoint* _cp; uint _humongous_regions_removed; @@ -62,7 +64,7 @@ class G1FullGCPrepareTask : public G1FullGCTask { void reset_region_metadata(HeapRegion* hr); public: - G1CalculatePointersClosure(G1CMBitMap* bitmap, + G1CalculatePointersClosure(G1FullCollector* collector, G1FullGCCompactionPoint* cp); void update_sets(); diff --git a/src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.cpp b/src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.cpp index 1e180192612..103fb4eca88 100644 --- a/src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ G1FullGCReferenceProcessingExecutor::G1RefProcTaskProxy::G1RefProcTaskProxy(Proc void G1FullGCReferenceProcessingExecutor::G1RefProcTaskProxy::work(uint worker_id) { G1FullGCMarker* marker = _collector->marker(worker_id); - G1IsAliveClosure is_alive(_collector->mark_bitmap()); + G1IsAliveClosure is_alive(_collector); G1FullKeepAliveClosure keep_alive(marker); _proc_task.work(worker_id, is_alive, @@ -82,7 +82,7 @@ void G1FullGCReferenceProcessingExecutor::execute(STWGCTimer* timer, G1FullGCTra GCTraceTime(Debug, gc, phases) debug("Phase 1: Reference Processing", timer); // Process reference objects found during marking. G1FullGCMarker* marker = _collector->marker(0); - G1IsAliveClosure is_alive(_collector->mark_bitmap()); + G1IsAliveClosure is_alive(_collector); G1FullKeepAliveClosure keep_alive(marker); ReferenceProcessorPhaseTimes pt(timer, _reference_processor->max_num_queues()); AbstractRefProcTaskExecutor* executor = _reference_processor->processing_is_mt() ? this : NULL; diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 3aa5b5f2071..d96bd5c211c 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -240,8 +240,7 @@ class VerifyObjsInRegionClosure: public ObjectClosure { class VerifyArchiveOopClosure: public BasicOopIterateClosure { HeapRegion* _hr; public: - VerifyArchiveOopClosure(HeapRegion *hr) - : _hr(hr) { } + VerifyArchiveOopClosure(HeapRegion *hr) : _hr(hr) { } void do_oop(narrowOop *p) { do_oop_work(p); } void do_oop( oop *p) { do_oop_work(p); } @@ -249,12 +248,12 @@ class VerifyArchiveOopClosure: public BasicOopIterateClosure { oop obj = RawAccess<>::oop_load(p); if (_hr->is_open_archive()) { - guarantee(obj == NULL || G1ArchiveAllocator::is_archived_object(obj), + guarantee(obj == NULL || G1CollectedHeap::heap()->heap_region_containing(obj)->is_archive(), "Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT, p2i(p), p2i(obj)); } else { assert(_hr->is_closed_archive(), "should be closed archive region"); - guarantee(obj == NULL || G1ArchiveAllocator::is_closed_archive_object(obj), + guarantee(obj == NULL || G1CollectedHeap::heap()->heap_region_containing(obj)->is_closed_archive(), "Archive object at " PTR_FORMAT " references a non-archive object at " PTR_FORMAT, p2i(p), p2i(obj)); } diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 7a5fb1b9cd2..c2940123dc8 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -490,12 +490,11 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio age++; } if (old_mark.has_displaced_mark_helper()) { - // In this case, we have to install the mark word first, - // otherwise obj looks to be forwarded (the old mark word, - // which contains the forward pointer, was copied) - obj->set_mark(old_mark); + // In this case, we have to install the old mark word containing the + // displacement tag, and update the age in the displaced mark word. markWord new_mark = old_mark.displaced_mark_helper().set_age(age); old_mark.set_displaced_mark_helper(new_mark); + obj->set_mark(old_mark); } else { obj->set_mark(old_mark.set_age(age)); } diff --git a/src/hotspot/share/gc/g1/g1ServiceThread.cpp b/src/hotspot/share/gc/g1/g1ServiceThread.cpp index 3c3e561a6b4..02762b375a0 100644 --- a/src/hotspot/share/gc/g1/g1ServiceThread.cpp +++ b/src/hotspot/share/gc/g1/g1ServiceThread.cpp @@ -176,15 +176,30 @@ G1ServiceThread::G1ServiceThread() : true, Monitor::_safepoint_check_never), _task_queue(), + _remset_task(new G1RemSetSamplingTask("Remembered Set Sampling Task")), + _periodic_gc_task(new G1PeriodicGCTask("Periodic GC Task")), _vtime_accum(0) { set_name("G1 Service"); create_and_start(); } +G1ServiceThread::~G1ServiceThread() { + delete _remset_task; + delete _periodic_gc_task; +} + void G1ServiceThread::register_task(G1ServiceTask* task, jlong delay) { guarantee(!task->is_registered(), "Task already registered"); guarantee(task->next() == NULL, "Task already in queue"); + // Make sure the service thread is still up and running, there is a race + // during shutdown where the service thread has been stopped, but other + // GC threads might still be running and trying to add tasks. + if (has_terminated()) { + log_debug(gc, task)("G1 Service Thread (%s) (terminated)", task->name()); + return; + } + log_debug(gc, task)("G1 Service Thread (%s) (register)", task->name()); // Associate the task with the service thread. @@ -272,13 +287,9 @@ void G1ServiceThread::run_task(G1ServiceTask* task) { void G1ServiceThread::run_service() { double vtime_start = os::elapsedVTime(); - // Setup the tasks handeled by the service thread and - // add them to the task list. - G1PeriodicGCTask gc_task("Periodic GC Task"); - register_task(&gc_task); - - G1RemSetSamplingTask remset_task("Remembered Set Sampling Task"); - register_task(&remset_task); + // Register the tasks handled by the service thread. + register_task(_periodic_gc_task); + register_task(_remset_task); while (!should_terminate()) { G1ServiceTask* task = pop_due_task(); @@ -293,6 +304,8 @@ void G1ServiceThread::run_service() { } sleep_before_next_cycle(); } + + log_debug(gc, task)("G1 Service Thread (stopping)"); } void G1ServiceThread::stop_service() { diff --git a/src/hotspot/share/gc/g1/g1ServiceThread.hpp b/src/hotspot/share/gc/g1/g1ServiceThread.hpp index 331e254012e..ec86dead879 100644 --- a/src/hotspot/share/gc/g1/g1ServiceThread.hpp +++ b/src/hotspot/share/gc/g1/g1ServiceThread.hpp @@ -28,6 +28,8 @@ #include "gc/shared/concurrentGCThread.hpp" #include "runtime/mutex.hpp" +class G1PeriodicGCTask; +class G1RemSetSamplingTask; class G1ServiceTaskQueue; class G1ServiceThread; @@ -103,6 +105,9 @@ class G1ServiceThread: public ConcurrentGCThread { Monitor _monitor; G1ServiceTaskQueue _task_queue; + G1RemSetSamplingTask* _remset_task; + G1PeriodicGCTask* _periodic_gc_task; + double _vtime_accum; // Accumulated virtual time. void run_service(); @@ -122,6 +127,8 @@ class G1ServiceThread: public ConcurrentGCThread { public: G1ServiceThread(); + ~G1ServiceThread(); + double vtime_accum() { return _vtime_accum; } // Register a task with the service thread and schedule it. If // no delay is specified the task is scheduled to run directly. diff --git a/src/hotspot/share/gc/g1/heapRegion.hpp b/src/hotspot/share/gc/g1/heapRegion.hpp index 3756d5fe094..a7566037b63 100644 --- a/src/hotspot/share/gc/g1/heapRegion.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.hpp @@ -123,7 +123,9 @@ class HeapRegion : public CHeapObj { bool is_empty() const { return used() == 0; } private: - void reset_after_compaction() { set_top(compaction_top()); } + void reset_compaction_top_after_compaction(); + + void reset_after_full_gc_common(); void clear(bool mangle_space); @@ -165,16 +167,11 @@ class HeapRegion : public CHeapObj { HeapWord* initialize_threshold(); HeapWord* cross_threshold(HeapWord* start, HeapWord* end); - // Update heap region to be consistent after Full GC compaction. - void reset_humongous_during_compaction() { - assert(is_humongous(), - "should only be called for humongous regions"); - zero_marked_bytes(); - init_top_at_mark_start(); - } - // Update heap region to be consistent after Full GC compaction. - void complete_compaction(); + // Update heap region that has been compacted to be consistent after Full GC. + void reset_compacted_after_full_gc(); + // Update pinned heap region (not compacted) to be consistent after Full GC. + void reset_pinned_after_full_gc(); // All allocated blocks are occupied by objects in a HeapRegion bool block_is_obj(const HeapWord* p) const; diff --git a/src/hotspot/share/gc/g1/heapRegion.inline.hpp b/src/hotspot/share/gc/g1/heapRegion.inline.hpp index 1736d4b512d..31b787869c5 100644 --- a/src/hotspot/share/gc/g1/heapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -181,18 +181,44 @@ inline size_t HeapRegion::block_size(const HeapWord *addr) const { return block_size_using_bitmap(addr, G1CollectedHeap::heap()->concurrent_mark()->prev_mark_bitmap()); } -inline void HeapRegion::complete_compaction() { - // Reset space and bot after compaction is complete if needed. - reset_after_compaction(); - if (is_empty()) { - reset_bot(); - } +inline void HeapRegion::reset_compaction_top_after_compaction() { + set_top(compaction_top()); + _compaction_top = bottom(); +} + +inline void HeapRegion::reset_compacted_after_full_gc() { + assert(!is_pinned(), "must be"); - // After a compaction the mark bitmap is invalid, so we must - // treat all objects as being inside the unmarked area. + reset_compaction_top_after_compaction(); + // After a compaction the mark bitmap in a non-pinned regions is invalid. + // We treat all objects as being above PTAMS. zero_marked_bytes(); init_top_at_mark_start(); + reset_after_full_gc_common(); +} + +inline void HeapRegion::reset_pinned_after_full_gc() { + assert(!is_free(), "should not have compacted free region"); + assert(is_pinned(), "must be"); + + assert(compaction_top() == bottom(), + "region %u compaction_top " PTR_FORMAT " must not be different from bottom " PTR_FORMAT, + hrm_index(), p2i(compaction_top()), p2i(bottom())); + + _prev_top_at_mark_start = top(); // Keep existing top and usage. + _prev_marked_bytes = used(); + _next_top_at_mark_start = bottom(); + _next_marked_bytes = 0; + + reset_after_full_gc_common(); +} + +inline void HeapRegion::reset_after_full_gc_common() { + if (is_empty()) { + reset_bot(); + } + // Clear unused heap memory in debug builds. if (ZapUnusedHeapArea) { mangle_unused_area(); diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp index fa8c431c5b8..4f3f41e5ccf 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp @@ -539,6 +539,71 @@ void ParallelScavengeHeap::object_iterate(ObjectClosure* cl) { old_gen()->object_iterate(cl); } +// The HeapBlockClaimer is used during parallel iteration over the heap, +// allowing workers to claim heap areas ("blocks"), gaining exclusive rights to these. +// The eden and survivor spaces are treated as single blocks as it is hard to divide +// these spaces. +// The old space is divided into fixed-size blocks. +class HeapBlockClaimer : public StackObj { + size_t _claimed_index; + +public: + static const size_t InvalidIndex = SIZE_MAX; + static const size_t EdenIndex = 0; + static const size_t SurvivorIndex = 1; + static const size_t NumNonOldGenClaims = 2; + + HeapBlockClaimer() : _claimed_index(EdenIndex) { } + // Claim the block and get the block index. + size_t claim_and_get_block() { + size_t block_index; + block_index = Atomic::fetch_and_add(&_claimed_index, 1u); + + PSOldGen* old_gen = ParallelScavengeHeap::heap()->old_gen(); + size_t num_claims = old_gen->num_iterable_blocks() + NumNonOldGenClaims; + + return block_index < num_claims ? block_index : InvalidIndex; + } +}; + +void ParallelScavengeHeap::object_iterate_parallel(ObjectClosure* cl, + HeapBlockClaimer* claimer) { + size_t block_index = claimer->claim_and_get_block(); + // Iterate until all blocks are claimed + if (block_index == HeapBlockClaimer::EdenIndex) { + young_gen()->eden_space()->object_iterate(cl); + block_index = claimer->claim_and_get_block(); + } + if (block_index == HeapBlockClaimer::SurvivorIndex) { + young_gen()->from_space()->object_iterate(cl); + young_gen()->to_space()->object_iterate(cl); + block_index = claimer->claim_and_get_block(); + } + while (block_index != HeapBlockClaimer::InvalidIndex) { + old_gen()->object_iterate_block(cl, block_index - HeapBlockClaimer::NumNonOldGenClaims); + block_index = claimer->claim_and_get_block(); + } +} + +class PSScavengeParallelObjectIterator : public ParallelObjectIterator { +private: + ParallelScavengeHeap* _heap; + HeapBlockClaimer _claimer; + +public: + PSScavengeParallelObjectIterator() : + _heap(ParallelScavengeHeap::heap()), + _claimer() {} + + virtual void object_iterate(ObjectClosure* cl, uint worker_id) { + _heap->object_iterate_parallel(cl, &_claimer); + } +}; + +ParallelObjectIterator* ParallelScavengeHeap::parallel_object_iterator(uint thread_num) { + return new PSScavengeParallelObjectIterator(); +} + HeapWord* ParallelScavengeHeap::block_start(const void* addr) const { if (young_gen()->is_in_reserved(addr)) { assert(young_gen()->is_in(addr), diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp index ed72efea866..77f9ce1dc43 100644 --- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp +++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp @@ -45,6 +45,7 @@ class AdjoiningGenerations; class GCHeapSummary; +class HeapBlockClaimer; class MemoryManager; class MemoryPool; class PSAdaptiveSizePolicy; @@ -207,6 +208,8 @@ class ParallelScavengeHeap : public CollectedHeap { size_t unsafe_max_tlab_alloc(Thread* thr) const; void object_iterate(ObjectClosure* cl); + void object_iterate_parallel(ObjectClosure* cl, HeapBlockClaimer* claimer); + virtual ParallelObjectIterator* parallel_object_iterator(uint thread_num); HeapWord* block_start(const void* addr) const; bool block_is_obj(const HeapWord* addr) const; diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp index c5b59439682..8506079d5f0 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.cpp +++ b/src/hotspot/share/gc/parallel/psOldGen.cpp @@ -173,6 +173,38 @@ HeapWord* PSOldGen::allocate(size_t word_size) { return res; } +size_t PSOldGen::num_iterable_blocks() const { + return (object_space()->used_in_bytes() + IterateBlockSize - 1) / IterateBlockSize; +} + +void PSOldGen::object_iterate_block(ObjectClosure* cl, size_t block_index) { + size_t block_word_size = IterateBlockSize / HeapWordSize; + assert((block_word_size % (ObjectStartArray::block_size)) == 0, + "Block size not a multiple of start_array block"); + + MutableSpace *space = object_space(); + + HeapWord* begin = space->bottom() + block_index * block_word_size; + HeapWord* end = MIN2(space->top(), begin + block_word_size); + + if (!start_array()->object_starts_in_range(begin, end)) { + return; + } + + // Get object starting at or reaching into this block. + HeapWord* start = start_array()->object_start(begin); + if (start < begin) { + start += oop(start)->size(); + } + assert(start >= begin, + "Object address" PTR_FORMAT " must be larger or equal to block address at " PTR_FORMAT, + p2i(start), p2i(begin)); + // Iterate all objects until the end. + for (HeapWord* p = start; p < end; p += oop(p)->size()) { + cl->do_object(oop(p)); + } +} + HeapWord* PSOldGen::expand_and_allocate(size_t word_size) { expand(word_size*HeapWordSize); if (GCExpandToAllocateDelayMillis > 0) { diff --git a/src/hotspot/share/gc/parallel/psOldGen.hpp b/src/hotspot/share/gc/parallel/psOldGen.hpp index f7e43af064f..d882bab114b 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.hpp +++ b/src/hotspot/share/gc/parallel/psOldGen.hpp @@ -52,6 +52,9 @@ class PSOldGen : public CHeapObj { const size_t _min_gen_size; const size_t _max_gen_size; + // Block size for parallel iteration + static const size_t IterateBlockSize = 1024 * 1024; + #ifdef ASSERT void assert_block_in_covered_region(MemRegion new_memregion) { // Explictly capture current covered_region in a local @@ -163,6 +166,14 @@ class PSOldGen : public CHeapObj { void oop_iterate(OopIterateClosure* cl) { object_space()->oop_iterate(cl); } void object_iterate(ObjectClosure* cl) { object_space()->object_iterate(cl); } + // Number of blocks to be iterated over in the used part of old gen. + size_t num_iterable_blocks() const; + // Iterate the objects starting in block block_index within [bottom, top) of the + // old gen. The object just reaching into this block is not iterated over. + // A block is an evenly sized non-overlapping part of the old gen of + // IterateBlockSize bytes. + void object_iterate_block(ObjectClosure* cl, size_t block_index); + // Debugging - do not use for time critical operations void print() const; virtual void print_on(outputStream* st) const; diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index 4fb52049532..dd3c5e27316 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -599,6 +599,10 @@ void CollectedHeap::unpin_object(JavaThread* thread, oop obj) { ShouldNotReachHere(); } +bool CollectedHeap::is_archived_object(oop object) const { + return false; +} + void CollectedHeap::deduplicate_string(oop str) { // Do nothing, unless overridden in subclass. } diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index d8223a69f12..a02dca8ccf7 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -511,11 +511,13 @@ class CollectedHeap : public CHeapObj { virtual oop pin_object(JavaThread* thread, oop obj); virtual void unpin_object(JavaThread* thread, oop obj); + // Is the given object inside a CDS archive area? + virtual bool is_archived_object(oop object) const; + // Deduplicate the string, iff the GC supports string deduplication. virtual void deduplicate_string(oop str); virtual bool is_oop(oop object) const; - // Non product verification and debugging. #ifndef PRODUCT // Support for PromotionFailureALot. Return true if it's time to cause a diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 956634b2066..064e0da22a1 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -293,9 +293,10 @@ product(bool, ExecutingUnitTests, false, \ "Whether the JVM is running unit tests or not") \ \ - product_pd(bool, UseTLAB, "Use thread-local object allocation") \ + product(bool, UseTLAB, true, \ + "Use thread-local object allocation") \ \ - product_pd(bool, ResizeTLAB, \ + product(bool, ResizeTLAB, true, \ "Dynamically resize TLAB size for threads") \ \ product(bool, ZeroTLAB, false, \ diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index d022cc241f0..564bc74dd89 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -644,7 +644,8 @@ Node* ShenandoahBarrierSetC2::atomic_cmpxchg_val_at_resolved(C2AtomicParseAccess load_store = kit->gvn().transform(new DecodeNNode(load_store, load_store->get_ptr_type())); } #endif - load_store = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, load_store, ShenandoahBarrierSet::AccessKind::NORMAL)); + ShenandoahBarrierSet::AccessKind kind = ShenandoahBarrierSet::access_kind(access.decorators(), access.type()); + load_store = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, load_store, kind)); return load_store; } return BarrierSetC2::atomic_cmpxchg_val_at_resolved(access, expected_val, new_val, value_type); @@ -712,7 +713,8 @@ Node* ShenandoahBarrierSetC2::atomic_xchg_at_resolved(C2AtomicParseAccess& acces } Node* result = BarrierSetC2::atomic_xchg_at_resolved(access, val, value_type); if (access.is_oop()) { - result = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, result, ShenandoahBarrierSet::AccessKind::NORMAL)); + ShenandoahBarrierSet::AccessKind kind = ShenandoahBarrierSet::access_kind(access.decorators(), access.type()); + result = kit->gvn().transform(new ShenandoahLoadReferenceBarrierNode(NULL, result, kind)); shenandoah_write_barrier_pre(kit, false /* do_load */, NULL, NULL, max_juint, NULL, NULL, result /* pre_val */, T_OBJECT); diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 9e51e9fbad1..5335a987830 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -2374,7 +2374,7 @@ void MemoryGraphFixer::collect_memory_nodes() { while (dead_phis.size() > 0) { Node* n = dead_phis.pop(); n->replace_by(_phase->C->top()); - n->destruct(); + n->destruct(&_phase->igvn()); } for (int i = rpo_list.size() - 1; i >= 0; i--) { Node* c = rpo_list.at(i); @@ -2941,7 +2941,12 @@ const Type* ShenandoahLoadReferenceBarrierNode::bottom_type() const { if (t == TypePtr::NULL_PTR) { return t; } - return t->is_oopptr(); + + if (kind() == ShenandoahBarrierSet::AccessKind::NORMAL) { + return t; + } + + return t->meet(TypePtr::NULL_PTR); } const Type* ShenandoahLoadReferenceBarrierNode::Value(PhaseGVN* phase) const { @@ -2953,8 +2958,11 @@ const Type* ShenandoahLoadReferenceBarrierNode::Value(PhaseGVN* phase) const { return t2; } - const Type* type = t2->is_oopptr(); - return type; + if (kind() == ShenandoahBarrierSet::AccessKind::NORMAL) { + return t2; + } + + return t2->meet(TypePtr::NULL_PTR); } Node* ShenandoahLoadReferenceBarrierNode::Identity(PhaseGVN* phase) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index bf91b199d99..f9605719df8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -106,14 +106,15 @@ inline oop ShenandoahBarrierSet::load_reference_barrier(oop obj, T* load_addr) { if (!HasDecorator::value && obj != NULL && _heap->is_concurrent_weak_root_in_progress() && !_heap->marking_context()->is_marked(obj)) { - Thread* thr = Thread::current(); - if (thr->is_Java_thread()) { - return NULL; - } else { - // This path is sometimes (rarely) taken by GC threads. - // See e.g.: https://bugs.openjdk.java.net/browse/JDK-8237874 - return obj; - } + return NULL; + } + + // Prevent resurrection of unreachable objects that are visited during + // concurrent class-unloading. + if (HasDecorator::value && obj != NULL && + _heap->is_evacuation_in_progress() && + !_heap->marking_context()->is_marked(obj)) { + return obj; } oop fwd = load_reference_barrier(obj); @@ -255,7 +256,7 @@ inline oop ShenandoahBarrierSet::AccessBarrier::oop_ato // Note: We don't need a keep-alive-barrier here. We already enqueue any loaded reference for SATB anyway, // because it must be the previous value. - res = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(res); + res = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(res, NULL); bs->satb_enqueue(res); return res; } @@ -281,7 +282,7 @@ inline oop ShenandoahBarrierSet::AccessBarrier::oop_ato // Note: We don't need a keep-alive-barrier here. We already enqueue any loaded reference for SATB anyway, // because it must be the previous value. - previous = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(previous); + previous = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(previous, NULL); bs->satb_enqueue(previous); return previous; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index c36ed910315..7c388284665 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -2416,17 +2416,17 @@ void ShenandoahHeap::stw_process_weak_roots(bool full_gc) { ShenandoahForwardedIsAliveClosure is_alive; ShenandoahUpdateRefsClosure keep_alive; ShenandoahParallelWeakRootsCleaningTask - cleaning_task(timing_phase, &is_alive, &keep_alive, num_workers, !ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()); + cleaning_task(timing_phase, &is_alive, &keep_alive, num_workers, is_stw_gc_in_progress()); _workers->run_task(&cleaning_task); } else { ShenandoahIsAliveClosure is_alive; #ifdef ASSERT ShenandoahAssertNotForwardedClosure verify_cl; ShenandoahParallelWeakRootsCleaningTask - cleaning_task(timing_phase, &is_alive, &verify_cl, num_workers, !ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()); + cleaning_task(timing_phase, &is_alive, &verify_cl, num_workers, is_stw_gc_in_progress()); #else ShenandoahParallelWeakRootsCleaningTask - cleaning_task(timing_phase, &is_alive, &do_nothing_cl, num_workers, !ShenandoahConcurrentRoots::should_do_concurrent_class_unloading()); + cleaning_task(timing_phase, &is_alive, &do_nothing_cl, num_workers, is_stw_gc_in_progress()); #endif _workers->run_task(&cleaning_task); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp index 09f0e92d6fb..61e5b4b7705 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahParallelCleaning.inline.hpp @@ -53,7 +53,9 @@ ShenandoahParallelWeakRootsCleaningTask::~ShenandoahParallel if (StringDedup::is_enabled()) { StringDedup::gc_epilogue(); } - _weak_processing_task.report_num_dead(); + if (_include_concurrent_roots) { + _weak_processing_task.report_num_dead(); + } } template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index 9cdfa5d6e65..8bbecdc0e2c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -265,7 +265,7 @@ template bool ShenandoahReferenceProcessor::should_discover(oop reference, ReferenceType type) const { T* referent_addr = (T*) java_lang_ref_Reference::referent_addr_raw(reference); T heap_oop = RawAccess<>::oop_load(referent_addr); - oop referent = CompressedOops::decode_not_null(heap_oop); + oop referent = CompressedOops::decode(heap_oop); if (is_inactive(reference, referent, type)) { log_trace(gc,ref)("Reference inactive: " PTR_FORMAT, p2i(reference)); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp index cdd1aa3a34f..4bb361776e5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp @@ -200,7 +200,6 @@ class ShenandoahConcurrentRootScanner { ShenandoahVMRoots _vm_roots; ShenandoahClassLoaderDataRoots _cld_roots; - ShenandoahConcurrentStringDedupRoots _dedup_roots; ShenandoahNMethodTableSnapshot* _codecache_snapshot; ShenandoahPhaseTimings::Phase _phase; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp index 94dea3ccc17..84a95370a01 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp @@ -149,7 +149,6 @@ ShenandoahConcurrentRootScanner::ShenandoahConcurrentRootScanner(uin ShenandoahPhaseTimings::Phase phase) : _vm_roots(phase), _cld_roots(phase, n_workers), - _dedup_roots(phase), _codecache_snapshot(NULL), _phase(phase) { if (!ShenandoahHeap::heap()->unload_classes()) { @@ -180,9 +179,7 @@ void ShenandoahConcurrentRootScanner::oops_do(OopClosure* oops, uint _vm_roots.oops_do(oops, worker_id); if (!heap->unload_classes()) { - AlwaysTrueClosure always_true; _cld_roots.cld_do(&clds_cl, worker_id); - _dedup_roots.oops_do(&always_true, oops, worker_id); ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id); CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); _codecache_snapshot->parallel_blobs_do(&blobs); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp index 6e3c826a80e..b1f6d175cd9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp @@ -136,13 +136,6 @@ void ShenandoahRootVerifier::roots_do(OopClosure* oops) { JNIHandles::oops_do(oops); Universe::vm_global()->oops_do(oops); - AlwaysTrueClosure always_true; - WeakProcessor::weak_oops_do(&always_true, oops); - - if (ShenandoahStringDedup::is_enabled()) { - ShenandoahStringDedup::oops_do_slow(oops); - } - // Do thread roots the last. This allows verification code to find // any broken objects from those special roots first, not the accidental // dangling reference from the thread root. diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 67f01a0f187..cf11a8d610b 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -1547,7 +1547,10 @@ JRT_ENTRY(void, InterpreterRuntime::post_method_entry(JavaThread *thread)) JRT_END -JRT_ENTRY(void, InterpreterRuntime::post_method_exit(JavaThread *thread)) +// This is a JRT_BLOCK_ENTRY because we have to stash away the return oop +// before transitioning to VM, and restore it after transitioning back +// to Java. The return oop at the top-of-stack, is not walked by the GC. +JRT_BLOCK_ENTRY(void, InterpreterRuntime::post_method_exit(JavaThread *thread)) LastFrameAccessor last_frame(thread); JvmtiExport::post_method_exit(thread, last_frame.method(), last_frame.get_frame()); JRT_END diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index 789fd945bd1..06f66a13464 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -52,6 +52,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/threadCritical.hpp" #include "utilities/exceptions.hpp" +#include "utilities/macros.hpp" // no precompiled headers @@ -153,7 +154,7 @@ #endif #undef DEBUGGER_SINGLE_STEP_NOTIFY -#ifdef VM_JVMTI +#if INCLUDE_JVMTI /* NOTE: (kbr) This macro must be called AFTER the PC has been incremented. JvmtiExport::at_single_stepping_point() may cause a breakpoint opcode to get inserted at the current PC to allow the @@ -163,33 +164,31 @@ to get the current opcode. This will override any other prefetching that might have occurred. */ -#define DEBUGGER_SINGLE_STEP_NOTIFY() \ -{ \ - if (_jvmti_interp_events) { \ - if (JvmtiExport::should_post_single_step()) { \ - DECACHE_STATE(); \ - SET_LAST_JAVA_FRAME(); \ - ThreadInVMfromJava trans(THREAD); \ - JvmtiExport::at_single_stepping_point(THREAD, \ - istate->method(), \ - pc); \ - RESET_LAST_JAVA_FRAME(); \ - CACHE_STATE(); \ - if (THREAD->has_pending_popframe() && \ - !THREAD->pop_frame_in_process()) { \ - goto handle_Pop_Frame; \ - } \ - if (THREAD->jvmti_thread_state() && \ - THREAD->jvmti_thread_state()->is_earlyret_pending()) { \ - goto handle_Early_Return; \ - } \ - opcode = *pc; \ - } \ - } \ +#define DEBUGGER_SINGLE_STEP_NOTIFY() \ +{ \ + if (JVMTI_ENABLED && JvmtiExport::should_post_single_step()) { \ + DECACHE_STATE(); \ + SET_LAST_JAVA_FRAME(); \ + ThreadInVMfromJava trans(THREAD); \ + JvmtiExport::at_single_stepping_point(THREAD, \ + istate->method(), \ + pc); \ + RESET_LAST_JAVA_FRAME(); \ + CACHE_STATE(); \ + if (THREAD->has_pending_popframe() && \ + !THREAD->pop_frame_in_process()) { \ + goto handle_Pop_Frame; \ + } \ + if (THREAD->jvmti_thread_state() && \ + THREAD->jvmti_thread_state()->is_earlyret_pending()) { \ + goto handle_Early_Return; \ + } \ + opcode = *pc; \ + } \ } #else #define DEBUGGER_SINGLE_STEP_NOTIFY() -#endif +#endif // INCLUDE_JVMTI /* * CONTINUE - Macro for executing the next opcode. @@ -387,22 +386,18 @@ /* * BytecodeInterpreter::run(interpreterState istate) - * BytecodeInterpreter::runWithChecks(interpreterState istate) * * The real deal. This is where byte codes actually get interpreted. * Basically it's a big while loop that iterates until we return from * the method passed in. - * - * The runWithChecks is used if JVMTI is enabled. - * */ -#if defined(VM_JVMTI) -void -BytecodeInterpreter::runWithChecks(interpreterState istate) { -#else -void -BytecodeInterpreter::run(interpreterState istate) { -#endif + +// Instantiate two variants of the method for future linking. +template void BytecodeInterpreter::run(interpreterState istate); +template void BytecodeInterpreter::run(interpreterState istate); + +template +void BytecodeInterpreter::run(interpreterState istate) { // In order to simplify some tests based on switches set at runtime // we invoke the interpreter a single time after switches are enabled @@ -417,9 +412,6 @@ BytecodeInterpreter::run(interpreterState istate) { if (checkit && *c_addr != c_value) { os::breakpoint(); } -#ifdef VM_JVMTI - static bool _jvmti_interp_events = 0; -#endif #ifdef ASSERT if (istate->_msg != initialize) { @@ -555,9 +547,6 @@ BytecodeInterpreter::run(interpreterState istate) { switch (istate->msg()) { case initialize: { if (initialized++) ShouldNotReachHere(); // Only one initialize call. -#ifdef VM_JVMTI - _jvmti_interp_events = JvmtiExport::can_post_interpreter_events(); -#endif return; } break; @@ -667,17 +656,13 @@ BytecodeInterpreter::run(interpreterState istate) { } THREAD->clr_do_not_unlock(); - // Notify jvmti -#ifdef VM_JVMTI - if (_jvmti_interp_events) { - // Whenever JVMTI puts a thread in interp_only_mode, method - // entry/exit events are sent for that thread to track stack depth. - if (THREAD->is_interp_only_mode()) { - CALL_VM(InterpreterRuntime::post_method_entry(THREAD), - handle_exception); - } + // Notify jvmti. + // Whenever JVMTI puts a thread in interp_only_mode, method + // entry/exit events are sent for that thread to track stack depth. + if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) { + CALL_VM(InterpreterRuntime::post_method_entry(THREAD), + handle_exception); } -#endif /* VM_JVMTI */ goto run; } @@ -1800,8 +1785,7 @@ BytecodeInterpreter::run(interpreterState istate) { cache = cp->entry_at(index); } -#ifdef VM_JVMTI - if (_jvmti_interp_events) { + if (JVMTI_ENABLED) { int *count_addr; oop obj; // Check to see if a field modification watch has been set @@ -1820,7 +1804,6 @@ BytecodeInterpreter::run(interpreterState istate) { handle_exception); } } -#endif /* VM_JVMTI */ oop obj; if ((Bytecodes::Code)opcode == Bytecodes::_getstatic) { @@ -1898,8 +1881,7 @@ BytecodeInterpreter::run(interpreterState istate) { cache = cp->entry_at(index); } -#ifdef VM_JVMTI - if (_jvmti_interp_events) { + if (JVMTI_ENABLED) { int *count_addr; oop obj; // Check to see if a field modification watch has been set @@ -1925,7 +1907,6 @@ BytecodeInterpreter::run(interpreterState istate) { handle_exception); } } -#endif /* VM_JVMTI */ // QQQ Need to make this as inlined as possible. Probably need to split all the bytecode cases // out so c++ compiler has a chance for constant prop to fold everything possible away. @@ -2404,11 +2385,9 @@ BytecodeInterpreter::run(interpreterState istate) { if (callee != NULL) { istate->set_callee(callee); istate->set_callee_entry_point(callee->from_interpreted_entry()); -#ifdef VM_JVMTI - if (JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode()) { + if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) { istate->set_callee_entry_point(callee->interpreter_entry()); } -#endif /* VM_JVMTI */ istate->set_bcp_advance(5); UPDATE_PC_AND_RETURN(0); // I'll be back... } @@ -2466,11 +2445,9 @@ BytecodeInterpreter::run(interpreterState istate) { istate->set_callee(callee); istate->set_callee_entry_point(callee->from_interpreted_entry()); -#ifdef VM_JVMTI - if (JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode()) { + if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) { istate->set_callee_entry_point(callee->interpreter_entry()); } -#endif /* VM_JVMTI */ istate->set_bcp_advance(5); UPDATE_PC_AND_RETURN(0); // I'll be back... } @@ -2536,11 +2513,9 @@ BytecodeInterpreter::run(interpreterState istate) { istate->set_callee(callee); istate->set_callee_entry_point(callee->from_interpreted_entry()); -#ifdef VM_JVMTI - if (JvmtiExport::can_post_interpreter_events() && THREAD->is_interp_only_mode()) { + if (JVMTI_ENABLED && THREAD->is_interp_only_mode()) { istate->set_callee_entry_point(callee->interpreter_entry()); } -#endif /* VM_JVMTI */ istate->set_bcp_advance(3); UPDATE_PC_AND_RETURN(0); // I'll be back... } @@ -2963,25 +2938,16 @@ BytecodeInterpreter::run(interpreterState istate) { // (with this note) in anticipation of changing the vm and the tests // simultaneously. - - // suppress_exit_event = suppress_exit_event || illegal_state_oop() != NULL; + // Whenever JVMTI puts a thread in interp_only_mode, method + // entry/exit events are sent for that thread to track stack depth. - -#ifdef VM_JVMTI - if (_jvmti_interp_events) { - // Whenever JVMTI puts a thread in interp_only_mode, method - // entry/exit events are sent for that thread to track stack depth. - if ( !suppress_exit_event && THREAD->is_interp_only_mode() ) { - { - // Prevent any HandleMarkCleaner from freeing our live handles - HandleMark __hm(THREAD); - CALL_VM_NOCHECK(InterpreterRuntime::post_method_exit(THREAD)); - } - } - } -#endif /* VM_JVMTI */ + if (JVMTI_ENABLED && !suppress_exit_event && THREAD->is_interp_only_mode()) { + // Prevent any HandleMarkCleaner from freeing our live handles + HandleMark __hm(THREAD); + CALL_VM_NOCHECK(InterpreterRuntime::post_method_exit(THREAD)); + } // // See if we are returning any exception @@ -3032,13 +2998,6 @@ BytecodeInterpreter::run(interpreterState istate) { return; } -/* - * All the code following this point is only produced once and is not present - * in the JVMTI version of the interpreter -*/ - -#ifndef VM_JVMTI - // This constructor should only be used to contruct the object to signal // interpreter initialization. All other instances should be created by // the frame manager. @@ -3049,151 +3008,12 @@ BytecodeInterpreter::BytecodeInterpreter(messages msg) { _prev_link = NULL; } -// Inline static functions for Java Stack and Local manipulation - -// The implementations are platform dependent. We have to worry about alignment -// issues on some machines which can change on the same platform depending on -// whether it is an LP64 machine also. -address BytecodeInterpreter::stack_slot(intptr_t *tos, int offset) { - return (address) tos[Interpreter::expr_index_at(-offset)]; -} - -jint BytecodeInterpreter::stack_int(intptr_t *tos, int offset) { - return *((jint*) &tos[Interpreter::expr_index_at(-offset)]); -} - -jfloat BytecodeInterpreter::stack_float(intptr_t *tos, int offset) { - return *((jfloat *) &tos[Interpreter::expr_index_at(-offset)]); -} - -oop BytecodeInterpreter::stack_object(intptr_t *tos, int offset) { - return cast_to_oop(tos [Interpreter::expr_index_at(-offset)]); -} - -jdouble BytecodeInterpreter::stack_double(intptr_t *tos, int offset) { - return ((VMJavaVal64*) &tos[Interpreter::expr_index_at(-offset)])->d; -} - -jlong BytecodeInterpreter::stack_long(intptr_t *tos, int offset) { - return ((VMJavaVal64 *) &tos[Interpreter::expr_index_at(-offset)])->l; -} - -// only used for value types -void BytecodeInterpreter::set_stack_slot(intptr_t *tos, address value, - int offset) { - *((address *)&tos[Interpreter::expr_index_at(-offset)]) = value; -} - -void BytecodeInterpreter::set_stack_int(intptr_t *tos, int value, - int offset) { - *((jint *)&tos[Interpreter::expr_index_at(-offset)]) = value; -} - -void BytecodeInterpreter::set_stack_float(intptr_t *tos, jfloat value, - int offset) { - *((jfloat *)&tos[Interpreter::expr_index_at(-offset)]) = value; -} - -void BytecodeInterpreter::set_stack_object(intptr_t *tos, oop value, - int offset) { - *((oop *)&tos[Interpreter::expr_index_at(-offset)]) = value; -} - -// needs to be platform dep for the 32 bit platforms. -void BytecodeInterpreter::set_stack_double(intptr_t *tos, jdouble value, - int offset) { - ((VMJavaVal64*)&tos[Interpreter::expr_index_at(-offset)])->d = value; -} - -void BytecodeInterpreter::set_stack_double_from_addr(intptr_t *tos, - address addr, int offset) { - (((VMJavaVal64*)&tos[Interpreter::expr_index_at(-offset)])->d = - ((VMJavaVal64*)addr)->d); -} - -void BytecodeInterpreter::set_stack_long(intptr_t *tos, jlong value, - int offset) { - ((VMJavaVal64*)&tos[Interpreter::expr_index_at(-offset+1)])->l = 0xdeedbeeb; - ((VMJavaVal64*)&tos[Interpreter::expr_index_at(-offset)])->l = value; -} - -void BytecodeInterpreter::set_stack_long_from_addr(intptr_t *tos, - address addr, int offset) { - ((VMJavaVal64*)&tos[Interpreter::expr_index_at(-offset+1)])->l = 0xdeedbeeb; - ((VMJavaVal64*)&tos[Interpreter::expr_index_at(-offset)])->l = - ((VMJavaVal64*)addr)->l; -} - -// Locals - -address BytecodeInterpreter::locals_slot(intptr_t* locals, int offset) { - return (address)locals[Interpreter::local_index_at(-offset)]; -} -jint BytecodeInterpreter::locals_int(intptr_t* locals, int offset) { - return (jint)locals[Interpreter::local_index_at(-offset)]; -} -jfloat BytecodeInterpreter::locals_float(intptr_t* locals, int offset) { - return (jfloat)locals[Interpreter::local_index_at(-offset)]; -} -oop BytecodeInterpreter::locals_object(intptr_t* locals, int offset) { - return cast_to_oop(locals[Interpreter::local_index_at(-offset)]); -} -jdouble BytecodeInterpreter::locals_double(intptr_t* locals, int offset) { - return ((VMJavaVal64*)&locals[Interpreter::local_index_at(-(offset+1))])->d; -} -jlong BytecodeInterpreter::locals_long(intptr_t* locals, int offset) { - return ((VMJavaVal64*)&locals[Interpreter::local_index_at(-(offset+1))])->l; -} - -// Returns the address of locals value. -address BytecodeInterpreter::locals_long_at(intptr_t* locals, int offset) { - return ((address)&locals[Interpreter::local_index_at(-(offset+1))]); -} -address BytecodeInterpreter::locals_double_at(intptr_t* locals, int offset) { - return ((address)&locals[Interpreter::local_index_at(-(offset+1))]); -} - -// Used for local value or returnAddress -void BytecodeInterpreter::set_locals_slot(intptr_t *locals, - address value, int offset) { - *((address*)&locals[Interpreter::local_index_at(-offset)]) = value; -} -void BytecodeInterpreter::set_locals_int(intptr_t *locals, - jint value, int offset) { - *((jint *)&locals[Interpreter::local_index_at(-offset)]) = value; -} -void BytecodeInterpreter::set_locals_float(intptr_t *locals, - jfloat value, int offset) { - *((jfloat *)&locals[Interpreter::local_index_at(-offset)]) = value; -} -void BytecodeInterpreter::set_locals_object(intptr_t *locals, - oop value, int offset) { - *((oop *)&locals[Interpreter::local_index_at(-offset)]) = value; -} -void BytecodeInterpreter::set_locals_double(intptr_t *locals, - jdouble value, int offset) { - ((VMJavaVal64*)&locals[Interpreter::local_index_at(-(offset+1))])->d = value; -} -void BytecodeInterpreter::set_locals_long(intptr_t *locals, - jlong value, int offset) { - ((VMJavaVal64*)&locals[Interpreter::local_index_at(-(offset+1))])->l = value; -} -void BytecodeInterpreter::set_locals_double_from_addr(intptr_t *locals, - address addr, int offset) { - ((VMJavaVal64*)&locals[Interpreter::local_index_at(-(offset+1))])->d = ((VMJavaVal64*)addr)->d; -} -void BytecodeInterpreter::set_locals_long_from_addr(intptr_t *locals, - address addr, int offset) { - ((VMJavaVal64*)&locals[Interpreter::local_index_at(-(offset+1))])->l = ((VMJavaVal64*)addr)->l; -} - void BytecodeInterpreter::astore(intptr_t* tos, int stack_offset, intptr_t* locals, int locals_offset) { intptr_t value = tos[Interpreter::expr_index_at(-stack_offset)]; locals[Interpreter::local_index_at(-locals_offset)] = value; } - void BytecodeInterpreter::copy_stack_slot(intptr_t *tos, int from_offset, int to_offset) { tos[Interpreter::expr_index_at(-to_offset)] = @@ -3203,6 +3023,7 @@ void BytecodeInterpreter::copy_stack_slot(intptr_t *tos, int from_offset, void BytecodeInterpreter::dup(intptr_t *tos) { copy_stack_slot(tos, -1, 0); } + void BytecodeInterpreter::dup2(intptr_t *tos) { copy_stack_slot(tos, -2, 0); copy_stack_slot(tos, -1, 1); @@ -3307,5 +3128,3 @@ extern "C" { } } #endif // PRODUCT - -#endif // JVMTI diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp index df2943a1e3f..e4a09d492bd 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.hpp @@ -503,58 +503,8 @@ static void dup2_x1(intptr_t *tos); /* insert top 2 slots three down */ static void dup2_x2(intptr_t *tos); /* insert top 2 slots four down */ static void swap(intptr_t *tos); /* swap top two elements */ -// umm don't like this method modifies its object - -// The Interpreter used when +template static void run(interpreterState istate); -// The interpreter used if JVMTI needs interpreter events -static void runWithChecks(interpreterState istate); -static void End_Of_Interpreter(void); - -// Inline static functions for Java Stack and Local manipulation - -static address stack_slot(intptr_t *tos, int offset); -static jint stack_int(intptr_t *tos, int offset); -static jfloat stack_float(intptr_t *tos, int offset); -static oop stack_object(intptr_t *tos, int offset); -static jdouble stack_double(intptr_t *tos, int offset); -static jlong stack_long(intptr_t *tos, int offset); - -// only used for value types -static void set_stack_slot(intptr_t *tos, address value, int offset); -static void set_stack_int(intptr_t *tos, int value, int offset); -static void set_stack_float(intptr_t *tos, jfloat value, int offset); -static void set_stack_object(intptr_t *tos, oop value, int offset); - -// needs to be platform dep for the 32 bit platforms. -static void set_stack_double(intptr_t *tos, jdouble value, int offset); -static void set_stack_long(intptr_t *tos, jlong value, int offset); - -static void set_stack_double_from_addr(intptr_t *tos, address addr, int offset); -static void set_stack_long_from_addr(intptr_t *tos, address addr, int offset); - -// Locals - -static address locals_slot(intptr_t* locals, int offset); -static jint locals_int(intptr_t* locals, int offset); -static jfloat locals_float(intptr_t* locals, int offset); -static oop locals_object(intptr_t* locals, int offset); -static jdouble locals_double(intptr_t* locals, int offset); -static jlong locals_long(intptr_t* locals, int offset); - -static address locals_long_at(intptr_t* locals, int offset); -static address locals_double_at(intptr_t* locals, int offset); - -static void set_locals_slot(intptr_t *locals, address value, int offset); -static void set_locals_int(intptr_t *locals, jint value, int offset); -static void set_locals_float(intptr_t *locals, jfloat value, int offset); -static void set_locals_object(intptr_t *locals, oop value, int offset); -static void set_locals_double(intptr_t *locals, jdouble value, int offset); -static void set_locals_long(intptr_t *locals, jlong value, int offset); -static void set_locals_double_from_addr(intptr_t *locals, - address addr, int offset); -static void set_locals_long_from_addr(intptr_t *locals, - address addr, int offset); static void astore(intptr_t* topOfStack, int stack_offset, intptr_t* locals, int locals_offset); diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreterWithChecks.xml b/src/hotspot/share/interpreter/zero/bytecodeInterpreterWithChecks.xml deleted file mode 100644 index 8cbf66593c7..00000000000 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreterWithChecks.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - -]> - - diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreterWithChecks.xsl b/src/hotspot/share/interpreter/zero/bytecodeInterpreterWithChecks.xsl deleted file mode 100644 index 14546dfc9a3..00000000000 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreterWithChecks.xsl +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - -#define VM_JVMTI -#include "interpreter/zero/bytecodeInterpreter.cpp" - - - - - - - - diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 466e6c8e035..a412b16040b 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -2295,6 +2295,7 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas // 1) Try JNI short style stringStream st; char* pure_name = NativeLookup::pure_jni_name(method); + guarantee(pure_name != NULL, "Illegal native method name encountered"); os::print_jni_name_prefix_on(&st, args_size); st.print_raw(pure_name); os::print_jni_name_suffix_on(&st, args_size); @@ -2305,6 +2306,7 @@ C2V_VMENTRY_NULL(jlongArray, registerNativeMethods, (JNIEnv* env, jobject, jclas // 2) Try JNI long style st.reset(); char* long_name = NativeLookup::long_jni_name(method); + guarantee(long_name != NULL, "Illegal native method name encountered"); os::print_jni_name_prefix_on(&st, args_size); st.print_raw(pure_name); st.print_raw(long_name); diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index c6cd21c27f5..323537b012c 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -110,9 +110,7 @@ void LogConfiguration::initialize(jlong vm_start_time) { } void LogConfiguration::finalize() { - for (size_t i = _n_outputs; i > 0; i--) { - disable_output(i - 1); - } + disable_outputs(); FREE_C_HEAP_ARRAY(LogOutput*, _outputs); } @@ -272,28 +270,31 @@ void LogConfiguration::configure_output(size_t idx, const LogSelectionList& sele assert(strlen(output->config_string()) > 0, "should always have a config description"); } -void LogConfiguration::disable_output(size_t idx) { - assert(idx < _n_outputs, "invalid index: " SIZE_FORMAT " (_n_outputs: " SIZE_FORMAT ")", idx, _n_outputs); - LogOutput* out = _outputs[idx]; +void LogConfiguration::disable_outputs() { + size_t idx = _n_outputs; - // Remove the output from all tagsets. + // Remove all outputs from all tagsets. for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { - ts->set_output_level(out, LogLevel::Off); - ts->update_decorators(); + ts->disable_outputs(); } - // Delete the output unless stdout or stderr (idx 0 or 1) - if (idx > 1) { - delete_output(idx); - } else { - out->set_config_string("all=off"); + while (idx > 0) { + LogOutput* out = _outputs[--idx]; + // Delete the output unless stdout or stderr (idx 0 or 1) + if (idx > 1) { + delete_output(idx); + } else { + out->set_config_string("all=off"); + } } } void LogConfiguration::disable_logging() { ConfigurationLock cl; - for (size_t i = _n_outputs; i > 0; i--) { - disable_output(i - 1); + disable_outputs(); + // Update the decorators on all tagsets to get rid of unused decorators + for (LogTagSet* ts = LogTagSet::first(); ts != NULL; ts = ts->next()) { + ts->update_decorators(); } notify_update_listeners(); } diff --git a/src/hotspot/share/logging/logConfiguration.hpp b/src/hotspot/share/logging/logConfiguration.hpp index 635a801312b..34c0c07b76a 100644 --- a/src/hotspot/share/logging/logConfiguration.hpp +++ b/src/hotspot/share/logging/logConfiguration.hpp @@ -69,8 +69,8 @@ class LogConfiguration : public AllStatic { // Output should be completely disabled before it is deleted. static void delete_output(size_t idx); - // Disable all logging to the specified output and then delete it (unless it is stdout/stderr). - static void disable_output(size_t idx); + // Disable all logging to all outputs. All outputs except stdout/stderr will be deleted. + static void disable_outputs(); // Get output index by name. Returns SIZE_MAX if output not found. static size_t find_output(const char* name); diff --git a/src/hotspot/share/logging/logOutputList.cpp b/src/hotspot/share/logging/logOutputList.cpp index 56525505ef4..91139c900cf 100644 --- a/src/hotspot/share/logging/logOutputList.cpp +++ b/src/hotspot/share/logging/logOutputList.cpp @@ -68,6 +68,25 @@ LogOutputList::LogOutputNode* LogOutputList::find(const LogOutput* output) const return NULL; } +void LogOutputList::clear() { + + // Grab the linked list + LogOutputNode* cur = _level_start[LogLevel::Last]; + + // Clear _level_start + for (uint level = LogLevel::First; level < LogLevel::Count; level++) { + _level_start[level] = NULL; + } + + // Delete all nodes from the linked list + wait_until_no_readers(); + while (cur != NULL) { + LogOutputNode* next = cur->_next; + delete cur; + cur = next; + } +} + void LogOutputList::remove_output(LogOutputList::LogOutputNode* node) { assert(node != NULL, "Node must be non-null"); diff --git a/src/hotspot/share/logging/logOutputList.hpp b/src/hotspot/share/logging/logOutputList.hpp index 47b37b6bbb0..d02f50cc8b2 100644 --- a/src/hotspot/share/logging/logOutputList.hpp +++ b/src/hotspot/share/logging/logOutputList.hpp @@ -88,6 +88,10 @@ class LogOutputList { // Set (add/update/remove) the output to the specified level. void set_output_level(LogOutput* output, LogLevelType level); + // Removes all outputs. Equivalent of set_output_level(out, Off) + // for all outputs. + void clear(); + class Iterator { friend class LogOutputList; private: diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index 5b79f88a18d..75cf58e797d 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -95,6 +95,7 @@ LOG_TAG(jit) \ LOG_TAG(jni) \ LOG_TAG(jvmti) \ + LOG_TAG(lambda) \ LOG_TAG(library) \ LOG_TAG(liveness) \ LOG_TAG(load) /* Trace all classes loaded */ \ diff --git a/src/hotspot/share/logging/logTagSet.hpp b/src/hotspot/share/logging/logTagSet.hpp index 45c33c96c58..af092473eff 100644 --- a/src/hotspot/share/logging/logTagSet.hpp +++ b/src/hotspot/share/logging/logTagSet.hpp @@ -98,6 +98,10 @@ class LogTagSet { return _output_list.level_for(output); } + void disable_outputs() { + _output_list.clear(); + } + void set_output_level(LogOutput* output, LogLevelType level) { _output_list.set_output_level(output, level); } diff --git a/src/hotspot/share/memory/heapShared.cpp b/src/hotspot/share/memory/heapShared.cpp index 8527df81a16..72f9dbc69a2 100644 --- a/src/hotspot/share/memory/heapShared.cpp +++ b/src/hotspot/share/memory/heapShared.cpp @@ -53,6 +53,7 @@ #include "runtime/javaCalls.hpp" #include "runtime/safepointVerifiers.hpp" #include "utilities/bitMap.inline.hpp" +#include "utilities/copy.hpp" #if INCLUDE_G1GC #include "gc/g1/g1CollectedHeap.hpp" #endif diff --git a/src/hotspot/share/memory/heapShared.inline.hpp b/src/hotspot/share/memory/heapShared.inline.hpp index b27996251c1..a022fcfb4bc 100644 --- a/src/hotspot/share/memory/heapShared.inline.hpp +++ b/src/hotspot/share/memory/heapShared.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,15 @@ #ifndef SHARE_MEMORY_HEAPSHARED_INLINE_HPP #define SHARE_MEMORY_HEAPSHARED_INLINE_HPP +#include "gc/shared/collectedHeap.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "memory/heapShared.hpp" #include "utilities/align.hpp" -#if INCLUDE_G1GC -#include "gc/g1/g1Allocator.inline.hpp" -#endif #if INCLUDE_CDS_JAVA_HEAP bool HeapShared::is_archived_object(oop p) { - return (p == NULL) ? false : G1ArchiveAllocator::is_archived_object(p); + return Universe::heap()->is_archived_object(p); } inline oop HeapShared::decode_from_archive(narrowOop v) { diff --git a/src/hotspot/share/memory/metaspaceShared.cpp b/src/hotspot/share/memory/metaspaceShared.cpp index f3af404e783..9ee35a57361 100644 --- a/src/hotspot/share/memory/metaspaceShared.cpp +++ b/src/hotspot/share/memory/metaspaceShared.cpp @@ -71,7 +71,7 @@ #include "utilities/defaultStream.hpp" #include "utilities/hashtable.inline.hpp" #if INCLUDE_G1GC -#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1CollectedHeap.inline.hpp" #endif ReservedSpace MetaspaceShared::_shared_rs; diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 207115b393e..e400876cf2d 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -3800,9 +3800,19 @@ void InstanceKlass::oop_print_value_on(oop obj, outputStream* st) { st->print(" = "); vmtarget->print_value_on(st); } else { - java_lang_invoke_MemberName::clazz(obj)->print_value_on(st); + oop clazz = java_lang_invoke_MemberName::clazz(obj); + oop name = java_lang_invoke_MemberName::name(obj); + if (clazz != NULL) { + clazz->print_value_on(st); + } else { + st->print("NULL"); + } st->print("."); - java_lang_invoke_MemberName::name(obj)->print_value_on(st); + if (name != NULL) { + name->print_value_on(st); + } else { + st->print("NULL"); + } } } } diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index 2c8ad2414db..acc007d2d48 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.cpp @@ -25,20 +25,55 @@ #include "precompiled.hpp" #include "oops/markWord.hpp" #include "runtime/thread.inline.hpp" -#include "runtime/objectMonitor.hpp" +#include "runtime/objectMonitor.inline.hpp" #include "utilities/ostream.hpp" -void markWord::print_on(outputStream* st) const { +markWord markWord::displaced_mark_helper() const { + assert(has_displaced_mark_helper(), "check"); + if (has_monitor()) { + // Has an inflated monitor. Must be checked before has_locker(). + ObjectMonitor* monitor = this->monitor(); + return monitor->header(); + } + if (has_locker()) { // has a stack lock + BasicLock* locker = this->locker(); + return locker->displaced_header(); + } + // This should never happen: + fatal("bad header=" INTPTR_FORMAT, value()); + return markWord(value()); +} + +void markWord::set_displaced_mark_helper(markWord m) const { + assert(has_displaced_mark_helper(), "check"); + if (has_monitor()) { + // Has an inflated monitor. Must be checked before has_locker(). + ObjectMonitor* monitor = this->monitor(); + monitor->set_header(m); + return; + } + if (has_locker()) { // has a stack lock + BasicLock* locker = this->locker(); + locker->set_displaced_header(m); + return; + } + // This should never happen: + fatal("bad header=" INTPTR_FORMAT, value()); +} + +void markWord::print_on(outputStream* st, bool print_monitor_info) const { if (is_marked()) { // last bits = 11 st->print(" marked(" INTPTR_FORMAT ")", value()); } else if (has_monitor()) { // last bits = 10 // have to check has_monitor() before is_locked() st->print(" monitor(" INTPTR_FORMAT ")=", value()); - ObjectMonitor* mon = monitor(); - if (mon == NULL) { - st->print("NULL (this should never be seen!)"); - } else { - mon->print_on(st); + if (print_monitor_info) { + ObjectMonitor* mon = monitor(); + if (mon == NULL) { + st->print("NULL (this should never be seen!)"); + } else { + mon->print_on(st); + } } } else if (is_locked()) { // last bits != 01 => 00 // thin locked diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 0a5ad4b5861..36ba1427f13 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -393,16 +393,8 @@ class markWord { bool has_displaced_mark_helper() const { return ((value() & unlocked_value) == 0); } - markWord displaced_mark_helper() const { - assert(has_displaced_mark_helper(), "check"); - uintptr_t ptr = (value() & ~monitor_value); - return *(markWord*)ptr; - } - void set_displaced_mark_helper(markWord m) const { - assert(has_displaced_mark_helper(), "check"); - uintptr_t ptr = (value() & ~monitor_value); - ((markWord*)ptr)->_value = m._value; - } + markWord displaced_mark_helper() const; + void set_displaced_mark_helper(markWord m) const; markWord copy_set_hash(intptr_t hash) const { uintptr_t tmp = value() & (~hash_mask_in_place); tmp |= ((hash & hash_mask) << hash_shift); @@ -495,7 +487,7 @@ class markWord { static inline markWord prototype_for_klass(const Klass* klass); // Debugging - void print_on(outputStream* st) const; + void print_on(outputStream* st, bool print_monitor_info = true) const; // Prepare address of oop for placement into mark inline static markWord encode_pointer_as_mark(void* p) { return from_pointer(p).set_marked(); } diff --git a/src/hotspot/share/opto/arraycopynode.cpp b/src/hotspot/share/opto/arraycopynode.cpp index 2d4ec6ed821..27497a4a2bb 100644 --- a/src/hotspot/share/opto/arraycopynode.cpp +++ b/src/hotspot/share/opto/arraycopynode.cpp @@ -189,7 +189,7 @@ Node* ArrayCopyNode::try_clone_instance(PhaseGVN *phase, bool can_reshape, int c const Type* src_type = phase->type(base_src); - MergeMemNode* mem = MergeMemNode::make(in_mem); + MergeMemNode* mem = phase->transform(MergeMemNode::make(in_mem))->as_MergeMem(); const TypeInstPtr* inst_src = src_type->isa_instptr(); @@ -447,7 +447,7 @@ void ArrayCopyNode::array_copy_forward(GraphKit& kit, for (int i = 0; i < count; i++) { copy(kit, atp_src, atp_dest, i, base_src, base_dest, adr_src, adr_dest, copy_type, value_type); } - } else if(can_reshape) { + } else if (can_reshape) { PhaseGVN& gvn = kit.gvn(); assert(gvn.is_IterGVN(), ""); gvn.record_for_igvn(adr_src); diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 365c3e7c40d..4ad848a634b 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -360,9 +360,6 @@ "Limit of ops to make speculative when using CMOVE") \ range(0, max_jint) \ \ - product(bool, UseRDPCForConstantTableBase, false, \ - "Use Sparc RDPC instruction for the constant table base.") \ - \ notproduct(bool, PrintIdealGraph, false, \ "Print ideal graph to XML file / network interface. " \ "By default attempts to connect to the visualizer on a socket.") \ diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index c40ff774fed..b7c14320204 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -849,7 +849,8 @@ bool RegionNode::optimize_trichotomy(PhaseIterGVN* igvn) { cmp2->Opcode() == Op_CmpF || cmp2->Opcode() == Op_CmpD || cmp1->Opcode() == Op_CmpP || cmp1->Opcode() == Op_CmpN || cmp2->Opcode() == Op_CmpP || cmp2->Opcode() == Op_CmpN || - cmp1->is_SubTypeCheck() || cmp2->is_SubTypeCheck()) { + cmp1->is_SubTypeCheck() || cmp2->is_SubTypeCheck() || + cmp1->is_FlatArrayCheck() || cmp2->is_FlatArrayCheck()) { // Floats and pointers don't exactly obey trichotomy. To be on the safe side, don't transform their tests. // SubTypeCheck is not commutative return false; @@ -2339,12 +2340,7 @@ Node *PhiNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* phi = mms.memory(); mms.set_memory(phase->transform(phi)); } - if (igvn) { // Unhook. - igvn->hash_delete(hook); - for (uint i = 1; i < hook->req(); i++) { - hook->set_req(i, NULL); - } - } + hook->destruct(igvn); // Replace self with the result. return result; } diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 19502e472e6..5733944a371 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -401,7 +401,7 @@ class IfNode : public MultiBranchNode { // Returns NULL is it couldn't improve the type. static const TypeInt* filtered_int_type(PhaseGVN* phase, Node* val, Node* if_proj); - bool is_non_flattened_array_check(PhaseTransform* phase, Node** array = NULL); + bool is_flat_array_check(PhaseTransform* phase, Node** array = NULL); #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; diff --git a/src/hotspot/share/opto/classes.hpp b/src/hotspot/share/opto/classes.hpp index dd955ae2d05..074e55d442f 100644 --- a/src/hotspot/share/opto/classes.hpp +++ b/src/hotspot/share/opto/classes.hpp @@ -161,6 +161,7 @@ macro(EncodeP) macro(EncodePKlass) macro(FastLock) macro(FastUnlock) +macro(FlatArrayCheck) macro(FmaD) macro(FmaF) macro(Goto) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 5a007d89e3b..0955c8ad696 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1136,8 +1136,7 @@ void Compile::print_missing_nodes() { } } void Compile::record_modified_node(Node* n) { - if (_modified_nodes != NULL && !_inlining_incrementally && - n->outcnt() != 0 && !n->is_Con()) { + if (_modified_nodes != NULL && !_inlining_incrementally && !n->is_Con()) { _modified_nodes->push(n); } } @@ -2172,7 +2171,7 @@ void Compile::adjust_flattened_array_access_aliases(PhaseIterGVN& igvn) { Node* hook = new Node(1); hook->init_req(0, mm); igvn.replace_node(place_holder, mm_clone); - hook->destruct(); + hook->destruct(&igvn); } assert(!m->has_out_with(Op_Node), "place holder should be gone now"); } diff --git a/src/hotspot/share/opto/convertnode.cpp b/src/hotspot/share/opto/convertnode.cpp index fa556b16dd5..c08e8591fb1 100644 --- a/src/hotspot/share/opto/convertnode.cpp +++ b/src/hotspot/share/opto/convertnode.cpp @@ -258,14 +258,30 @@ static inline bool long_ranges_overlap(jlong lo1, jlong hi1, // Two ranges overlap iff one range's low point falls in the other range. return (lo2 <= lo1 && lo1 <= hi2) || (lo1 <= lo2 && lo2 <= hi1); } + +// If there is an existing ConvI2L node with the given parent and type, return +// it. Otherwise, create and return a new one. Both reusing existing ConvI2L +// nodes and postponing the idealization of new ones are needed to avoid an +// explosion of recursive Ideal() calls when compiling long AddI chains. +static Node* find_or_make_convI2L(PhaseIterGVN* igvn, Node* parent, + const TypeLong* type) { + Node* n = new ConvI2LNode(parent, type); + Node* existing = igvn->hash_find_insert(n); + if (existing != NULL) { + n->destruct(igvn); + return existing; + } + return igvn->register_new_node_with_optimizer(n); +} #endif //------------------------------Ideal------------------------------------------ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { + PhaseIterGVN *igvn = phase->is_IterGVN(); const TypeLong* this_type = this->type()->is_long(); Node* this_changed = NULL; - if (can_reshape) { + if (igvn != NULL) { // Do NOT remove this node's type assertion until no more loop ops can happen. if (phase->C->post_loop_opts_phase()) { const TypeInt* in_type = phase->type(in(1))->isa_int(); @@ -334,10 +350,9 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* z = in(1); int op = z->Opcode(); if (op == Op_AddI || op == Op_SubI) { - if (!can_reshape) { - // Postpone this optimization to after parsing because with deep AddNode - // chains a large amount of dead ConvI2L nodes might be created that are - // not removed during parsing. As a result, we might hit the node limit. + if (igvn == NULL) { + // Postpone this optimization to iterative GVN, where we can handle deep + // AddI chains without an exponential number of recursive Ideal() calls. phase->record_for_igvn(this); return this_changed; } @@ -399,12 +414,8 @@ Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) { } assert(rxlo == (int)rxlo && rxhi == (int)rxhi, "x should not overflow"); assert(rylo == (int)rylo && ryhi == (int)ryhi, "y should not overflow"); - Node* cx = phase->C->constrained_convI2L(phase, x, TypeInt::make(rxlo, rxhi, widen), NULL); - Node *hook = new Node(1); - hook->init_req(0, cx); // Add a use to cx to prevent him from dying - Node* cy = phase->C->constrained_convI2L(phase, y, TypeInt::make(rylo, ryhi, widen), NULL); - hook->del_req(0); // Just yank bogus edge - hook->destruct(); + Node* cx = find_or_make_convI2L(igvn, x, TypeLong::make(rxlo, rxhi, widen)); + Node* cy = find_or_make_convI2L(igvn, y, TypeLong::make(rylo, ryhi, widen)); switch (op) { case Op_AddI: return new AddLNode(cx, cy); case Op_SubI: return new SubLNode(cx, cy); diff --git a/src/hotspot/share/opto/divnode.cpp b/src/hotspot/share/opto/divnode.cpp index ef2b5b8d257..19acf2b4d2a 100644 --- a/src/hotspot/share/opto/divnode.cpp +++ b/src/hotspot/share/opto/divnode.cpp @@ -326,14 +326,7 @@ static Node* long_by_long_mulhi(PhaseGVN* phase, Node* dividend, jlong magic_con Node* temp2 = phase->transform(new RShiftLNode(w1, phase->intcon(N / 2))); // Remove the bogus extra edges used to keep things alive - PhaseIterGVN* igvn = phase->is_IterGVN(); - if (igvn != NULL) { - igvn->remove_dead_node(hook); - } else { - for (int i = 0; i < 4; i++) { - hook->set_req(i, NULL); - } - } + hook->destruct(phase); return new AddLNode(temp1, temp2); } @@ -916,11 +909,7 @@ Node *ModINode::Ideal(PhaseGVN *phase, bool can_reshape) { // cmov2 is now the mod // Now remove the bogus extra edges used to keep things alive - if (can_reshape) { - phase->is_IterGVN()->remove_dead_node(hook); - } else { - hook->set_req(0, NULL); // Just yank bogus edge during Parse phase - } + hook->destruct(phase); return cmov2; } } @@ -972,11 +961,7 @@ Node *ModINode::Ideal(PhaseGVN *phase, bool can_reshape) { } // Now remove the bogus extra edges used to keep things alive - if (can_reshape) { - phase->is_IterGVN()->remove_dead_node(hook); - } else { - hook->set_req(0, NULL); // Just yank bogus edge during Parse phase - } + hook->destruct(phase); // return the value return result; @@ -1091,11 +1076,7 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) { // cmov2 is now the mod // Now remove the bogus extra edges used to keep things alive - if (can_reshape) { - phase->is_IterGVN()->remove_dead_node(hook); - } else { - hook->set_req(0, NULL); // Just yank bogus edge during Parse phase - } + hook->destruct(phase); return cmov2; } } @@ -1147,11 +1128,7 @@ Node *ModLNode::Ideal(PhaseGVN *phase, bool can_reshape) { } // Now remove the bogus extra edges used to keep things alive - if (can_reshape) { - phase->is_IterGVN()->remove_dead_node(hook); - } else { - hook->set_req(0, NULL); // Just yank bogus edge during Parse phase - } + hook->destruct(phase); // return the value return result; diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index bc0a958a3e7..f2a4f3a0fca 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -1638,21 +1638,28 @@ int ConnectionGraph::find_init_values(JavaObjectNode* pta, PointsToNode* init_va if (init_val == phantom_obj) { // Do nothing for Allocate nodes since its fields values are // "known" unless they are initialized by arraycopy/clone. - if (alloc->is_Allocate() && !pta->arraycopy_dst()) - return 0; - assert(pta->arraycopy_dst() || alloc->as_CallStaticJava(), "sanity"); + if (alloc->is_Allocate() && !pta->arraycopy_dst()) { + if (alloc->as_Allocate()->in(AllocateNode::DefaultValue) != NULL) { + // Non-flattened inline type arrays are initialized with + // the default value instead of null. Handle them here. + init_val = ptnode_adr(alloc->as_Allocate()->in(AllocateNode::DefaultValue)->_idx); + assert(init_val != NULL, "default value should be registered"); + } else { + return 0; + } + } + // Non-escaped allocation returned from Java or runtime call has unknown values in fields. + assert(pta->arraycopy_dst() || alloc->is_CallStaticJava() || init_val != phantom_obj, "sanity"); #ifdef ASSERT - if (!pta->arraycopy_dst() && alloc->as_CallStaticJava()->method() == NULL) { + if (alloc->is_CallStaticJava() && alloc->as_CallStaticJava()->method() == NULL) { const char* name = alloc->as_CallStaticJava()->_name; assert(strncmp(name, "_multianewarray", 15) == 0, "sanity"); } #endif - // Non-escaped allocation returned from Java or runtime call have - // unknown values in fields. for (EdgeIterator i(pta); i.has_next(); i.next()) { PointsToNode* field = i.get(); if (field->is_Field() && field->as_Field()->is_oop()) { - if (add_edge(field, phantom_obj)) { + if (add_edge(field, init_val)) { // New edge was added new_edges++; add_field_uses_to_worklist(field->as_Field()); @@ -1663,8 +1670,9 @@ int ConnectionGraph::find_init_values(JavaObjectNode* pta, PointsToNode* init_va } assert(init_val == null_obj, "sanity"); // Do nothing for Call nodes since its fields values are unknown. - if (!alloc->is_Allocate()) + if (!alloc->is_Allocate() || alloc->as_Allocate()->in(AllocateNode::DefaultValue) != NULL) { return 0; + } InitializeNode* ini = alloc->as_Allocate()->initialization(); bool visited_bottom_offset = false; @@ -3496,7 +3504,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, } else if (!(BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use) || op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives || op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || - op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar)) { + op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar || op == Op_FlatArrayCheck)) { n->dump(); use->dump(); assert(false, "EA: missing memory path"); diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index 80e1cb95731..d246671d1ab 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -3517,7 +3517,7 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, Node* *failure_contro if (region->req() == 3 && region->in(2) != NULL && region->in(2)->in(0) != NULL) { IfNode* iff = region->in(2)->in(0)->isa_If(); if (iff != NULL) { - iff->is_non_flattened_array_check(&_gvn, &array); + iff->is_flat_array_check(&_gvn, &array); } } } @@ -3548,8 +3548,8 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass, Node* *failure_contro } Node* GraphKit::inline_type_test(Node* obj, bool is_inline) { - Node* mark_addr = basic_plus_adr(obj, oopDesc::mark_offset_in_bytes()); - Node* mark = make_load(NULL, mark_addr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered); + Node* mark_adr = basic_plus_adr(obj, oopDesc::mark_offset_in_bytes()); + Node* mark = make_load(NULL, mark_adr, TypeX_X, TypeX_X->basic_type(), MemNode::unordered); Node* mask = MakeConX(markWord::inline_type_pattern); Node* masked = _gvn.transform(new AndXNode(mark, mask)); Node* cmp = _gvn.transform(new CmpXNode(masked, mask)); @@ -3566,8 +3566,12 @@ Node* GraphKit::array_lh_test(Node* klass, jint mask, jint val, bool eq) { } Node* GraphKit::flat_array_test(Node* ary, bool flat) { - Node* klass = load_object_klass(ary); - return array_lh_test(klass, Klass::_lh_array_tag_vt_value_bit_inplace, 0, !flat); + // We can't use immutable memory here because the mark word is mutable. + // PhaseIdealLoop::move_flat_array_check_out_of_loop will make sure the + // check is moved out of loops (mainly to enable loop unswitching). + Node* mem = UseArrayMarkWordCheck ? memory(Compile::AliasIdxRaw) : immutable_memory(); + Node* cmp = _gvn.transform(new FlatArrayCheckNode(C, mem, ary)); + return _gvn.transform(new BoolNode(cmp, flat ? BoolTest::eq : BoolTest::ne)); } Node* GraphKit::null_free_array_test(Node* klass, bool null_free) { diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index c3384bd9cd3..627d8c9c52a 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -999,8 +999,7 @@ bool IfNode::fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* f if (adjusted_lim == NULL) { adjusted_lim = igvn->transform(new SubINode(hi, lo)); } - hook->del_req(0); // Just yank bogus edge - hook->destruct(); + hook->destruct(igvn); Node* newcmp = igvn->transform(new CmpUNode(adjusted_val, adjusted_lim)); Node* newbool = igvn->transform(new BoolNode(newcmp, cond)); @@ -1181,51 +1180,21 @@ bool IfNode::is_null_check(ProjNode* proj, PhaseIterGVN* igvn) { return false; } -// Returns true if this IfNode belongs to a non-flattened array check +// Returns true if this IfNode belongs to a flat array check // and returns the corresponding array in the 'array' parameter. -bool IfNode::is_non_flattened_array_check(PhaseTransform* phase, Node** array) { +bool IfNode::is_flat_array_check(PhaseTransform* phase, Node** array) { Node* bol = in(1); if (!bol->is_Bool()) { return false; } Node* cmp = bol->in(1); - if (cmp->Opcode() != Op_CmpI) { - return false; - } - Node* cmp_in1 = cmp->in(1); - Node* cmp_in2 = cmp->in(2); - if (cmp_in2->find_int_con(-1) != 0) { - return false; - } - if (cmp_in1->Opcode() != Op_AndI) { - return false; - } - Node* and_in1 = cmp_in1->in(1); - Node* and_in2 = cmp_in1->in(2); - if (and_in2->find_int_con(0) != Klass::_lh_array_tag_vt_value_bit_inplace) { - return false; - } - if (and_in1->Opcode() != Op_LoadI) { - return false; - } - intptr_t offset; - Node* ptr = and_in1->in(MemNode::Address); - Node* addr = AddPNode::Ideal_base_and_offset(ptr, phase, offset); - if (addr == NULL || offset != in_bytes(Klass::layout_helper_offset())) { - return false; - } - if (!phase->type(addr)->isa_klassptr()) { - return false; - } - Node* klass_load = ptr->as_AddP()->in(AddPNode::Base)->uncast(); - if (klass_load->is_DecodeNKlass()) { - klass_load = klass_load->in(1); - } - if (array != NULL && klass_load->is_Load()) { - Node* address = klass_load->in(MemNode::Address); - *array = address->as_AddP()->in(AddPNode::Base); + if (cmp->isa_FlatArrayCheck()) { + if (array != NULL) { + *array = cmp->in(FlatArrayCheckNode::Array); + } + return true; } - return true; + return false; } // Check that the If that is in between the 2 integer comparisons has diff --git a/src/hotspot/share/opto/indexSet.cpp b/src/hotspot/share/opto/indexSet.cpp index f4a596a4ff3..eb90151eef0 100644 --- a/src/hotspot/share/opto/indexSet.cpp +++ b/src/hotspot/share/opto/indexSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,7 +241,7 @@ IndexSet::IndexSet (IndexSet *set) { set_block(i, &_empty_block); } else { BitBlock *new_block = alloc_block(); - memcpy(new_block->words(), block->words(), sizeof(uint32_t) * words_per_block); + memcpy(new_block->words(), block->words(), sizeof(uintptr_t) * words_per_block); set_block(i, new_block); } } diff --git a/src/hotspot/share/opto/indexSet.hpp b/src/hotspot/share/opto/indexSet.hpp index 5f57faaeb32..7ed34116d1c 100644 --- a/src/hotspot/share/opto/indexSet.hpp +++ b/src/hotspot/share/opto/indexSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,9 +60,12 @@ class IndexSet : public ResourceObj { // membership of the element in the set. // The lengths of the index bitfields - enum { bit_index_length = 5, - word_index_length = 3, - block_index_length = 8 // not used + enum { + // Each block consists of 256 bits + block_index_length = 8, + // Split over 4 or 8 words depending on bitness + word_index_length = block_index_length - LogBitsPerWord, + bit_index_length = block_index_length - word_index_length, }; // Derived constants used for manipulating the index bitfields @@ -88,7 +91,7 @@ class IndexSet : public ResourceObj { return mask_bits(element >> word_index_offset,word_index_mask); } static uint get_bit_index(uint element) { - return mask_bits(element,bit_index_mask); + return mask_bits(element, bit_index_mask); } //------------------------------ class BitBlock ---------------------------- @@ -102,17 +105,17 @@ class IndexSet : public ResourceObj { // All of BitBlocks fields and methods are declared private. We limit // access to IndexSet and IndexSetIterator. - // A BitBlock is composed of some number of 32 bit words. When a BitBlock + // A BitBlock is composed of some number of 32- or 64-bit words. When a BitBlock // is not in use by any IndexSet, it is stored on a free list. The next field - // is used by IndexSet to mainting this free list. + // is used by IndexSet to maintain this free list. union { - uint32_t _words[words_per_block]; + uintptr_t _words[words_per_block]; BitBlock *_next; } _data; // accessors - uint32_t* words() { return _data._words; } + uintptr_t* words() { return _data._words; } void set_next(BitBlock *next) { _data._next = next; } BitBlock *next() { return _data._next; } @@ -121,32 +124,32 @@ class IndexSet : public ResourceObj { // not assume that the block index has been masked out. void clear() { - memset(words(), 0, sizeof(uint32_t) * words_per_block); + memset(words(), 0, sizeof(uintptr_t) * words_per_block); } bool member(uint element) { uint word_index = IndexSet::get_word_index(element); - uint bit_index = IndexSet::get_bit_index(element); + uintptr_t bit_index = IndexSet::get_bit_index(element); - return ((words()[word_index] & (uint32_t)(0x1 << bit_index)) != 0); + return ((words()[word_index] & (uintptr_t(1) << bit_index)) != 0); } bool insert(uint element) { uint word_index = IndexSet::get_word_index(element); - uint bit_index = IndexSet::get_bit_index(element); + uintptr_t bit_index = IndexSet::get_bit_index(element); - uint32_t bit = (0x1 << bit_index); - uint32_t before = words()[word_index]; + uintptr_t bit = uintptr_t(1) << bit_index; + uintptr_t before = words()[word_index]; words()[word_index] = before | bit; return ((before & bit) != 0); } bool remove(uint element) { uint word_index = IndexSet::get_word_index(element); - uint bit_index = IndexSet::get_bit_index(element); + uintptr_t bit_index = IndexSet::get_bit_index(element); - uint32_t bit = (0x1 << bit_index); - uint32_t before = words()[word_index]; + uintptr_t bit = uintptr_t(1) << bit_index; + uintptr_t before = words()[word_index]; words()[word_index] = before & ~bit; return ((before & bit) != 0); } @@ -376,7 +379,7 @@ class IndexSetIterator { private: // The current word we are inspecting - uint32_t _current; + uintptr_t _current; // What element number are we currently on? uint _value; @@ -391,7 +394,7 @@ class IndexSetIterator { uint _max_blocks; // A pointer to the contents of the current block - uint32_t *_words; + uintptr_t* _words; // A pointer to the blocks in our set IndexSet::BitBlock **_blocks; @@ -447,7 +450,7 @@ class IndexSetIterator { // Return the next element of the set. uint next_value() { - uint current = _current; + uintptr_t current = _current; assert(current != 0, "sanity"); uint advance = count_trailing_zeros(current); assert(((current >> advance) & 0x1) == 1, "sanity"); diff --git a/src/hotspot/share/opto/lcm.cpp b/src/hotspot/share/opto/lcm.cpp index 2485b52f772..0a884238e8a 100644 --- a/src/hotspot/share/opto/lcm.cpp +++ b/src/hotspot/share/opto/lcm.cpp @@ -455,7 +455,7 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo tmp1->replace_by(tmp); tmp2->replace_by(tmp1); tmp->replace_by(tmp2); - tmp->destruct(); + tmp->destruct(NULL); } // Remove the existing null check; use a new implicit null check instead. diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index 7f04d2ac6c2..fbe0c94a474 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -727,7 +727,7 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree *loop, Node* ctrl, idx_type = (TypeInt*)mul->mul_ring(idx_type, scale_type); if (overflow || TypeInt::INT->higher_equal(idx_type)) { // May overflow - mul->destruct(); + mul->destruct(&_igvn); if (!overflow) { max_idx_expr = new ConvI2LNode(max_idx_expr); register_new_node(max_idx_expr, ctrl); diff --git a/src/hotspot/share/opto/loopUnswitch.cpp b/src/hotspot/share/opto/loopUnswitch.cpp index 88bf7363eb2..bf21d0ee0ac 100644 --- a/src/hotspot/share/opto/loopUnswitch.cpp +++ b/src/hotspot/share/opto/loopUnswitch.cpp @@ -124,10 +124,10 @@ IfNode* PhaseIdealLoop::find_unswitching_candidate(const IdealLoopTree *loop, No // Collect all non-flattened array checks for unswitching to create a fast loop // without checks (only non-flattened array accesses) and a slow loop with checks. - if (unswitch_iff == NULL || unswitch_iff->is_non_flattened_array_check(&_igvn)) { + if (unswitch_iff == NULL || unswitch_iff->is_flat_array_check(&_igvn)) { for (uint i = 0; i < loop->_body.size(); i++) { IfNode* n = loop->_body.at(i)->isa_If(); - if (n != NULL && n != unswitch_iff && n->is_non_flattened_array_check(&_igvn) && + if (n != NULL && n != unswitch_iff && n->is_flat_array_check(&_igvn) && loop->is_invariant(n->in(1)) && !loop->is_loop_exit(n)) { unswitch_iffs.push(n); if (unswitch_iff == NULL) { @@ -231,26 +231,18 @@ void PhaseIdealLoop::do_unswitching(IdealLoopTree *loop, Node_List &old_new) { // can be removed from the fast loop (true proj) but not from the // slow loop (false proj) as it can have a mix of flattened/legacy accesses. assert(bol->_test._test == BoolTest::ne, "IfTrue proj must point to flat array"); - // Adjust condition such that the true proj points to non-flat array - bol = new BoolNode(bol->in(1), bol->_test.negate()); - register_new_node(bol, invar_iff->in(0)); - Node* cmp = bol->in(1)->clone(); - register_new_node(cmp, invar_iff->in(0)); + bol = bol->clone()->as_Bool(); + register_new_node(bol, invar_iff_c); + FlatArrayCheckNode* cmp = bol->in(1)->clone()->as_FlatArrayCheck(); + register_new_node(cmp, invar_iff_c); bol->set_req(1, cmp); // Combine all checks into a single one that fails if one array is flattened - Node* lhs = NULL; + assert(cmp->req() == 3, "unexpected number of inputs for FlatArrayCheck"); + cmp->add_req_batch(C->top(), unswitch_iffs.size() - 1); for (uint i = 0; i < unswitch_iffs.size(); i++) { - Node* lh = unswitch_iffs.at(i)->in(1)->in(1)->in(1)->in(1); - if (lhs == NULL) { - lhs = lh; - } else { - lhs = new OrINode(lhs, lh); - register_new_node(lhs, invar_iff->in(0)); - } + Node* array = unswitch_iffs.at(i)->in(1)->in(1)->in(FlatArrayCheckNode::Array); + cmp->set_req(FlatArrayCheckNode::Array + i, array); } - Node* masked = new AndINode(lhs, _igvn.intcon(Klass::_lh_array_tag_vt_value_bit_inplace)); - register_new_node(masked, invar_iff->in(0)); - cmp->set_req(1, masked); } invar_iff->set_req(1, bol); @@ -267,7 +259,7 @@ void PhaseIdealLoop::do_unswitching(IdealLoopTree *loop, Node_List &old_new) { worklist.push(use); } } - ProjNode* invar_proj = invar_iff->proj_out(flat_array_checks ? (1-proj->_con) : proj->_con)->as_Proj(); + ProjNode* invar_proj = invar_iff->proj_out(proj->_con)->as_Proj(); while (worklist.size() > 0) { Node* use = worklist.pop(); Node* nuse = use->clone(); @@ -287,13 +279,13 @@ void PhaseIdealLoop::do_unswitching(IdealLoopTree *loop, Node_List &old_new) { for (uint i = 0; i < unswitch_iffs.size(); i++) { IfNode* iff = unswitch_iffs.at(i)->as_If(); _igvn.rehash_node_delayed(iff); - dominated_by(proj_true, iff, /* flip = */ flat_array_checks, false); + dominated_by(proj_true, iff); } IfNode* unswitch_iff_clone = old_new[unswitch_iff->_idx]->as_If(); if (!flat_array_checks) { ProjNode* proj_false = invar_iff->proj_out(0)->as_Proj(); _igvn.rehash_node_delayed(unswitch_iff_clone); - dominated_by(proj_false, unswitch_iff_clone, false, false); + dominated_by(proj_false, unswitch_iff_clone); } else { // Leave the flattened array checks in the slow loop and // prevent it from being unswitched again based on these checks. diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 7d0d2f1c485..8b42740937d 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -1400,8 +1400,6 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*& loop) { assert(x->Opcode() == Op_Loop, "regular loops only"); C->print_method(PHASE_BEFORE_CLOOPS, 3); - Node *hook = new Node(6); - // =================================================== // Generate loop limit check to avoid integer overflow // in cases like next (cyclic loops): @@ -1691,9 +1689,6 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*& loop) { } } - // Free up intermediate goo - _igvn.remove_dead_node(hook); - #ifdef ASSERT assert(l->is_valid_counted_loop(), "counted loop shape is messed up"); assert(l == loop->_head && l->phi() == phi && l->loopexit_or_null() == lex, "" ); @@ -2657,7 +2652,7 @@ void IdealLoopTree::split_fall_in( PhaseIdealLoop *phase, int fall_in_cnt ) { // with the CSE to avoid O(N^2) node blow-up. Node *p2 = igvn.hash_find_insert(p); // Look for a CSE if( p2 ) { // Found CSE - p->destruct(); // Recover useless new node + p->destruct(&igvn); // Recover useless new node p = p2; // Use old node } else { igvn.register_new_node_with_optimizer(p, old_phi); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index eda128fb9ab..52fb0ab950a 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1375,6 +1375,7 @@ class PhaseIdealLoop : public PhaseTransform { Node *place_near_use( Node *useblock ) const; Node* try_move_store_before_loop(Node* n, Node *n_ctrl); void try_move_store_after_loop(Node* n); + void move_flat_array_check_out_of_loop(Node* n); bool identical_backtoback_ifs(Node *n); bool flatten_array_element_type_check(Node *n); bool can_split_if(Node *n_ctrl); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 428f951a9b6..f89534b37d7 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -968,6 +968,56 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) { } } +// If UseArrayMarkWordCheck is enabled, we can't use immutable memory for the flat array check +// because we are loading the mark word which is mutable. Although the bits we are interested in +// are immutable (we check for markWord::unlocked_value), we need to use raw memory to not break +// anti dependency analysis. Below code will attempt to still move flat array checks out of loops, +// mainly to enable loop unswitching. +void PhaseIdealLoop::move_flat_array_check_out_of_loop(Node* n) { + // Skip checks for more than one array + if (n->req() > 3) { + return; + } + Node* mem = n->in(FlatArrayCheckNode::Memory); + Node* array = n->in(FlatArrayCheckNode::Array)->uncast(); + IdealLoopTree* check_loop = get_loop(get_ctrl(n)); + IdealLoopTree* ary_loop = get_loop(get_ctrl(array)); + + // Check if array is loop invariant + if (!check_loop->is_member(ary_loop)) { + // Walk up memory graph from the check until we leave the loop + ResourceMark rm; + VectorSet wq; + wq.set(mem->_idx); + while (check_loop->is_member(get_loop(ctrl_or_self(mem)))) { + if (mem->is_Phi()) { + mem = mem->in(1); + } else if (mem->is_MergeMem()) { + mem = mem->as_MergeMem()->memory_at(Compile::AliasIdxRaw); + } else if (mem->is_Proj()) { + mem = mem->in(0); + } else if (mem->is_MemBar() || mem->is_SafePoint()) { + mem = mem->in(TypeFunc::Memory); + } else if (mem->is_Store() || mem->is_LoadStore() || mem->is_ClearArray()) { + mem = mem->in(MemNode::Memory); + } else { +#ifdef ASSERT + mem->dump(); +#endif + ShouldNotReachHere(); + } + if (wq.test_set(mem->_idx)) { + return; + } + } + // Replace memory input and re-compute ctrl to move the check out of the loop + _igvn.replace_input_of(n, 1, mem); + set_ctrl_and_loop(n, get_early_ctrl(n)); + Node* bol = n->unique_out(); + set_ctrl_and_loop(bol, get_early_ctrl(bol)); + } +} + //------------------------------split_if_with_blocks_pre----------------------- // Do the real work in a non-recursive function. Data nodes want to be // cloned in the pre-order so they can feed each other nicely. @@ -980,6 +1030,12 @@ Node *PhaseIdealLoop::split_if_with_blocks_pre( Node *n ) { if (n->is_Proj()) { return n; } + + if (UseArrayMarkWordCheck && n->isa_FlatArrayCheck()) { + move_flat_array_check_out_of_loop(n); + return n; + } + // Do not clone-up CmpFXXX variations, as these are always // followed by a CmpI if (n->is_Cmp()) { diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp index 9fb42edba44..c504b84f79f 100644 --- a/src/hotspot/share/opto/machnode.cpp +++ b/src/hotspot/share/opto/machnode.cpp @@ -295,7 +295,7 @@ const Node* MachNode::get_base_and_disp(intptr_t &offset, const TypePtr* &adr_ty } offset = disp; - // In i486.ad, indOffset32X uses base==RegI and disp==RegP, + // In x86_32.ad, indOffset32X uses base==RegI and disp==RegP, // this will prevent alias analysis without the following support: // Lookup the TypePtr used by indOffset32X, a compile-time constant oop, // Add the offset determined by the "base", or use Type::OffsetBot. diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp index 2aa2dac6ae0..7758c361513 100644 --- a/src/hotspot/share/opto/machnode.hpp +++ b/src/hotspot/share/opto/machnode.hpp @@ -152,7 +152,7 @@ class MachOper : public ResourceObj { virtual int index_position() const; // index edge position, or -1 // Access the TypeKlassPtr of operands with a base==RegI and disp==RegP - // Only returns non-null value for i486.ad's indOffset32X + // Only returns non-null value for x86_32.ad's indOffset32X virtual const TypePtr *disp_as_type() const { return NULL; } // Return the label @@ -435,7 +435,6 @@ class MachConstantBaseNode : public MachIdealNode { virtual void emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const; virtual uint size(PhaseRegAlloc* ra_) const; - virtual bool pinned() const { return UseRDPCForConstantTableBase; } static const RegMask& static_out_RegMask() { return _out_RegMask; } virtual const RegMask& out_RegMask() const { return static_out_RegMask(); } diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 585be5270a9..517a8b3f99f 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -319,7 +319,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, Node* base = ac->in(ArrayCopyNode::Src); Node* adr = _igvn.transform(new AddPNode(base, base, MakeConX(offset))); const TypePtr* adr_type = _igvn.type(base)->is_ptr()->add_offset(offset); - MergeMemNode* mergemen = MergeMemNode::make(mem); + MergeMemNode* mergemen = _igvn.transform(MergeMemNode::make(mem))->as_MergeMem(); BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); res = ArrayCopyNode::load(bs, &_igvn, ctl, mergemen, adr, adr_type, type, bt); } else { @@ -368,7 +368,7 @@ Node* PhaseMacroExpand::make_arraycopy_load(ArrayCopyNode* ac, intptr_t offset, adr_type = adr_type->is_aryptr()->add_field_offset_and_offset(offset)->add_offset(Type::OffsetBot); adr = _igvn.transform(new CastPPNode(adr, adr_type)); } - MergeMemNode* mergemen = MergeMemNode::make(mem); + MergeMemNode* mergemen = _igvn.transform(MergeMemNode::make(mem))->as_MergeMem(); BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); res = ArrayCopyNode::load(bs, &_igvn, ctl, mergemen, adr, adr_type, type, bt); } @@ -2903,6 +2903,102 @@ void PhaseMacroExpand::expand_subtypecheck_node(SubTypeCheckNode *check) { _igvn.replace_node(check, C->top()); } +// FlatArrayCheckNode (array1 array2 ...) is expanded into: +// +// long mark = array1.mark | array2.mark | ...; +// long locked_bit = markWord::unlocked_value & array1.mark & array2.mark & ...; +// if (locked_bit == 0) { +// // One array is locked, load prototype header from the klass +// mark = array1.klass.proto | array2.klass.proto | ... +// } +// if ((mark & markWord::flat_array_bit_in_place) == 0) { +// ... +// } +void PhaseMacroExpand::expand_flatarraycheck_node(FlatArrayCheckNode* check) { + if (UseArrayMarkWordCheck) { + Node* mark = MakeConX(0); + Node* locked_bit = MakeConX(markWord::unlocked_value); + Node* mem = check->in(FlatArrayCheckNode::Memory); + for (uint i = FlatArrayCheckNode::Array; i < check->req(); ++i) { + Node* ary = check->in(i); + if (ary->is_top()) continue; + const TypeAryPtr* t = _igvn.type(ary)->isa_aryptr(); + assert(!t->is_flat() && !t->is_not_flat(), "Should have been optimized out"); + Node* mark_adr = basic_plus_adr(ary, oopDesc::mark_offset_in_bytes()); + Node* mark_load = _igvn.transform(LoadNode::make(_igvn, NULL, mem, mark_adr, mark_adr->bottom_type()->is_ptr(), TypeX_X, TypeX_X->basic_type(), MemNode::unordered)); + mark = _igvn.transform(new OrXNode(mark, mark_load)); + locked_bit = _igvn.transform(new AndXNode(locked_bit, mark_load)); + } + assert(!mark->is_Con(), "Should have been optimized out"); + Node* cmp = _igvn.transform(new CmpXNode(locked_bit, MakeConX(0))); + Node* is_unlocked = _igvn.transform(new BoolNode(cmp, BoolTest::ne)); + + // BoolNode might be shared, replace each if user + Node* old_bol = check->unique_out(); + assert(old_bol->is_Bool() && old_bol->as_Bool()->_test._test == BoolTest::ne, "unexpected condition"); + for (DUIterator_Last imin, i = old_bol->last_outs(imin); i >= imin; --i) { + IfNode* old_iff = old_bol->last_out(i)->as_If(); + Node* ctrl = old_iff->in(0); + RegionNode* region = new RegionNode(3); + Node* mark_phi = new PhiNode(region, TypeX_X); + + // Check if array is unlocked + IfNode* iff = _igvn.transform(new IfNode(ctrl, is_unlocked, PROB_MAX, COUNT_UNKNOWN))->as_If(); + + // Unlocked: Use bits from mark word + region->init_req(1, _igvn.transform(new IfTrueNode(iff))); + mark_phi->init_req(1, mark); + + // Locked: Load prototype header from klass + ctrl = _igvn.transform(new IfFalseNode(iff)); + Node* proto = MakeConX(0); + for (uint i = FlatArrayCheckNode::Array; i < check->req(); ++i) { + Node* ary = check->in(i); + if (ary->is_top()) continue; + // Make loads control dependent to make sure they are only executed if array is locked + Node* klass_adr = basic_plus_adr(ary, oopDesc::klass_offset_in_bytes()); + Node* klass = _igvn.transform(LoadKlassNode::make(_igvn, ctrl, C->immutable_memory(), klass_adr, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); + Node* proto_adr = basic_plus_adr(klass, in_bytes(Klass::prototype_header_offset())); + Node* proto_load = _igvn.transform(LoadNode::make(_igvn, ctrl, C->immutable_memory(), proto_adr, proto_adr->bottom_type()->is_ptr(), TypeX_X, TypeX_X->basic_type(), MemNode::unordered)); + proto = _igvn.transform(new OrXNode(proto, proto_load)); + } + region->init_req(2, ctrl); + mark_phi->init_req(2, proto); + + // Check if flat array bits are set + Node* mask = MakeConX(markWord::flat_array_bit_in_place); + Node* masked = _igvn.transform(new AndXNode(_igvn.transform(mark_phi), mask)); + cmp = _igvn.transform(new CmpXNode(masked, MakeConX(0))); + Node* is_not_flat = _igvn.transform(new BoolNode(cmp, BoolTest::eq)); + + ctrl = _igvn.transform(region); + iff = _igvn.transform(new IfNode(ctrl, is_not_flat, PROB_MAX, COUNT_UNKNOWN))->as_If(); + _igvn.replace_node(old_iff, iff); + } + _igvn.replace_node(check, C->top()); + } else { + // Fall back to layout helper check + Node* lhs = intcon(0); + for (uint i = FlatArrayCheckNode::Array; i < check->req(); ++i) { + Node* ary = check->in(i); + if (ary->is_top()) continue; + const TypeAryPtr* t = _igvn.type(ary)->isa_aryptr(); + assert(!t->is_flat() && !t->is_not_flat(), "Should have been optimized out"); + Node* klass_adr = basic_plus_adr(ary, oopDesc::klass_offset_in_bytes()); + Node* klass = transform_later(LoadKlassNode::make(_igvn, NULL, C->immutable_memory(), klass_adr, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT)); + Node* lh_addr = basic_plus_adr(klass, in_bytes(Klass::layout_helper_offset())); + Node* lh_val = _igvn.transform(LoadNode::make(_igvn, NULL, C->immutable_memory(), lh_addr, lh_addr->bottom_type()->is_ptr(), TypeInt::INT, T_INT, MemNode::unordered)); + lhs = _igvn.transform(new OrINode(lhs, lh_val)); + } + Node* masked = transform_later(new AndINode(lhs, intcon(Klass::_lh_array_tag_vt_value_bit_inplace))); + Node* cmp = transform_later(new CmpINode(masked, intcon(0))); + Node* bol = transform_later(new BoolNode(cmp, BoolTest::eq)); + Node* old_bol = check->unique_out(); + _igvn.replace_node(old_bol, bol); + _igvn.replace_node(check, C->top()); + } +} + //---------------------------eliminate_macro_nodes---------------------- // Eliminate scalar replaced allocations and associated locks. void PhaseMacroExpand::eliminate_macro_nodes() { @@ -2967,6 +3063,8 @@ void PhaseMacroExpand::eliminate_macro_nodes() { break; case Node::Class_Opaque1: break; + case Node::Class_FlatArrayCheck: + break; default: assert(n->Opcode() == Op_LoopLimit || n->Opcode() == Op_Opaque2 || @@ -3105,6 +3203,10 @@ bool PhaseMacroExpand::expand_macro_nodes() { C->remove_macro_node(n); assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list"); break; + case Node::Class_FlatArrayCheck: + expand_flatarraycheck_node(n->as_FlatArrayCheck()); + assert(C->macro_count() == (old_macro_count - 1), "expansion must have deleted one node from macro list"); + break; default: assert(false, "unknown node type in macro list"); } diff --git a/src/hotspot/share/opto/macro.hpp b/src/hotspot/share/opto/macro.hpp index ee91acd177b..8fd00c2a870 100644 --- a/src/hotspot/share/opto/macro.hpp +++ b/src/hotspot/share/opto/macro.hpp @@ -200,6 +200,8 @@ class PhaseMacroExpand : public Phase { void expand_subtypecheck_node(SubTypeCheckNode *check); + void expand_flatarraycheck_node(FlatArrayCheckNode* check); + int replace_input(Node *use, Node *oldref, Node *newref); Node* opt_bits_test(Node* ctrl, Node* region, int edge, Node* word, int mask, int bits, bool return_fast_path = false); void copy_predefined_input_for_runtime_call(Node * ctrl, CallNode* oldcall, CallNode* call); diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index b255a0a8360..976a05757a2 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -584,8 +584,11 @@ void Node::setup_is_top() { //------------------------------~Node------------------------------------------ // Fancy destructor; eagerly attempt to reclaim Node numberings and storage -void Node::destruct() { - Compile* compile = Compile::current(); +void Node::destruct(PhaseValues* phase) { + Compile* compile = (phase != NULL) ? phase->C : Compile::current(); + if (phase != NULL && phase->is_IterGVN()) { + phase->is_IterGVN()->_worklist.remove(this); + } // If this is the most recently created node, reclaim its index. Otherwise, // record the node as dead to keep liveness information accurate. if ((uint)_idx+1 == compile->unique()) { @@ -1405,7 +1408,6 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) { // Done with outputs. igvn->hash_delete(dead); igvn->_worklist.remove(dead); - igvn->C->remove_modified_node(dead); igvn->set_type(dead, Type::TOP); if (dead->is_macro()) { igvn->C->remove_macro_node(dead); @@ -1444,6 +1446,7 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) { } } } + igvn->C->remove_modified_node(dead); } // (dead->outcnt() == 0) } // while (nstack.size() > 0) for outputs return; diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 6c5fa0cd570..3c64a5ffc88 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -72,6 +72,7 @@ class EncodePNode; class EncodePKlassNode; class FastLockNode; class FastUnlockNode; +class FlatArrayCheckNode; class HaltNode; class IfNode; class IfProjNode; @@ -241,7 +242,7 @@ class Node { // Delete is a NOP void operator delete( void *ptr ) {} // Fancy destructor; eagerly attempt to reclaim Node numberings and storage - void destruct(); + void destruct(PhaseValues* phase); // Create a new Node. Required is the number is of inputs required for // semantic correctness. @@ -719,9 +720,10 @@ class Node { DEFINE_CLASS_ID(Sub, Node, 6) DEFINE_CLASS_ID(Cmp, Sub, 0) - DEFINE_CLASS_ID(FastLock, Cmp, 0) - DEFINE_CLASS_ID(FastUnlock, Cmp, 1) - DEFINE_CLASS_ID(SubTypeCheck,Cmp, 2) + DEFINE_CLASS_ID(FastLock, Cmp, 0) + DEFINE_CLASS_ID(FastUnlock, Cmp, 1) + DEFINE_CLASS_ID(SubTypeCheck, Cmp, 2) + DEFINE_CLASS_ID(FlatArrayCheck, Cmp, 3) DEFINE_CLASS_ID(MergeMem, Node, 7) DEFINE_CLASS_ID(Bool, Node, 8) @@ -843,6 +845,7 @@ class Node { DEFINE_CLASS_QUERY(EncodePKlass) DEFINE_CLASS_QUERY(FastLock) DEFINE_CLASS_QUERY(FastUnlock) + DEFINE_CLASS_QUERY(FlatArrayCheck) DEFINE_CLASS_QUERY(Halt) DEFINE_CLASS_QUERY(If) DEFINE_CLASS_QUERY(RangeCheck) diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 1703048a4fa..539cea4f3f0 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -99,7 +99,7 @@ void Parse::array_load(BasicType bt) { ideal.declarations_done(); ideal.if_then(flat_array_test(ary, /* flat = */ false)); { // non-flattened - assert(ideal.ctrl()->in(0)->as_If()->is_non_flattened_array_check(&_gvn), "Should be found"); + assert(ideal.ctrl()->in(0)->as_If()->is_flat_array_check(&_gvn), "Should be found"); sync_kit(ideal); const TypeAryPtr* adr_type = TypeAryPtr::get_array_body_type(bt); Node* ld = access_load_at(ary, adr, adr_type, elemptr, bt, @@ -306,7 +306,7 @@ void Parse::array_store(BasicType bt) { IdealKit ideal(this); ideal.if_then(flat_array_test(ary, /* flat = */ false)); { // non-flattened - assert(ideal.ctrl()->in(0)->as_If()->is_non_flattened_array_check(&_gvn), "Should be found"); + assert(ideal.ctrl()->in(0)->as_If()->is_flat_array_check(&_gvn), "Should be found"); sync_kit(ideal); inline_array_null_guard(ary, cast_val, 3); inc_sp(3); @@ -3137,7 +3137,7 @@ void Parse::do_one_bytecode() { if (Matcher::convL2FSupported()) { a = pop_pair(); b = _gvn.transform( new ConvL2FNode(a)); - // For i486.ad, FILD doesn't restrict precision to 24 or 53 bits. + // For x86_32.ad, FILD doesn't restrict precision to 24 or 53 bits. // Rather than storing the result into an FP register then pushing // out to memory to round, the machine instruction that implements // ConvL2D is responsible for rounding. @@ -3152,7 +3152,7 @@ void Parse::do_one_bytecode() { case Bytecodes::_l2d: a = pop_pair(); b = _gvn.transform( new ConvL2DNode(a)); - // For i486.ad, rounding is always necessary (see _l2f above). + // For x86_32.ad, rounding is always necessary (see _l2f above). // c = dprecision_rounding(b); c = _gvn.transform(b); push_pair(c); diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 937b61f1964..377fd94ad21 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -749,7 +749,7 @@ ConNode* PhaseValues::uncached_makecon(const Type *t) { loc->clear(); // do not put debug info on constants } } else { - x->destruct(); // Hit, destroy duplicate constant + x->destruct(this); // Hit, destroy duplicate constant x = k; // use existing constant } return x; @@ -1071,7 +1071,7 @@ void PhaseIterGVN::init_verifyPhaseIterGVN() { Node* n = modified_list->pop(); if (n->outcnt() != 0 && !n->is_Con() && !_worklist.member(n)) { n->dump(); - assert(false, "modified node is not on IGVN._worklist"); + fatal("modified node is not on IGVN._worklist"); } } #endif @@ -1085,7 +1085,7 @@ void PhaseIterGVN::verify_PhaseIterGVN() { Node* n = modified_list->pop(); if (n->outcnt() != 0 && !n->is_Con()) { // skip dead and Con nodes n->dump(); - assert(false, "modified node was not processed by IGVN.transform_old()"); + fatal("modified node was not processed by IGVN.transform_old()"); } } #endif @@ -1475,8 +1475,7 @@ void PhaseIterGVN::subsume_node( Node *old, Node *nn ) { } } #endif - _worklist.remove(temp); // this can be necessary - temp->destruct(); // reuse the _idx of this little guy + temp->destruct(this); // reuse the _idx of this little guy } void PhaseIterGVN::replace_in_uses(Node* n, Node* m) { diff --git a/src/hotspot/share/opto/regmask.cpp b/src/hotspot/share/opto/regmask.cpp index c09ed814bb0..f024387c985 100644 --- a/src/hotspot/share/opto/regmask.cpp +++ b/src/hotspot/share/opto/regmask.cpp @@ -32,8 +32,6 @@ #include "utilities/population_count.hpp" #include "utilities/powerOfTwo.hpp" -#define RM_SIZE _RM_SIZE /* a constant private to the class RegMask */ - //------------------------------dump------------------------------------------- #ifndef PRODUCT @@ -65,27 +63,29 @@ bool RegMask::is_vector(uint ireg) { } int RegMask::num_registers(uint ireg) { - switch(ireg) { - case Op_VecZ: - return SlotsPerVecZ; - case Op_VecY: - return SlotsPerVecY; - case Op_VecX: - return SlotsPerVecX; - case Op_VecD: - return SlotsPerVecD; - case Op_RegD: - case Op_RegL: + switch(ireg) { + case Op_VecZ: + return SlotsPerVecZ; + case Op_VecY: + return SlotsPerVecY; + case Op_VecX: + return SlotsPerVecX; + case Op_VecD: + return SlotsPerVecD; + case Op_RegD: + case Op_RegL: #ifdef _LP64 - case Op_RegP: + case Op_RegP: #endif - return 2; - case Op_VecA: - assert(Matcher::supports_scalable_vector(), "does not support scalable vector"); - return SlotsPerVecA; - } - // Op_VecS and the rest ideal registers. - return 1; + return 2; + case Op_VecA: + assert(Matcher::supports_scalable_vector(), "does not support scalable vector"); + return SlotsPerVecA; + default: + // Op_VecS and the rest ideal registers. + assert(ireg == Op_VecS || !is_vector(ireg), "unexpected, possibly multi-slot register"); + return 1; + } } int RegMask::num_registers(uint ireg, LRG &lrg) { @@ -101,14 +101,25 @@ int RegMask::num_registers(uint ireg, LRG &lrg) { return n_regs; } +static const uintptr_t zero = uintptr_t(0); // 0x00..00 +static const uintptr_t all = ~uintptr_t(0); // 0xFF..FF +static const uintptr_t fives = all/3; // 0x5555..55 + +// only indices of power 2 are accessed, so index 3 is only filled in for storage. +static const uintptr_t low_bits[5] = { fives, // 0x5555..55 + all/0xF, // 0x1111..11, + all/0xFF, // 0x0101..01, + zero, // 0x0000..00 + all/0xFFFF }; // 0x0001..01 + // Clear out partial bits; leave only bit pairs void RegMask::clear_to_pairs() { assert(valid_watermarks(), "sanity"); - for (int i = _lwm; i <= _hwm; i++) { - int bits = _A[i]; - bits &= ((bits & 0x55555555)<<1); // 1 hi-bit set for each pair - bits |= (bits>>1); // Smear 1 hi-bit into a pair - _A[i] = bits; + for (unsigned i = _lwm; i <= _hwm; i++) { + uintptr_t bits = _RM_UP[i]; + bits &= ((bits & fives) << 1U); // 1 hi-bit set for each pair + bits |= (bits >> 1U); // Smear 1 hi-bit into a pair + _RM_UP[i] = bits; } assert(is_aligned_pairs(), "mask is not aligned, adjacent pairs"); } @@ -120,16 +131,16 @@ bool RegMask::is_misaligned_pair() const { bool RegMask::is_aligned_pairs() const { // Assert that the register mask contains only bit pairs. assert(valid_watermarks(), "sanity"); - for (int i = _lwm; i <= _hwm; i++) { - int bits = _A[i]; + for (unsigned i = _lwm; i <= _hwm; i++) { + uintptr_t bits = _RM_UP[i]; while (bits) { // Check bits for pairing - int bit = bits & -bits; // Extract low bit + uintptr_t bit = uintptr_t(1) << find_lowest_bit(bits); // Extract low bit // Low bit is not odd means its mis-aligned. - if ((bit & 0x55555555) == 0) return false; + if ((bit & fives) == 0) return false; bits -= bit; // Remove bit from mask // Check for aligned adjacent bit - if ((bits & (bit<<1)) == 0) return false; - bits -= (bit<<1); // Remove other halve of pair + if ((bits & (bit << 1U)) == 0) return false; + bits -= (bit << 1U); // Remove other halve of pair } } return true; @@ -144,19 +155,19 @@ bool RegMask::is_bound1() const { // Return TRUE if the mask contains an adjacent pair of bits and no other bits. bool RegMask::is_bound_pair() const { if (is_AllStack()) return false; - int bit = -1; // Set to hold the one bit allowed + uintptr_t bit = all; // Set to hold the one bit allowed assert(valid_watermarks(), "sanity"); - for (int i = _lwm; i <= _hwm; i++) { - if (_A[i]) { // Found some bits - if (bit != -1) return false; // Already had bits, so fail - bit = _A[i] & -(_A[i]); // Extract 1 bit from mask - if ((bit << 1) != 0) { // Bit pair stays in same word? - if ((bit | (bit<<1)) != _A[i]) + for (unsigned i = _lwm; i <= _hwm; i++) { + if (_RM_UP[i]) { // Found some bits + if (bit != all) return false; // Already had bits, so fail + bit = uintptr_t(1) << find_lowest_bit(_RM_UP[i]); // Extract lowest bit from mask + if ((bit << 1U) != 0) { // Bit pair stays in same word? + if ((bit | (bit << 1U)) != _RM_UP[i]) return false; // Require adjacent bit pair and no more bits } else { // Else its a split-pair case - if(bit != _A[i]) return false; // Found many bits, so fail + if (bit != _RM_UP[i]) return false; // Found many bits, so fail i++; // Skip iteration forward - if (i > _hwm || _A[i] != 1) + if (i > _hwm || _RM_UP[i] != 1) return false; // Require 1 lo bit in next word } } @@ -186,9 +197,6 @@ bool RegMask::is_valid_reg(OptoReg::Name reg, const int size) const { return true; } -// only indicies of power 2 are accessed, so index 3 is only filled in for storage. -static int low_bits[5] = { 0x55555555, 0x11111111, 0x01010101, 0x00000000, 0x00010001 }; - // Find the lowest-numbered register set in the mask. Return the // HIGHEST register number in the set, or BAD if no sets. // Works also for size 1. @@ -200,90 +208,90 @@ OptoReg::Name RegMask::find_first_set(LRG &lrg, const int size) const { assert(is_aligned_sets(size), "mask is not aligned, adjacent sets"); } assert(valid_watermarks(), "sanity"); - for (int i = _lwm; i <= _hwm; i++) { - if (_A[i]) { // Found some bits + for (unsigned i = _lwm; i <= _hwm; i++) { + if (_RM_UP[i]) { // Found some bits // Convert to bit number, return hi bit in pair - return OptoReg::Name((i<<_LogWordBits) + find_lowest_bit(_A[i]) + (size - 1)); + return OptoReg::Name((i<<_LogWordBits) + find_lowest_bit(_RM_UP[i]) + (size - 1)); } } return OptoReg::Bad; } // Clear out partial bits; leave only aligned adjacent bit pairs -void RegMask::clear_to_sets(const int size) { +void RegMask::clear_to_sets(const unsigned int size) { if (size == 1) return; assert(2 <= size && size <= 16, "update low bits table"); assert(is_power_of_2(size), "sanity"); assert(valid_watermarks(), "sanity"); - int low_bits_mask = low_bits[size>>2]; - for (int i = _lwm; i <= _hwm; i++) { - int bits = _A[i]; - int sets = (bits & low_bits_mask); - for (int j = 1; j < size; j++) { - sets = (bits & (sets<<1)); // filter bits which produce whole sets + uintptr_t low_bits_mask = low_bits[size >> 2U]; + for (unsigned i = _lwm; i <= _hwm; i++) { + uintptr_t bits = _RM_UP[i]; + uintptr_t sets = (bits & low_bits_mask); + for (unsigned j = 1U; j < size; j++) { + sets = (bits & (sets << 1U)); // filter bits which produce whole sets } - sets |= (sets>>1); // Smear 1 hi-bit into a set + sets |= (sets >> 1U); // Smear 1 hi-bit into a set if (size > 2) { - sets |= (sets>>2); // Smear 2 hi-bits into a set + sets |= (sets >> 2U); // Smear 2 hi-bits into a set if (size > 4) { - sets |= (sets>>4); // Smear 4 hi-bits into a set + sets |= (sets >> 4U); // Smear 4 hi-bits into a set if (size > 8) { - sets |= (sets>>8); // Smear 8 hi-bits into a set + sets |= (sets >> 8U); // Smear 8 hi-bits into a set } } } - _A[i] = sets; + _RM_UP[i] = sets; } assert(is_aligned_sets(size), "mask is not aligned, adjacent sets"); } // Smear out partial bits to aligned adjacent bit sets -void RegMask::smear_to_sets(const int size) { +void RegMask::smear_to_sets(const unsigned int size) { if (size == 1) return; assert(2 <= size && size <= 16, "update low bits table"); assert(is_power_of_2(size), "sanity"); assert(valid_watermarks(), "sanity"); - int low_bits_mask = low_bits[size>>2]; - for (int i = _lwm; i <= _hwm; i++) { - int bits = _A[i]; - int sets = 0; - for (int j = 0; j < size; j++) { + uintptr_t low_bits_mask = low_bits[size >> 2U]; + for (unsigned i = _lwm; i <= _hwm; i++) { + uintptr_t bits = _RM_UP[i]; + uintptr_t sets = 0; + for (unsigned j = 0; j < size; j++) { sets |= (bits & low_bits_mask); // collect partial bits - bits = bits>>1; + bits = bits >> 1U; } - sets |= (sets<<1); // Smear 1 lo-bit into a set + sets |= (sets << 1U); // Smear 1 lo-bit into a set if (size > 2) { - sets |= (sets<<2); // Smear 2 lo-bits into a set + sets |= (sets << 2U); // Smear 2 lo-bits into a set if (size > 4) { - sets |= (sets<<4); // Smear 4 lo-bits into a set + sets |= (sets << 4U); // Smear 4 lo-bits into a set if (size > 8) { - sets |= (sets<<8); // Smear 8 lo-bits into a set + sets |= (sets << 8U); // Smear 8 lo-bits into a set } } } - _A[i] = sets; + _RM_UP[i] = sets; } assert(is_aligned_sets(size), "mask is not aligned, adjacent sets"); } // Assert that the register mask contains only bit sets. -bool RegMask::is_aligned_sets(const int size) const { +bool RegMask::is_aligned_sets(const unsigned int size) const { if (size == 1) return true; assert(2 <= size && size <= 16, "update low bits table"); assert(is_power_of_2(size), "sanity"); - int low_bits_mask = low_bits[size>>2]; + uintptr_t low_bits_mask = low_bits[size >> 2U]; assert(valid_watermarks(), "sanity"); - for (int i = _lwm; i <= _hwm; i++) { - int bits = _A[i]; + for (unsigned i = _lwm; i <= _hwm; i++) { + uintptr_t bits = _RM_UP[i]; while (bits) { // Check bits for pairing - int bit = bits & -bits; // Extract low bit + uintptr_t bit = uintptr_t(1) << find_lowest_bit(bits); // Low bit is not odd means its mis-aligned. if ((bit & low_bits_mask) == 0) { return false; } // Do extra work since (bit << size) may overflow. - int hi_bit = bit << (size-1); // high bit - int set = hi_bit + ((hi_bit-1) & ~(bit-1)); + uintptr_t hi_bit = bit << (size-1); // high bit + uintptr_t set = hi_bit + ((hi_bit-1) & ~(bit-1)); // Check for aligned adjacent bits in this set if ((bits & set) != set) { return false; @@ -296,32 +304,29 @@ bool RegMask::is_aligned_sets(const int size) const { // Return TRUE if the mask contains one adjacent set of bits and no other bits. // Works also for size 1. -int RegMask::is_bound_set(const int size) const { +bool RegMask::is_bound_set(const unsigned int size) const { if (is_AllStack()) return false; assert(1 <= size && size <= 16, "update low bits table"); assert(valid_watermarks(), "sanity"); - int bit = -1; // Set to hold the one bit allowed - for (int i = _lwm; i <= _hwm; i++) { - if (_A[i] ) { // Found some bits - if (bit != -1) - return false; // Already had bits, so fail - bit = _A[i] & -_A[i]; // Extract low bit from mask - int hi_bit = bit << (size-1); // high bit + uintptr_t bit = all; // Set to hold the one bit allowed + for (unsigned i = _lwm; i <= _hwm; i++) { + if (_RM_UP[i] ) { // Found some bits + if (bit != all) + return false; // Already had bits, so fail + unsigned bit_index = find_lowest_bit(_RM_UP[i]); + bit = uintptr_t(1) << bit_index; + uintptr_t hi_bit = bit << (size - 1); // high bit if (hi_bit != 0) { // Bit set stays in same word? - int set = hi_bit + ((hi_bit-1) & ~(bit-1)); - if (set != _A[i]) + uintptr_t set = hi_bit + ((hi_bit-1) & ~(bit-1)); + if (set != _RM_UP[i]) return false; // Require adjacent bit set and no more bits } else { // Else its a split-set case - if (((-1) & ~(bit-1)) != _A[i]) + if ((all & ~(bit-1)) != _RM_UP[i]) return false; // Found many bits, so fail i++; // Skip iteration forward and check high part - // The lower (32-size) bits should be 0 since it is split case. - int clear_bit_size = 32-size; - int shift_back_size = 32-clear_bit_size; - int set = bit>>clear_bit_size; - set = set & -set; // Remove sign extension. - set = (((set << size) - 1) >> shift_back_size); - if (i > _hwm || _A[i] != set) + // The lower (BitsPerWord - size) bits should be 1 since it is split case. + uintptr_t set = (bit >> (BitsPerWord - bit_index)) - 1; + if (i > _hwm || _RM_UP[i] != set) return false; // Require expected low bits in next word } } @@ -346,8 +351,8 @@ bool RegMask::is_UP() const { uint RegMask::Size() const { uint sum = 0; assert(valid_watermarks(), "sanity"); - for (int i = _lwm; i <= _hwm; i++) { - sum += population_count((unsigned)_A[i]); + for (unsigned i = _lwm; i <= _hwm; i++) { + sum += population_count(_RM_UP[i]); } return sum; } diff --git a/src/hotspot/share/opto/regmask.hpp b/src/hotspot/share/opto/regmask.hpp index d9165da6c90..bed1c416e1a 100644 --- a/src/hotspot/share/opto/regmask.hpp +++ b/src/hotspot/share/opto/regmask.hpp @@ -34,12 +34,12 @@ class LRG; //-------------Non-zero bit search methods used by RegMask--------------------- // Find lowest 1, undefined if empty/0 -static int find_lowest_bit(uint32_t mask) { +static unsigned int find_lowest_bit(uintptr_t mask) { return count_trailing_zeros(mask); } // Find highest 1, undefined if empty/0 -static int find_highest_bit(uint32_t mask) { - return count_leading_zeros(mask) ^ 31; +static unsigned int find_highest_bit(uintptr_t mask) { + return count_leading_zeros(mask) ^ (BitsPerWord - 1U); } //------------------------------RegMask---------------------------------------- @@ -48,37 +48,39 @@ static int find_highest_bit(uint32_t mask) { // just a collection of Register numbers. // The ADLC defines 2 macros, RM_SIZE and FORALL_BODY. -// RM_SIZE is the size of a register mask in words. +// RM_SIZE is the size of a register mask in 32-bit words. // FORALL_BODY replicates a BODY macro once per word in the register mask. // The usage is somewhat clumsy and limited to the regmask.[h,c]pp files. // However, it means the ADLC can redefine the unroll macro and all loops // over register masks will be unrolled by the correct amount. class RegMask { + + enum { + _WordBits = BitsPerWord, + _LogWordBits = LogBitsPerWord, + _RM_SIZE = LP64_ONLY(align_up(RM_SIZE, 2) >> 1) NOT_LP64(RM_SIZE) + }; + union { - double _dummy_force_double_alignment[RM_SIZE>>1]; // Array of Register Mask bits. This array is large enough to cover // all the machine registers and all parameters that need to be passed // on the stack (stack registers) up to some interesting limit. Methods // that need more parameters will NOT be compiled. On Intel, the limit // is something like 90+ parameters. - int _A[RM_SIZE]; + int _RM_I[RM_SIZE]; + uintptr_t _RM_UP[_RM_SIZE]; }; + // The low and high water marks represents the lowest and highest word // that might contain set register mask bits, respectively. We guarantee // that there are no bits in words outside this range, but any word at // and between the two marks can still be 0. - int _lwm; - int _hwm; - - enum { - _WordBits = BitsPerInt, - _LogWordBits = LogBitsPerInt, - _RM_SIZE = RM_SIZE // local constant, imported, then hidden by #undef - }; + unsigned int _lwm; + unsigned int _hwm; public: - enum { CHUNK_SIZE = RM_SIZE*_WordBits }; + enum { CHUNK_SIZE = RM_SIZE*BitsPerInt }; // SlotsPerLong is 2, since slots are 32 bits and longs are 64 bits. // Also, consider the maximum alignment size for a normally allocated @@ -108,13 +110,18 @@ class RegMask { FORALL_BODY # undef BODY int dummy = 0) { -# define BODY(I) _A[I] = a##I; +#if defined(VM_LITTLE_ENDIAN) || !defined(_LP64) +# define BODY(I) _RM_I[I] = a##I; +#else + // We need to swap ints. +# define BODY(I) _RM_I[I ^ 1] = a##I; +#endif FORALL_BODY # undef BODY _lwm = 0; - _hwm = RM_SIZE - 1; - while (_hwm > 0 && _A[_hwm] == 0) _hwm--; - while ((_lwm < _hwm) && _A[_lwm] == 0) _lwm++; + _hwm = _RM_SIZE - 1; + while (_hwm > 0 && _RM_UP[_hwm] == 0) _hwm--; + while ((_lwm < _hwm) && _RM_UP[_lwm] == 0) _lwm++; assert(valid_watermarks(), "post-condition"); } @@ -122,48 +129,41 @@ class RegMask { RegMask(RegMask *rm) { _hwm = rm->_hwm; _lwm = rm->_lwm; - for (int i = 0; i < RM_SIZE; i++) { - _A[i] = rm->_A[i]; + for (unsigned i = 0; i < _RM_SIZE; i++) { + _RM_UP[i] = rm->_RM_UP[i]; } assert(valid_watermarks(), "post-condition"); } // Construct an empty mask - RegMask() { - Clear(); - } + RegMask() : _RM_UP(), _lwm(_RM_SIZE - 1), _hwm(0) {} // Construct a mask with a single bit - RegMask(OptoReg::Name reg) { - Clear(); + RegMask(OptoReg::Name reg) : RegMask() { Insert(reg); } // Check for register being in mask - int Member(OptoReg::Name reg) const { + bool Member(OptoReg::Name reg) const { assert(reg < CHUNK_SIZE, ""); - return _A[reg>>_LogWordBits] & (1<<(reg&(_WordBits-1))); + + unsigned r = (unsigned)reg; + return _RM_UP[r >> _LogWordBits] & (uintptr_t(1) <<(r & (_WordBits - 1U))); } // The last bit in the register mask indicates that the mask should repeat // indefinitely with ONE bits. Returns TRUE if mask is infinite or // unbounded in size. Returns FALSE if mask is finite size. - int is_AllStack() const { return _A[RM_SIZE-1] >> (_WordBits-1); } - - // Work around an -xO3 optimization problme in WS6U1. The old way: - // void set_AllStack() { _A[RM_SIZE-1] |= (1<<(_WordBits-1)); } - // will cause _A[RM_SIZE-1] to be clobbered, not updated when set_AllStack() - // follows an Insert() loop, like the one found in init_spill_mask(). Using - // Insert() instead works because the index into _A in computed instead of - // constant. See bug 4665841. + bool is_AllStack() const { return _RM_UP[_RM_SIZE - 1U] >> (_WordBits - 1U); } + void set_AllStack() { Insert(OptoReg::Name(CHUNK_SIZE-1)); } // Test for being a not-empty mask. - int is_NotEmpty() const { + bool is_NotEmpty() const { assert(valid_watermarks(), "sanity"); - int tmp = 0; - for (int i = _lwm; i <= _hwm; i++) { - tmp |= _A[i]; + uintptr_t tmp = 0; + for (unsigned i = _lwm; i <= _hwm; i++) { + tmp |= _RM_UP[i]; } return tmp; } @@ -171,8 +171,8 @@ class RegMask { // Find lowest-numbered register from mask, or BAD if mask is empty. OptoReg::Name find_first_elem() const { assert(valid_watermarks(), "sanity"); - for (int i = _lwm; i <= _hwm; i++) { - int bits = _A[i]; + for (unsigned i = _lwm; i <= _hwm; i++) { + uintptr_t bits = _RM_UP[i]; if (bits) { return OptoReg::Name((i<<_LogWordBits) + find_lowest_bit(bits)); } @@ -183,8 +183,10 @@ class RegMask { // Get highest-numbered register from mask, or BAD if mask is empty. OptoReg::Name find_last_elem() const { assert(valid_watermarks(), "sanity"); - for (int i = _hwm; i >= _lwm; i--) { - int bits = _A[i]; + // Careful not to overflow if _lwm == 0 + unsigned i = _hwm + 1; + while (i > _lwm) { + uintptr_t bits = _RM_UP[--i]; if (bits) { return OptoReg::Name((i<<_LogWordBits) + find_highest_bit(bits)); } @@ -199,13 +201,13 @@ class RegMask { // Verify watermarks are sane, i.e., within bounds and that no // register words below or above the watermarks have bits set. bool valid_watermarks() const { - assert(_hwm >= 0 && _hwm < RM_SIZE, "_hwm out of range: %d", _hwm); - assert(_lwm >= 0 && _lwm < RM_SIZE, "_lwm out of range: %d", _lwm); - for (int i = 0; i < _lwm; i++) { - assert(_A[i] == 0, "_lwm too high: %d regs at: %d", _lwm, i); + assert(_hwm < _RM_SIZE, "_hwm out of range: %d", _hwm); + assert(_lwm < _RM_SIZE, "_lwm out of range: %d", _lwm); + for (unsigned i = 0; i < _lwm; i++) { + assert(_RM_UP[i] == 0, "_lwm too high: %d regs at: %d", _lwm, i); } - for (int i = _hwm + 1; i < RM_SIZE; i++) { - assert(_A[i] == 0, "_hwm too low: %d regs at: %d", _hwm, i); + for (unsigned i = _hwm + 1; i < _RM_SIZE; i++) { + assert(_RM_UP[i] == 0, "_hwm too low: %d regs at: %d", _hwm, i); } return true; } @@ -233,27 +235,27 @@ class RegMask { OptoReg::Name find_first_set(LRG &lrg, const int size) const; // Clear out partial bits; leave only aligned adjacent bit sets of size. - void clear_to_sets(const int size); + void clear_to_sets(const unsigned int size); // Smear out partial bits to aligned adjacent bit sets. - void smear_to_sets(const int size); + void smear_to_sets(const unsigned int size); // Test that the mask contains only aligned adjacent bit sets - bool is_aligned_sets(const int size) const; + bool is_aligned_sets(const unsigned int size) const; // Test for a single adjacent set - int is_bound_set(const int size) const; + bool is_bound_set(const unsigned int size) const; static bool is_vector(uint ireg); static int num_registers(uint ireg); static int num_registers(uint ireg, LRG &lrg); // Fast overlap test. Non-zero if any registers in common. - int overlap(const RegMask &rm) const { + bool overlap(const RegMask &rm) const { assert(valid_watermarks() && rm.valid_watermarks(), "sanity"); - int hwm = MIN2(_hwm, rm._hwm); - int lwm = MAX2(_lwm, rm._lwm); - int result = 0; - for (int i = lwm; i <= hwm; i++) { - result |= _A[i] & rm._A[i]; + unsigned hwm = MIN2(_hwm, rm._hwm); + unsigned lwm = MAX2(_lwm, rm._lwm); + uintptr_t result = 0; + for (unsigned i = lwm; i <= hwm; i++) { + result |= _RM_UP[i] & rm._RM_UP[i]; } return result; } @@ -264,35 +266,39 @@ class RegMask { // Clear a register mask void Clear() { - _lwm = RM_SIZE - 1; + _lwm = _RM_SIZE - 1; _hwm = 0; - memset(_A, 0, sizeof(int)*RM_SIZE); + memset(_RM_UP, 0, sizeof(uintptr_t)*_RM_SIZE); assert(valid_watermarks(), "sanity"); } // Fill a register mask with 1's void Set_All() { _lwm = 0; - _hwm = RM_SIZE - 1; - memset(_A, 0xFF, sizeof(int)*RM_SIZE); + _hwm = _RM_SIZE - 1; + memset(_RM_UP, 0xFF, sizeof(uintptr_t)*_RM_SIZE); assert(valid_watermarks(), "sanity"); } // Insert register into mask void Insert(OptoReg::Name reg) { + assert(reg != OptoReg::Bad, "sanity"); + assert(reg != OptoReg::Special, "sanity"); assert(reg < CHUNK_SIZE, "sanity"); assert(valid_watermarks(), "pre-condition"); - int index = reg>>_LogWordBits; + unsigned r = (unsigned)reg; + unsigned index = r >> _LogWordBits; if (index > _hwm) _hwm = index; if (index < _lwm) _lwm = index; - _A[index] |= (1<<(reg&(_WordBits-1))); + _RM_UP[index] |= (uintptr_t(1) << (r & (_WordBits - 1U))); assert(valid_watermarks(), "post-condition"); } // Remove register from mask void Remove(OptoReg::Name reg) { assert(reg < CHUNK_SIZE, ""); - _A[reg>>_LogWordBits] &= ~(1<<(reg&(_WordBits-1))); + unsigned r = (unsigned)reg; + _RM_UP[r >> _LogWordBits] &= ~(uintptr_t(1) << (r & (_WordBits-1U))); } // OR 'rm' into 'this' @@ -301,8 +307,8 @@ class RegMask { // OR widens the live range if (_lwm > rm._lwm) _lwm = rm._lwm; if (_hwm < rm._hwm) _hwm = rm._hwm; - for (int i = _lwm; i <= _hwm; i++) { - _A[i] |= rm._A[i]; + for (unsigned i = _lwm; i <= _hwm; i++) { + _RM_UP[i] |= rm._RM_UP[i]; } assert(valid_watermarks(), "sanity"); } @@ -312,8 +318,8 @@ class RegMask { assert(valid_watermarks() && rm.valid_watermarks(), "sanity"); // Do not evaluate words outside the current watermark range, as they are // already zero and an &= would not change that - for (int i = _lwm; i <= _hwm; i++) { - _A[i] &= rm._A[i]; + for (unsigned i = _lwm; i <= _hwm; i++) { + _RM_UP[i] &= rm._RM_UP[i]; } // Narrow the watermarks if &rm spans a narrower range. // Update after to ensure non-overlapping words are zeroed out. @@ -324,10 +330,10 @@ class RegMask { // Subtract 'rm' from 'this' void SUBTRACT(const RegMask &rm) { assert(valid_watermarks() && rm.valid_watermarks(), "sanity"); - int hwm = MIN2(_hwm, rm._hwm); - int lwm = MAX2(_lwm, rm._lwm); - for (int i = lwm; i <= hwm; i++) { - _A[i] &= ~rm._A[i]; + unsigned hwm = MIN2(_hwm, rm._hwm); + unsigned lwm = MAX2(_lwm, rm._lwm); + for (unsigned i = lwm; i <= hwm; i++) { + _RM_UP[i] &= ~rm._RM_UP[i]; } } diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index c892c7646a9..f0269c7ab72 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -338,7 +338,7 @@ Node *PhaseIdealLoop::spinup( Node *iff_dom, Node *new_false, Node *new_true, No if( t ) { // See if we already have this one // phi_post will not be used, so kill it _igvn.remove_dead_node(phi_post); - phi_post->destruct(); + phi_post->destruct(&_igvn); phi_post = t; } else { register_new_node( phi_post, prior_n ); diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 94380922ba3..ddf7f9f33d1 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -1266,6 +1266,43 @@ Node *CmpDNode::Ideal(PhaseGVN *phase, bool can_reshape){ return NULL; // No change } +//============================================================================= +//------------------------------Value------------------------------------------ +const Type* FlatArrayCheckNode::Value(PhaseGVN* phase) const { + bool all_not_flat = true; + for (uint i = Array; i < req(); ++i) { + Node* array = in(i); + if (!array->is_top()) { + const TypeAryPtr* t = phase->type(array)->isa_aryptr(); + if (t != NULL && t->is_flat()) { + // One of the input arrays is flat, check always passes + return TypeInt::CC_EQ; + } else if (t == NULL || !t->is_not_flat()) { + // One of the input arrays might be flat + all_not_flat = false; + } + } + } + if (all_not_flat) { + // None of the input arrays can be flat, check always fails + return TypeInt::CC_GT; + } + return TypeInt::CC; +} + +//------------------------------Ideal------------------------------------------ +Node* FlatArrayCheckNode::Ideal(PhaseGVN* phase, bool can_reshape) { + bool changed = false; + // Remove array inputs that are known to be non-flat + for (uint i = Array; i < req(); ++i) { + const TypeAryPtr* t = phase->type(in(i))->isa_aryptr(); + if (t != NULL && t->is_not_flat()) { + set_req(i, phase->C->top()); + changed = true; + } + } + return changed ? this : NULL; +} //============================================================================= //------------------------------cc2logical------------------------------------- diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp index b3a37703000..102e833f114 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -277,6 +277,25 @@ class CmpD3Node : public CmpDNode { virtual uint ideal_reg() const { return Op_RegI; } }; +//--------------------------FlatArrayCheckNode--------------------------------- +// Returns true if one of the input arrays (there can be multiple) is flat. +class FlatArrayCheckNode : public CmpNode { +public: + enum { + Control, + Memory, + Array + }; + FlatArrayCheckNode(Compile* C, Node* mem, Node* array) : CmpNode(mem, array) { + init_class_id(Class_FlatArrayCheck); + init_flags(Flag_is_macro); + C->add_macro_node(this); + } + virtual int Opcode() const; + virtual const Type* sub(const Type*, const Type*) const { ShouldNotReachHere(); return NULL; } + const Type* Value(PhaseGVN* phase) const; + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); +}; //------------------------------BoolTest--------------------------------------- // Convert condition codes to a boolean test value (0 or -1). diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index bfe5d574a7c..e2878eeaabb 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -1560,16 +1560,12 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu } } -void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame current_frame) { +void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame current_frame) { HandleMark hm(thread); methodHandle mh(thread, method); - EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("[%s] Trg Method Exit triggered %s.%s", - JvmtiTrace::safe_get_thread_name(thread), - (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), - (mh() == NULL) ? "NULL" : mh()->name()->as_C_string() )); - JvmtiThreadState *state = thread->jvmti_thread_state(); + if (state == NULL || !state->is_interp_only_mode()) { // for any thread that actually wants method exit, interp_only_mode is set return; @@ -1578,13 +1574,11 @@ void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame cur // return a flag when a method terminates by throwing an exception // i.e. if an exception is thrown and it's not caught by the current method bool exception_exit = state->is_exception_detected() && !state->is_exception_caught(); - + Handle result; + jvalue value; + value.j = 0L; if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) { - Handle result; - jvalue value; - value.j = 0L; - // if the method hasn't been popped because of an exception then we populate // the return_value parameter for the callback. At this point we only have // the address of a "raw result" and we just call into the interpreter to @@ -1594,9 +1588,36 @@ void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame cur BasicType type = current_frame.interpreter_frame_result(&oop_result, &value); if (is_reference_type(type)) { result = Handle(thread, oop_result); + value.l = JNIHandles::make_local(thread, result()); } } + } + // Deferred transition to VM, so we can stash away the return oop before GC + // Note that this transition is not needed when throwing an exception, because + // there is no oop to retain. + JRT_BLOCK + post_method_exit_inner(thread, mh, state, exception_exit, current_frame, value); + JRT_BLOCK_END + + if (result.not_null() && !mh->is_native()) { + // We have to restore the oop on the stack for interpreter frames + *(oop*)current_frame.interpreter_frame_tos_address() = result(); + } +} + +void JvmtiExport::post_method_exit_inner(JavaThread* thread, + methodHandle& mh, + JvmtiThreadState *state, + bool exception_exit, + frame current_frame, + jvalue& value) { + EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("[%s] Trg Method Exit triggered %s.%s", + JvmtiTrace::safe_get_thread_name(thread), + (mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(), + (mh() == NULL) ? "NULL" : mh()->name()->as_C_string() )); + + if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) { JvmtiEnvThreadStateIterator it(state); for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) { if (ets->is_enabled(JVMTI_EVENT_METHOD_EXIT)) { @@ -1607,9 +1628,6 @@ void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame cur JvmtiEnv *env = ets->get_env(); JvmtiMethodEventMark jem(thread, mh); - if (result.not_null()) { - value.l = JNIHandles::make_local(thread, result()); - } JvmtiJavaThreadEventTransition jet(thread); jvmtiEventMethodExit callback = env->callbacks()->MethodExit; if (callback != NULL) { @@ -1801,7 +1819,9 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met if(state->is_interp_only_mode()) { // method exit and frame pop events are posted only in interp mode. // When these events are enabled code should be in running in interp mode. - JvmtiExport::post_method_exit(thread, method, thread->last_frame()); + jvalue no_value; + no_value.j = 0L; + JvmtiExport::post_method_exit_inner(thread, mh, state, true, thread->last_frame(), no_value); // The cached cur_stack_depth might have changed from the // operations of frame pop or method exit. We are not 100% sure // the cached cur_stack_depth is still valid depth so invalidate diff --git a/src/hotspot/share/prims/jvmtiExport.hpp b/src/hotspot/share/prims/jvmtiExport.hpp index ce7f4100a5a..64e9d92e8b0 100644 --- a/src/hotspot/share/prims/jvmtiExport.hpp +++ b/src/hotspot/share/prims/jvmtiExport.hpp @@ -193,6 +193,13 @@ class JvmtiExport : public AllStatic { // dependency information is complete or not. static bool _all_dependencies_are_recorded; + static void post_method_exit_inner(JavaThread* thread, + methodHandle& mh, + JvmtiThreadState *state, + bool exception_exit, + frame current_frame, + jvalue& value); + public: inline static bool has_redefined_a_class() { JVMTI_ONLY(return _redefinition_count != 0); diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 80a79ae83ed..4c7edf969d5 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1456,7 +1456,8 @@ jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) { } } - if (VerifyMergedCPBytecodes) { +#ifdef ASSERT + { // verify what we have done during constant pool merging { RedefineVerifyMark rvm(the_class, scratch_class, state); @@ -1476,6 +1477,7 @@ jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) { } } } +#endif // ASSERT Rewriter::rewrite(scratch_class, THREAD); if (!HAS_PENDING_EXCEPTION) { diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 3957763388e..c0e9139a9a9 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -387,6 +387,11 @@ WB_ENTRY(jboolean, WB_isObjectInOldGen(JNIEnv* env, jobject o, jobject obj)) if (UseZGC) { return Universe::heap()->is_in(p); } +#endif +#if INCLUDE_SHENANDOAHGC + if (UseShenandoahGC) { + return Universe::heap()->is_in(p); + } #endif GenCollectedHeap* gch = GenCollectedHeap::heap(); return !gch->is_in_young(p); diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 3bf7c6e8228..141a0da3062 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -555,6 +555,8 @@ static SpecialFlag const special_jvm_flags[] = { { "ForceNUMA", JDK_Version::jdk(15), JDK_Version::jdk(16), JDK_Version::jdk(17) }, { "InsertMemBarAfterArraycopy", JDK_Version::undefined(), JDK_Version::jdk(16), JDK_Version::jdk(17) }, { "Debugging", JDK_Version::undefined(), JDK_Version::jdk(16), JDK_Version::jdk(17) }, + { "UseRDPCForConstantTableBase", JDK_Version::undefined(), JDK_Version::jdk(16), JDK_Version::jdk(17) }, + { "VerifyMergedCPBytecodes", JDK_Version::undefined(), JDK_Version::jdk(16), JDK_Version::jdk(17) }, #ifdef TEST_VERIFY_SPECIAL_JVM_FLAGS // These entries will generate build errors. Their purpose is to test the macros. @@ -3317,6 +3319,25 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) { } #endif +#if !INCLUDE_AOT + UNSUPPORTED_OPTION(UseAOT); + UNSUPPORTED_OPTION(PrintAOT); + UNSUPPORTED_OPTION(UseAOTStrictLoading); + UNSUPPORTED_OPTION_NULL(AOTLibrary); + + UNSUPPORTED_OPTION_INIT(Tier3AOTInvocationThreshold, 0); + UNSUPPORTED_OPTION_INIT(Tier3AOTMinInvocationThreshold, 0); + UNSUPPORTED_OPTION_INIT(Tier3AOTCompileThreshold, 0); + UNSUPPORTED_OPTION_INIT(Tier3AOTBackEdgeThreshold, 0); + UNSUPPORTED_OPTION_INIT(Tier0AOTInvocationThreshold, 0); + UNSUPPORTED_OPTION_INIT(Tier0AOTMinInvocationThreshold, 0); + UNSUPPORTED_OPTION_INIT(Tier0AOTCompileThreshold, 0); + UNSUPPORTED_OPTION_INIT(Tier0AOTBackEdgeThreshold, 0); +#ifndef PRODUCT + UNSUPPORTED_OPTION(PrintAOTStatistics); +#endif +#endif + #ifndef CAN_SHOW_REGISTERS_ON_ASSERT UNSUPPORTED_OPTION(ShowRegistersOnAssert); #endif // CAN_SHOW_REGISTERS_ON_ASSERT diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index eb3312dc588..7bb0c274532 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -684,5 +684,14 @@ do { \ } \ } while(0) +// Initialize options not supported in this release, with a warning +// if they were explicitly requested on the command-line +#define UNSUPPORTED_OPTION_INIT(opt, value) \ +do { \ + if (FLAG_IS_CMDLINE(opt)) { \ + warning("-XX flag " #opt " not supported in this VM"); \ + } \ + FLAG_SET_DEFAULT(opt, value); \ +} while(0) #endif // SHARE_RUNTIME_ARGUMENTS_HPP diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index 30017fc0303..623c3d1f7e8 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.cpp @@ -23,14 +23,18 @@ */ #include "precompiled.hpp" +#include "oops/oop.inline.hpp" #include "runtime/basicLock.hpp" #include "runtime/synchronizer.hpp" -void BasicLock::print_on(outputStream* st) const { +void BasicLock::print_on(outputStream* st, oop owner) const { st->print("monitor"); markWord mark_word = displaced_header(); - if (mark_word.value() != 0) - mark_word.print_on(st); + if (mark_word.value() != 0) { + // Print monitor info if there's an owning oop and it refers to this BasicLock. + bool print_monitor_info = (owner != NULL) && (owner->mark() == markWord::from_pointer((void*)this)); + mark_word.print_on(st, print_monitor_info); + } } void BasicLock::move_to(oop obj, BasicLock* dest) { diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index a292a742d8d..18236b9e2a3 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -43,7 +43,7 @@ class BasicLock { Atomic::store(&_displaced_header, header); } - void print_on(outputStream* st) const; + void print_on(outputStream* st, oop owner) const; // move a basic lock (used during deoptimization void move_to(oop obj, BasicLock* dest); diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index cf85f5fd26c..674edb691fa 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -532,7 +532,7 @@ void frame::interpreter_frame_print_on(outputStream* st) const { current->obj()->print_value_on(st); st->print_cr("]"); st->print(" - lock ["); - current->lock()->print_on(st); + current->lock()->print_on(st, current->obj()); st->print_cr("]"); } // monitor diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 86c193c7d05..45fd3d8a866 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -532,9 +532,6 @@ const intx ObjectAlignmentInBytes = 8; "error log in case of a crash.") \ range(0, (uint64_t)max_jlong/1000) \ \ - product_pd(bool, UseOSErrorReporting, \ - "Let VM fatal error propagate to the OS (ie. WER on Windows)") \ - \ product(bool, SuppressFatalErrorMessage, false, \ "Report NO fatal error message (avoid deadlock)") \ \ @@ -731,6 +728,20 @@ const intx ObjectAlignmentInBytes = 8; "MonitorUsedDeflationThreshold is exceeded (0 is off).") \ range(0, max_jint) \ \ + /* notice: the max range value here is max_jint, not max_intx */ \ + /* because of overflow issue */ \ + product(intx, AvgMonitorsPerThreadEstimate, 1024, DIAGNOSTIC, \ + "Used to estimate a variable ceiling based on number of threads " \ + "for use with MonitorUsedDeflationThreshold (0 is off).") \ + range(0, max_jint) \ + \ + /* notice: the max range value here is max_jint, not max_intx */ \ + /* because of overflow issue */ \ + product(intx, MonitorDeflationMax, 1000000, DIAGNOSTIC, \ + "The maximum number of monitors to deflate, unlink and delete " \ + "at one time (minimum is 1024).") \ + range(1024, max_jint) \ + \ product(intx, MonitorUsedDeflationThreshold, 90, EXPERIMENTAL, \ "Percentage of used monitors before triggering deflation (0 is " \ "off). The check is performed on GuaranteedSafepointInterval " \ @@ -758,7 +769,7 @@ const intx ObjectAlignmentInBytes = 8; "tables") \ \ product(bool, AllowUserSignalHandlers, false, \ - "Do not complain if the application installs signal handlers " \ + "Application will install primary signal handlers for the JVM " \ "(Unix only)") \ \ product(bool, UseSignalChaining, true, \ @@ -893,10 +904,6 @@ const intx ObjectAlignmentInBytes = 8; product(bool, StressLdcRewrite, false, \ "Force ldc -> ldc_w rewrite during RedefineClasses") \ \ - /* change to false by default sometime after Mustang */ \ - product(bool, VerifyMergedCPBytecodes, true, \ - "Verify bytecodes after RedefineClasses constant pool merging") \ - \ product(bool, AllowRedefinitionToAddDeleteMethods, false, \ "(Deprecated) Allow redefinition to add and delete private " \ "static or final methods for compatibility with old releases") \ @@ -2527,6 +2534,9 @@ const intx ObjectAlignmentInBytes = 8; develop(bool, ScalarizeInlineTypes, true, \ "Scalarize inline types in compiled code") \ \ + product(bool, UseArrayMarkWordCheck, NOT_LP64(false) LP64_ONLY(true), \ + "Use bits in the mark word to check for flat/null-free arrays") \ + \ product(ccstrlist, ForceNonTearable, "", DIAGNOSTIC, \ "List of inline classes which are forced to be atomic " \ "(whitespace and commas separate names, " \ diff --git a/src/hotspot/share/runtime/monitorDeflationThread.cpp b/src/hotspot/share/runtime/monitorDeflationThread.cpp new file mode 100644 index 00000000000..0b1dd2587fd --- /dev/null +++ b/src/hotspot/share/runtime/monitorDeflationThread.cpp @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "classfile/javaClasses.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/java.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/monitorDeflationThread.hpp" +#include "runtime/mutexLocker.hpp" + +MonitorDeflationThread* MonitorDeflationThread::_instance = NULL; + +void MonitorDeflationThread::initialize() { + EXCEPTION_MARK; + + const char* name = "Monitor Deflation Thread"; + Handle string = java_lang_String::create_from_str(name, CHECK); + + // Initialize thread_oop to put it into the system threadGroup + Handle thread_group (THREAD, Universe::system_thread_group()); + Handle thread_oop = JavaCalls::construct_new_instance( + SystemDictionary::Thread_klass(), + vmSymbols::threadgroup_string_void_signature(), + thread_group, + string, + CHECK); + + { + MutexLocker mu(THREAD, Threads_lock); + MonitorDeflationThread* thread = new MonitorDeflationThread(&monitor_deflation_thread_entry); + + // At this point it may be possible that no osthread was created for the + // JavaThread due to lack of memory. We would have to throw an exception + // in that case. However, since this must work and we do not allow + // exceptions anyway, check and abort if this fails. + if (thread == NULL || thread->osthread() == NULL) { + vm_exit_during_initialization("java.lang.OutOfMemoryError", + os::native_thread_creation_failed_msg()); + } + + java_lang_Thread::set_thread(thread_oop(), thread); + java_lang_Thread::set_priority(thread_oop(), NearMaxPriority); + java_lang_Thread::set_daemon(thread_oop()); + thread->set_threadObj(thread_oop()); + _instance = thread; + + Threads::add(thread); + Thread::start(thread); + } +} + +void MonitorDeflationThread::monitor_deflation_thread_entry(JavaThread* jt, TRAPS) { + while (true) { + { + // Need state transition ThreadBlockInVM so that this thread + // will be handled by safepoint correctly when this thread is + // notified at a safepoint. + + // This ThreadBlockInVM object is not also considered to be + // suspend-equivalent because MonitorDeflationThread is not + // visible to external suspension. + + ThreadBlockInVM tbivm(jt); + + MonitorLocker ml(MonitorDeflation_lock, Mutex::_no_safepoint_check_flag); + while (!ObjectSynchronizer::is_async_deflation_needed()) { + // Wait until notified that there is some work to do. + // We wait for GuaranteedSafepointInterval so that + // is_async_deflation_needed() is checked at the same interval. + ml.wait(GuaranteedSafepointInterval); + } + } + + (void)ObjectSynchronizer::deflate_idle_monitors(); + } +} diff --git a/src/hotspot/share/runtime/monitorDeflationThread.hpp b/src/hotspot/share/runtime/monitorDeflationThread.hpp new file mode 100644 index 00000000000..f76a32c26bd --- /dev/null +++ b/src/hotspot/share/runtime/monitorDeflationThread.hpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_MONITORDEFLATIONTHREAD_HPP +#define SHARE_RUNTIME_MONITORDEFLATIONTHREAD_HPP + +#include "runtime/thread.hpp" + +// A hidden from external view JavaThread for deflating idle monitors. + +class MonitorDeflationThread : public JavaThread { + friend class VMStructs; + private: + static MonitorDeflationThread* _instance; + + static void monitor_deflation_thread_entry(JavaThread* thread, TRAPS); + MonitorDeflationThread(ThreadFunction entry_point) : JavaThread(entry_point) {}; + + public: + static void initialize(); + + // Hide this thread from external view. + bool is_hidden_from_external_view() const { return true; } + bool is_monitor_deflation_thread() const { return true; } +}; + +#endif // SHARE_RUNTIME_MONITORDEFLATIONTHREAD_HPP diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 36d19e03c97..9a784bb501a 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -116,6 +116,7 @@ Mutex* OldSets_lock = NULL; Monitor* RootRegionScan_lock = NULL; Mutex* Management_lock = NULL; +Monitor* MonitorDeflation_lock = NULL; Monitor* Service_lock = NULL; Monitor* Notification_lock = NULL; Monitor* PeriodicTask_lock = NULL; @@ -244,6 +245,7 @@ void mutex_init() { def(Patching_lock , PaddedMutex , special, true, _safepoint_check_never); // used for safepointing and code patching. def(CompiledMethod_lock , PaddedMutex , special-1, true, _safepoint_check_never); + def(MonitorDeflation_lock , PaddedMonitor, tty-2, true, _safepoint_check_never); // used for monitor deflation thread operations def(Service_lock , PaddedMonitor, tty-2, true, _safepoint_check_never); // used for service thread operations if (UseNotificationThread) { diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 41d3c0910e9..95a3989bdb6 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -111,6 +111,7 @@ extern Mutex* OldSets_lock; // protects the old region sets extern Monitor* RootRegionScan_lock; // used to notify that the CM threads have finished scanning the IM snapshot regions extern Mutex* Management_lock; // a lock used to serialize JVM management +extern Monitor* MonitorDeflation_lock; // a lock used for monitor deflation thread operation extern Monitor* Service_lock; // a lock used for service thread operation extern Monitor* Notification_lock; // a lock used for notification thread operation extern Monitor* PeriodicTask_lock; // protects the periodic task structure diff --git a/src/hotspot/share/runtime/objectMonitor.cpp b/src/hotspot/share/runtime/objectMonitor.cpp index c8967bfbc1f..8cbe4dd9332 100644 --- a/src/hotspot/share/runtime/objectMonitor.cpp +++ b/src/hotspot/share/runtime/objectMonitor.cpp @@ -265,6 +265,29 @@ static void check_object_context() { #endif // ASSERT } +ObjectMonitor::ObjectMonitor(oop object) : + _header(markWord::zero()), + _object(_oop_storage, object), + _owner(NULL), + _previous_owner_tid(0), + _next_om(NULL), + _recursions(0), + _EntryList(NULL), + _cxq(NULL), + _succ(NULL), + _Responsible(NULL), + _Spinner(0), + _SpinDuration(ObjectMonitor::Knob_SpinLimit), + _contentions(0), + _WaitSet(NULL), + _waiters(0), + _WaitSetLock(0) +{ } + +ObjectMonitor::~ObjectMonitor() { + _object.release(_oop_storage); +} + oop ObjectMonitor::object() const { check_object_context(); if (_object.is_null()) { @@ -280,15 +303,6 @@ oop ObjectMonitor::object_peek() const { return _object.peek(); } -void ObjectMonitor::set_object(oop obj) { - check_object_context(); - if (_object.is_null()) { - _object = WeakHandle(_oop_storage, obj); - } else { - _object.replace(obj); - } -} - // ----------------------------------------------------------------------------- // Enter support @@ -363,7 +377,10 @@ bool ObjectMonitor::enter(TRAPS) { EventJavaMonitorEnter event; if (event.should_commit()) { event.set_monitorClass(object()->klass()); - event.set_address((uintptr_t)object_addr()); + // Set an address that is 'unique enough', such that events close in + // time and with the same address are likely (but not guaranteed) to + // belong to the same object. + event.set_address((uintptr_t)this); } { // Change java thread status to indicate blocked on monitor enter. @@ -475,6 +492,110 @@ int ObjectMonitor::TryLock(Thread * Self) { return -1; } +// Deflate the specified ObjectMonitor if not in-use. Returns true if it +// was deflated and false otherwise. +// +// The async deflation protocol sets owner to DEFLATER_MARKER and +// makes contentions negative as signals to contending threads that +// an async deflation is in progress. There are a number of checks +// as part of the protocol to make sure that the calling thread has +// not lost the race to a contending thread. +// +// The ObjectMonitor has been successfully async deflated when: +// (contentions < 0) +// Contending threads that see that condition know to retry their operation. +// +bool ObjectMonitor::deflate_monitor() { + if (is_busy() != 0) { + // Easy checks are first - the ObjectMonitor is busy so no deflation. + return false; + } + + if (ObjectSynchronizer::is_final_audit() && owner_is_DEFLATER_MARKER()) { + // The final audit can see an already deflated ObjectMonitor on the + // in-use list because MonitorList::unlink_deflated() might have + // blocked for the final safepoint before unlinking all the deflated + // monitors. + assert(contentions() < 0, "must be negative: contentions=%d", contentions()); + // Already returned 'true' when it was originally deflated. + return false; + } + + const oop obj = object_peek(); + + if (obj == NULL) { + // If the object died, we can recycle the monitor without racing with + // Java threads. The GC already broke the association with the object. + set_owner_from(NULL, DEFLATER_MARKER); + assert(contentions() >= 0, "must be non-negative: contentions=%d", contentions()); + _contentions = -max_jint; + } else { + // Attempt async deflation protocol. + + // Set a NULL owner to DEFLATER_MARKER to force any contending thread + // through the slow path. This is just the first part of the async + // deflation dance. + if (try_set_owner_from(NULL, DEFLATER_MARKER) != NULL) { + // The owner field is no longer NULL so we lost the race since the + // ObjectMonitor is now busy. + return false; + } + + if (contentions() > 0 || _waiters != 0) { + // Another thread has raced to enter the ObjectMonitor after + // is_busy() above or has already entered and waited on + // it which makes it busy so no deflation. Restore owner to + // NULL if it is still DEFLATER_MARKER. + if (try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) { + // Deferred decrement for the JT EnterI() that cancelled the async deflation. + add_to_contentions(-1); + } + return false; + } + + // Make a zero contentions field negative to force any contending threads + // to retry. This is the second part of the async deflation dance. + if (Atomic::cmpxchg(&_contentions, (jint)0, -max_jint) != 0) { + // Contentions was no longer 0 so we lost the race since the + // ObjectMonitor is now busy. Restore owner to NULL if it is + // still DEFLATER_MARKER: + if (try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) { + // Deferred decrement for the JT EnterI() that cancelled the async deflation. + add_to_contentions(-1); + } + return false; + } + } + + // Sanity checks for the races: + guarantee(owner_is_DEFLATER_MARKER(), "must be deflater marker"); + guarantee(contentions() < 0, "must be negative: contentions=%d", + contentions()); + guarantee(_waiters == 0, "must be 0: waiters=%d", _waiters); + guarantee(_cxq == NULL, "must be no contending threads: cxq=" + INTPTR_FORMAT, p2i(_cxq)); + guarantee(_EntryList == NULL, + "must be no entering threads: EntryList=" INTPTR_FORMAT, + p2i(_EntryList)); + + if (obj != NULL) { + if (log_is_enabled(Trace, monitorinflation)) { + ResourceMark rm; + log_trace(monitorinflation)("deflate_monitor: object=" INTPTR_FORMAT + ", mark=" INTPTR_FORMAT ", type='%s'", + p2i(obj), obj->mark().value(), + obj->klass()->external_name()); + } + + // Install the old mark word if nobody else has already done it. + install_displaced_markword_in_object(obj); + } + + // We leave owner == DEFLATER_MARKER and contentions < 0 + // to force any racing threads to retry. + return true; // Success, ObjectMonitor has been deflated. +} + // Install the displaced mark word (dmw) of a deflating ObjectMonitor // into the header of the object associated with the monitor. This // idempotent method is called by a thread that is deflating a @@ -1351,7 +1472,10 @@ static void post_monitor_wait_event(EventJavaMonitorWait* event, assert(monitor != NULL, "invariant"); event->set_monitorClass(monitor->object()->klass()); event->set_timeout(timeout); - event->set_address((uintptr_t)monitor->object_addr()); + // Set an address that is 'unique enough', such that events close in + // time and with the same address are likely (but not guaranteed) to + // belong to the same object. + event->set_address((uintptr_t)monitor); event->set_notifier(notifier_tid); event->set_timedOut(timedout); event->commit(); @@ -2124,7 +2248,6 @@ void ObjectMonitor::print() const { print_on(tty); } // (ObjectMonitor) 0x00007fdfb6012e40 = { // _header = 0x0000000000000001 // _object = 0x000000070ff45fd0 -// _allocation_state = Old // _pad_buf0 = { // [0] = '\0' // ... @@ -2155,17 +2278,6 @@ void ObjectMonitor::print_debug_style_on(outputStream* st) const { st->print_cr("(ObjectMonitor*) " INTPTR_FORMAT " = {", p2i(this)); st->print_cr(" _header = " INTPTR_FORMAT, header().value()); st->print_cr(" _object = " INTPTR_FORMAT, p2i(object_peek())); - st->print(" _allocation_state = "); - if (is_free()) { - st->print("Free"); - } else if (is_old()) { - st->print("Old"); - } else if (is_new()) { - st->print("New"); - } else { - st->print("unknown=%d", _allocation_state); - } - st->cr(); st->print_cr(" _pad_buf0 = {"); st->print_cr(" [0] = '\\0'"); st->print_cr(" ..."); diff --git a/src/hotspot/share/runtime/objectMonitor.hpp b/src/hotspot/share/runtime/objectMonitor.hpp index f36943f4d6c..d624d2d724e 100644 --- a/src/hotspot/share/runtime/objectMonitor.hpp +++ b/src/hotspot/share/runtime/objectMonitor.hpp @@ -127,7 +127,7 @@ class ObjectWaiter : public StackObj { #define OM_CACHE_LINE_SIZE DEFAULT_CACHE_LINE_SIZE #endif -class ObjectMonitor { +class ObjectMonitor : public CHeapObj { friend class ObjectSynchronizer; friend class ObjectWaiter; friend class VMStructs; @@ -139,20 +139,12 @@ class ObjectMonitor { // Enforced by the assert() in header_addr(). volatile markWord _header; // displaced object header word - mark WeakHandle _object; // backward object pointer - typedef enum { - Free = 0, // Free must be 0 for monitor to be free after memset(..,0,..). - New, - Old, - ChainMarker - } AllocationState; - AllocationState _allocation_state; // Separate _header and _owner on different cache lines since both can - // have busy multi-threaded access. _header, _object and _allocation_state - // are set at initial inflation. _object and _allocation_state don't - // change until deflation so _object and _allocation_state are good - // choices to share the cache line with _header. + // have busy multi-threaded access. _header and _object are set at initial + // inflation. The _object does not change, so it is a good choice to share + // its cache line with _header. DEFINE_PAD_MINUS_SIZE(0, OM_CACHE_LINE_SIZE, sizeof(volatile markWord) + - sizeof(WeakHandle) + sizeof(AllocationState)); + sizeof(WeakHandle)); // Used by async deflation as a marker in the _owner field: #define DEFLATER_MARKER reinterpret_cast(-1) void* volatile _owner; // pointer to owning thread OR BasicLock @@ -179,7 +171,7 @@ class ObjectMonitor { jint _contentions; // Number of active contentions in enter(). It is used by is_busy() // along with other fields to determine if an ObjectMonitor can be // deflated. It is also used by the async deflation protocol. See - // ObjectSynchronizer::deflate_monitor(). + // ObjectMonitor::deflate_monitor(). protected: ObjectWaiter* volatile _WaitSet; // LL of threads wait()ing on the monitor volatile jint _waiters; // number of waiting threads @@ -268,8 +260,6 @@ class ObjectMonitor { void release_clear_owner(void* old_value); // Simply set _owner field to new_value; current value must match old_value. void set_owner_from(void* old_value, void* new_value); - // Simply set _owner field to new_value; current value must match old_value1 or old_value2. - void set_owner_from(void* old_value1, void* old_value2, void* new_value); // Simply set _owner field to self; current value must match basic_lock_p. void set_owner_from_BasicLock(void* basic_lock_p, Thread* self); // Try to set _owner field to new_value if the current value matches @@ -301,55 +291,15 @@ class ObjectMonitor { ObjectWaiter* next_waiter(ObjectWaiter* o) { return o->_next; } Thread* thread_of_waiter(ObjectWaiter* o) { return o->_thread; } - protected: - // We don't typically expect or want the ctors or dtors to run. - // normal ObjectMonitors are type-stable and immortal. - ObjectMonitor() { ::memset((void*)this, 0, sizeof(*this)); } - - ~ObjectMonitor() { - // TODO: Add asserts ... - // _cxq == 0 _succ == NULL _owner == NULL _waiters == 0 - // _contentions == 0 _EntryList == NULL etc - } - - private: - void Recycle() { - // TODO: add stronger asserts ... - // _cxq == 0 _succ == NULL _owner == NULL _waiters == 0 - // _contentions == 0 EntryList == NULL - // _recursions == 0 _WaitSet == NULL -#ifdef ASSERT - stringStream ss; - assert((is_busy() | _recursions) == 0, "freeing in-use monitor: %s, " - "recursions=" INTX_FORMAT, is_busy_to_string(&ss), _recursions); -#endif - _succ = NULL; - _EntryList = NULL; - _cxq = NULL; - _WaitSet = NULL; - _recursions = 0; - } - - public: + ObjectMonitor(oop object); + ~ObjectMonitor(); oop object() const; oop object_peek() const; - oop* object_addr(); - void set_object(oop obj); - void release_set_allocation_state(AllocationState s); - void set_allocation_state(AllocationState s); - AllocationState allocation_state() const; - AllocationState allocation_state_acquire() const; - bool is_free() const; - bool is_old() const; - bool is_new() const; - bool is_chainmarker() const; // Returns true if the specified thread owns the ObjectMonitor. Otherwise // returns false and throws IllegalMonitorStateException (IMSE). bool check_owner(Thread* THREAD); - void clear(); - void clear_common(); bool enter(TRAPS); void exit(bool not_suspended, TRAPS); @@ -380,6 +330,9 @@ class ObjectMonitor { int TrySpin(Thread* self); void ExitEpilog(Thread* self, ObjectWaiter* Wakee); bool ExitSuspendEquivalent(JavaThread* self); + + // Deflation support + bool deflate_monitor(); void install_displaced_markword_in_object(const oop obj); }; diff --git a/src/hotspot/share/runtime/objectMonitor.inline.hpp b/src/hotspot/share/runtime/objectMonitor.inline.hpp index 0cfc6b8ce4e..6e25a7ba555 100644 --- a/src/hotspot/share/runtime/objectMonitor.inline.hpp +++ b/src/hotspot/share/runtime/objectMonitor.inline.hpp @@ -42,7 +42,6 @@ inline markWord ObjectMonitor::header() const { } inline volatile markWord* ObjectMonitor::header_addr() { - assert((intptr_t)this == (intptr_t)&_header, "sync code expects this"); return &_header; } @@ -72,37 +71,6 @@ inline bool ObjectMonitor::is_being_async_deflated() { return contentions() < 0; } -inline void ObjectMonitor::clear() { - assert(Atomic::load(&_header).value() != 0, "must be non-zero"); - assert(_owner == NULL, "must be NULL: owner=" INTPTR_FORMAT, p2i(_owner)); - - Atomic::store(&_header, markWord::zero()); - - clear_common(); -} - -inline void ObjectMonitor::clear_common() { - // Async deflation protocol uses the header, owner and contentions - // fields. While the ObjectMonitor being deflated is on the global - // free list, we leave those three fields alone; contentions < 0 - // will force any racing threads to retry. The header field is used - // by install_displaced_markword_in_object() to restore the object's - // header so we cannot check its value here. - guarantee(_owner == NULL || _owner == DEFLATER_MARKER, - "must be NULL or DEFLATER_MARKER: owner=" INTPTR_FORMAT, - p2i(_owner)); - assert(contentions() <= 0, "must not be positive: contentions=%d", contentions()); - assert(_waiters == 0, "must be 0: waiters=%d", _waiters); - assert(_recursions == 0, "must be 0: recursions=" INTX_FORMAT, _recursions); - - set_allocation_state(Free); - set_object(NULL); -} - -inline oop* ObjectMonitor::object_addr() { - return (oop*)&_object; -} - // Return number of threads contending for this monitor. inline jint ObjectMonitor::contentions() const { return Atomic::load(&_contentions); @@ -141,23 +109,6 @@ inline void ObjectMonitor::set_owner_from(void* old_value, void* new_value) { p2i(old_value), p2i(new_value)); } -// Simply set _owner field to new_value; current value must match old_value1 or old_value2. -// (Simple means no memory sync needed.) -inline void ObjectMonitor::set_owner_from(void* old_value1, void* old_value2, void* new_value) { - void* prev = Atomic::load(&_owner); - assert(prev == old_value1 || prev == old_value2, - "unexpected prev owner=" INTPTR_FORMAT ", expected1=" - INTPTR_FORMAT " or expected2=" INTPTR_FORMAT, p2i(prev), - p2i(old_value1), p2i(old_value2)); - _owner = new_value; - log_trace(monitorinflation, owner)("set_owner_from(old1=" INTPTR_FORMAT - ", old2=" INTPTR_FORMAT "): mid=" - INTPTR_FORMAT ", prev=" INTPTR_FORMAT - ", new=" INTPTR_FORMAT, p2i(old_value1), - p2i(old_value2), p2i(this), p2i(prev), - p2i(new_value)); -} - // Simply set _owner field to self; current value must match basic_lock_p. inline void ObjectMonitor::set_owner_from_BasicLock(void* basic_lock_p, Thread* self) { #ifdef ASSERT @@ -188,38 +139,6 @@ inline void* ObjectMonitor::try_set_owner_from(void* old_value, void* new_value) return prev; } -inline void ObjectMonitor::release_set_allocation_state(ObjectMonitor::AllocationState s) { - Atomic::release_store(&_allocation_state, s); -} - -inline void ObjectMonitor::set_allocation_state(ObjectMonitor::AllocationState s) { - _allocation_state = s; -} - -inline ObjectMonitor::AllocationState ObjectMonitor::allocation_state() const { - return _allocation_state; -} - -inline ObjectMonitor::AllocationState ObjectMonitor::allocation_state_acquire() const { - return Atomic::load_acquire(&_allocation_state); -} - -inline bool ObjectMonitor::is_free() const { - return _allocation_state == Free; -} - -inline bool ObjectMonitor::is_old() const { - return allocation_state_acquire() == Old; -} - -inline bool ObjectMonitor::is_new() const { - return _allocation_state == New; -} - -inline bool ObjectMonitor::is_chainmarker() const { - return _allocation_state == ChainMarker; -} - // The _next_om field can be concurrently read and modified so we // use Atomic operations to disable compiler optimizations that // might try to elide loading and/or storing this field. diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 60b0c410fdc..e42cd61452a 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -545,11 +545,6 @@ class ParallelSPCleanupTask : public AbstractGangTask { Threads::threads_do(&cl); } - if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_DEFLATE_MONITORS)) { - Tracer t("deflating idle monitors"); - ObjectSynchronizer::do_safepoint_work(); - } - if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_UPDATE_INLINE_CACHES)) { Tracer t("updating inline caches"); InlineCacheBuffer::update_inline_caches(); @@ -611,6 +606,12 @@ void SafepointSynchronize::do_cleanup_tasks() { } assert(InlineCacheBuffer::is_empty(), "should have cleaned up ICBuffer"); + + if (log_is_enabled(Debug, monitorinflation)) { + // The VMThread calls do_final_audit_and_print_stats() which calls + // audit_and_print_stats() at the Info level at VM exit time. + ObjectSynchronizer::audit_and_print_stats(false /* on_exit */); + } } // Methods for determining if a JavaThread is safepoint safe. diff --git a/src/hotspot/share/runtime/safepoint.hpp b/src/hotspot/share/runtime/safepoint.hpp index c9e52b522cd..df9086be145 100644 --- a/src/hotspot/share/runtime/safepoint.hpp +++ b/src/hotspot/share/runtime/safepoint.hpp @@ -71,7 +71,6 @@ class SafepointSynchronize : AllStatic { // The enums are listed in the order of the tasks when done serially. enum SafepointCleanupTasks { SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING, - SAFEPOINT_CLEANUP_DEFLATE_MONITORS, SAFEPOINT_CLEANUP_UPDATE_INLINE_CACHES, SAFEPOINT_CLEANUP_COMPILATION_POLICY, SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH, diff --git a/src/hotspot/share/runtime/serviceThread.cpp b/src/hotspot/share/runtime/serviceThread.cpp index 56f4c0ebba6..42a840fbeec 100644 --- a/src/hotspot/share/runtime/serviceThread.cpp +++ b/src/hotspot/share/runtime/serviceThread.cpp @@ -143,7 +143,6 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { bool thread_id_table_work = false; bool protection_domain_table_work = false; bool oopstorage_work = false; - bool deflate_idle_monitors = false; JvmtiDeferredEvent jvmti_event; bool oop_handles_to_release = false; bool cldg_cleanup_work = false; @@ -174,13 +173,10 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { (protection_domain_table_work = SystemDictionary::pd_cache_table()->has_work()) | (oopstorage_work = OopStorage::has_cleanup_work_and_reset()) | (oop_handles_to_release = (_oop_handle_list != NULL)) | - (cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) | - (deflate_idle_monitors = ObjectSynchronizer::is_async_deflation_needed()) + (cldg_cleanup_work = ClassLoaderDataGraph::should_clean_metaspaces_and_reset()) ) == 0) { // Wait until notified that there is some work to do. - // We wait for GuaranteedSafepointInterval so that - // is_async_deflation_needed() is checked at the same interval. - ml.wait(GuaranteedSafepointInterval); + ml.wait(); } if (has_jvmti_events) { @@ -233,10 +229,6 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) { cleanup_oopstorages(); } - if (deflate_idle_monitors) { - ObjectSynchronizer::deflate_idle_monitors(); - } - if (oop_handles_to_release) { release_oop_handles(); } diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index afa8a81fbc8..1e64ce66a4a 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -111,8 +111,6 @@ address StubRoutines::_arrayof_jlong_disjoint_arraycopy = CAST_FROM_FN_PTR(addr address StubRoutines::_arrayof_oop_disjoint_arraycopy = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_oop_copy); address StubRoutines::_arrayof_oop_disjoint_arraycopy_uninit = CAST_FROM_FN_PTR(address, StubRoutines::arrayof_oop_copy_uninit); -address StubRoutines::_zero_aligned_words = CAST_FROM_FN_PTR(address, Copy::zero_to_words); - address StubRoutines::_data_cache_writeback = NULL; address StubRoutines::_data_cache_writeback_sync = NULL; diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index 1553556be8c..2b345d9c946 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -207,9 +207,6 @@ class StubRoutines: AllStatic { static address _arrayof_jshort_fill; static address _arrayof_jint_fill; - // zero heap space aligned to jlong (8 bytes) - static address _zero_aligned_words; - static address _aescrypt_encryptBlock; static address _aescrypt_decryptBlock; static address _cipherBlockChaining_encryptAESCrypt; @@ -445,8 +442,6 @@ class StubRoutines: AllStatic { static address select_fill_function(BasicType t, bool aligned, const char* &name); - static address zero_aligned_words() { return _zero_aligned_words; } - // // Safefetch stub support // diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 8f1d1b06962..82643cffa48 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -24,9 +24,9 @@ #include "precompiled.hpp" #include "classfile/vmSymbols.hpp" +#include "jfr/jfrEvents.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" -#include "jfr/jfrEvents.hpp" #include "memory/allocation.inline.hpp" #include "memory/metaspaceShared.hpp" #include "memory/padded.hpp" @@ -57,10 +57,122 @@ #include "utilities/events.hpp" #include "utilities/preserveException.hpp" +class MonitorList { + ObjectMonitor* volatile _head; + volatile size_t _count; + volatile size_t _max; + +public: + void add(ObjectMonitor* monitor); + size_t unlink_deflated(Thread* self, LogStream* ls, elapsedTimer* timer_p, + GrowableArray* unlinked_list); + size_t count() const; + size_t max() const; + + class Iterator; + Iterator iterator() const; +}; + +class MonitorList::Iterator { + ObjectMonitor* _current; + +public: + Iterator(ObjectMonitor* head) : _current(head) {} + bool has_next() const { return _current != NULL; } + ObjectMonitor* next(); +}; + +void MonitorList::add(ObjectMonitor* m) { + ObjectMonitor* head; + do { + head = Atomic::load(&_head); + m->set_next_om(head); + } while (Atomic::cmpxchg(&_head, head, m) != head); + + size_t count = Atomic::add(&_count, 1u); + if (count > max()) { + Atomic::inc(&_max); + } +} + +size_t MonitorList::count() const { + return Atomic::load(&_count); +} + +size_t MonitorList::max() const { + return Atomic::load(&_max); +} + +// Walk the in-use list and unlink (at most MonitorDeflationMax) deflated +// ObjectMonitors. Returns the number of unlinked ObjectMonitors. +size_t MonitorList::unlink_deflated(Thread* self, LogStream* ls, + elapsedTimer* timer_p, + GrowableArray* unlinked_list) { + size_t unlinked_count = 0; + ObjectMonitor* prev = NULL; + ObjectMonitor* head = Atomic::load_acquire(&_head); + ObjectMonitor* m = head; + do { + if (m->is_being_async_deflated()) { + // Find next live ObjectMonitor. + ObjectMonitor* next = m; + do { + ObjectMonitor* next_next = next->next_om(); + unlinked_count++; + unlinked_list->append(next); + next = next_next; + if (unlinked_count >= (size_t)MonitorDeflationMax) { + // Reached the max so bail out on the gathering loop. + break; + } + } while (next != NULL && next->is_being_async_deflated()); + if (prev == NULL) { + ObjectMonitor* prev_head = Atomic::cmpxchg(&_head, head, next); + if (prev_head != head) { + // Find new prev ObjectMonitor that just got inserted. + for (ObjectMonitor* n = prev_head; n != m; n = n->next_om()) { + prev = n; + } + prev->set_next_om(next); + } + } else { + prev->set_next_om(next); + } + if (unlinked_count >= (size_t)MonitorDeflationMax) { + // Reached the max so bail out on the searching loop. + break; + } + m = next; + } else { + prev = m; + m = m->next_om(); + } + + if (self->is_Java_thread()) { + // A JavaThread must check for a safepoint/handshake and honor it. + ObjectSynchronizer::chk_for_block_req(self->as_Java_thread(), "unlinking", + "unlinked_count", unlinked_count, + ls, timer_p); + } + } while (m != NULL); + Atomic::sub(&_count, unlinked_count); + return unlinked_count; +} + +MonitorList::Iterator MonitorList::iterator() const { + return Iterator(Atomic::load_acquire(&_head)); +} + +ObjectMonitor* MonitorList::Iterator::next() { + ObjectMonitor* current = _current; + _current = current->next_om(); + return current; +} + // The "core" versions of monitor enter and exit reside in this file. // The interpreter and compilers contain specialized transliterated -// variants of the enter-exit fast-path operations. See i486.ad fast_lock(), -// for instance. If you make changes here, make sure to modify the +// variants of the enter-exit fast-path operations. See c2_MacroAssembler_x86.cpp +// fast_lock(...) for instance. If you make changes here, make sure to modify the // interpreter, and both C1 and C2 fast-path inline locking code emission. // // ----------------------------------------------------------------------------- @@ -74,7 +186,7 @@ char* bytes = NULL; \ int len = 0; \ jlong jtid = SharedRuntime::get_java_tid(thread); \ - Symbol* klassname = ((oop)(obj))->klass()->name(); \ + Symbol* klassname = obj->klass()->name(); \ if (klassname != NULL) { \ bytes = (char*)klassname->bytes(); \ len = klassname->utf8_length(); \ @@ -118,48 +230,26 @@ int dtrace_waited_probe(ObjectMonitor* monitor, Handle obj, Thread* thr) { #define NINFLATIONLOCKS 256 static volatile intptr_t gInflationLocks[NINFLATIONLOCKS]; -// global list of blocks of monitors -PaddedObjectMonitor* ObjectSynchronizer::g_block_list = NULL; +static MonitorList _in_use_list; +// The ratio of the current _in_use_list count to the ceiling is used +// to determine if we are above MonitorUsedDeflationThreshold and need +// to do an async monitor deflation cycle. The ceiling is increased by +// AvgMonitorsPerThreadEstimate when a thread is added to the system +// and is decreased by AvgMonitorsPerThreadEstimate when a thread is +// removed from the system. +// Note: If the _in_use_list max exceeds the ceiling, then +// monitors_used_above_threshold() will use the in_use_list max instead +// of the thread count derived ceiling because we have used more +// ObjectMonitors than the estimated average. +// +// Start the ceiling with the estimate for one thread. +// This is a 'jint' because the range of AvgMonitorsPerThreadEstimate +// is 0..max_jint: +static jint _in_use_list_ceiling = AvgMonitorsPerThreadEstimate; bool volatile ObjectSynchronizer::_is_async_deflation_requested = false; bool volatile ObjectSynchronizer::_is_final_audit = false; jlong ObjectSynchronizer::_last_async_deflation_time_ns = 0; -struct ObjectMonitorListGlobals { - char _pad_prefix[OM_CACHE_LINE_SIZE]; - // These are highly shared list related variables. - // To avoid false-sharing they need to be the sole occupants of a cache line. - - // Global ObjectMonitor free list. Newly allocated and deflated - // ObjectMonitors are prepended here. - ObjectMonitor* _free_list; - DEFINE_PAD_MINUS_SIZE(1, OM_CACHE_LINE_SIZE, sizeof(ObjectMonitor*)); - - // Global ObjectMonitor in-use list. When a JavaThread is exiting, - // ObjectMonitors on its per-thread in-use list are prepended here. - ObjectMonitor* _in_use_list; - DEFINE_PAD_MINUS_SIZE(2, OM_CACHE_LINE_SIZE, sizeof(ObjectMonitor*)); - - // Global ObjectMonitor wait list. Deflated ObjectMonitors wait on - // this list until after a handshake or a safepoint for platforms - // that don't support handshakes. After the handshake or safepoint, - // the deflated ObjectMonitors are prepended to free_list. - ObjectMonitor* _wait_list; - DEFINE_PAD_MINUS_SIZE(3, OM_CACHE_LINE_SIZE, sizeof(ObjectMonitor*)); - - int _free_count; // # on free_list - DEFINE_PAD_MINUS_SIZE(4, OM_CACHE_LINE_SIZE, sizeof(int)); - - int _in_use_count; // # on in_use_list - DEFINE_PAD_MINUS_SIZE(5, OM_CACHE_LINE_SIZE, sizeof(int)); - - int _population; // # Extant -- in circulation - DEFINE_PAD_MINUS_SIZE(6, OM_CACHE_LINE_SIZE, sizeof(int)); - - int _wait_count; // # on wait_list - DEFINE_PAD_MINUS_SIZE(7, OM_CACHE_LINE_SIZE, sizeof(int)); -}; -static ObjectMonitorListGlobals om_list_globals; - #define CHECK_THROW_NOSYNC_IMSE(obj) \ if (EnableValhalla && (obj)->mark().is_inline_type()) { \ ResourceMark rm(THREAD); \ @@ -172,269 +262,6 @@ static ObjectMonitorListGlobals om_list_globals; THROW_MSG_0(vmSymbols::java_lang_IllegalMonitorStateException(), obj->klass()->external_name()); \ } -// =====================> Spin-lock functions - -// ObjectMonitors are not lockable outside of this file. We use spin-locks -// implemented using a bit in the _next_om field instead of the heavier -// weight locking mechanisms for faster list management. - -#define OM_LOCK_BIT 0x1 - -// Return true if the ObjectMonitor is locked. -// Otherwise returns false. -static bool is_locked(ObjectMonitor* om) { - return ((intptr_t)om->next_om_acquire() & OM_LOCK_BIT) == OM_LOCK_BIT; -} - -// Mark an ObjectMonitor* with OM_LOCK_BIT and return it. -static ObjectMonitor* mark_om_ptr(ObjectMonitor* om) { - return (ObjectMonitor*)((intptr_t)om | OM_LOCK_BIT); -} - -// Return the unmarked next field in an ObjectMonitor. Note: the next -// field may or may not have been marked with OM_LOCK_BIT originally. -static ObjectMonitor* unmarked_next(ObjectMonitor* om) { - return (ObjectMonitor*)((intptr_t)om->next_om() & ~OM_LOCK_BIT); -} - -// Try to lock an ObjectMonitor. Returns true if locking was successful. -// Otherwise returns false. -static bool try_om_lock(ObjectMonitor* om) { - // Get current next field without any OM_LOCK_BIT value. - ObjectMonitor* next = unmarked_next(om); - if (om->try_set_next_om(next, mark_om_ptr(next)) != next) { - return false; // Cannot lock the ObjectMonitor. - } - return true; -} - -// Lock an ObjectMonitor. -static void om_lock(ObjectMonitor* om) { - while (true) { - if (try_om_lock(om)) { - return; - } - } -} - -// Unlock an ObjectMonitor. -static void om_unlock(ObjectMonitor* om) { - ObjectMonitor* next = om->next_om(); - guarantee(((intptr_t)next & OM_LOCK_BIT) == OM_LOCK_BIT, "next=" INTPTR_FORMAT - " must have OM_LOCK_BIT=%x set.", p2i(next), OM_LOCK_BIT); - - next = (ObjectMonitor*)((intptr_t)next & ~OM_LOCK_BIT); // Clear OM_LOCK_BIT. - om->release_set_next_om(next); -} - -// Get the list head after locking it. Returns the list head or NULL -// if the list is empty. -static ObjectMonitor* get_list_head_locked(ObjectMonitor** list_p) { - while (true) { - // Acquire semantics not needed on this list load since we're - // checking for NULL here or following up with a cmpxchg() via - // try_om_lock() below and we retry on cmpxchg() failure. - ObjectMonitor* mid = Atomic::load(list_p); - if (mid == NULL) { - return NULL; // The list is empty. - } - if (try_om_lock(mid)) { - // Acquire semantics not needed on this list load since memory is - // already consistent due to the cmpxchg() via try_om_lock() above. - if (Atomic::load(list_p) != mid) { - // The list head changed before we could lock it so we have to retry. - om_unlock(mid); - continue; - } - return mid; - } - } -} - -#undef OM_LOCK_BIT - - -// =====================> List Management functions - -// Prepend a list of ObjectMonitors to the specified *list_p. 'tail' is -// the last ObjectMonitor in the list and there are 'count' on the list. -// Also updates the specified *count_p. -static void prepend_list_to_common(ObjectMonitor* list, ObjectMonitor* tail, - int count, ObjectMonitor** list_p, - int* count_p) { - while (true) { - // Acquire semantics not needed on this list load since we're - // following up with a cmpxchg() via try_om_lock() below and we - // retry on cmpxchg() failure. - ObjectMonitor* cur = Atomic::load(list_p); - // Prepend list to *list_p. - if (!try_om_lock(tail)) { - // Failed to lock tail due to a list walker so try it all again. - continue; - } - // Release semantics not needed on this "unlock" since memory is - // already consistent due to the cmpxchg() via try_om_lock() above. - tail->set_next_om(cur); // tail now points to cur (and unlocks tail) - if (cur == NULL) { - // No potential race with takers or other prependers since - // *list_p is empty. - if (Atomic::cmpxchg(list_p, cur, list) == cur) { - // Successfully switched *list_p to the list value. - Atomic::add(count_p, count); - break; - } - // Implied else: try it all again - } else { - if (!try_om_lock(cur)) { - continue; // failed to lock cur so try it all again - } - // We locked cur so try to switch *list_p to the list value. - if (Atomic::cmpxchg(list_p, cur, list) != cur) { - // The list head has changed so unlock cur and try again: - om_unlock(cur); - continue; - } - Atomic::add(count_p, count); - om_unlock(cur); - break; - } - } -} - -// Prepend a newly allocated block of ObjectMonitors to g_block_list and -// om_list_globals._free_list. Also updates om_list_globals._population -// and om_list_globals._free_count. -void ObjectSynchronizer::prepend_block_to_lists(PaddedObjectMonitor* new_blk) { - // First we handle g_block_list: - while (true) { - PaddedObjectMonitor* cur = Atomic::load(&g_block_list); - // Prepend new_blk to g_block_list. The first ObjectMonitor in - // a block is reserved for use as linkage to the next block. - new_blk[0].set_next_om(cur); - if (Atomic::cmpxchg(&g_block_list, cur, new_blk) == cur) { - // Successfully switched g_block_list to the new_blk value. - Atomic::add(&om_list_globals._population, _BLOCKSIZE - 1); - break; - } - // Implied else: try it all again - } - - // Second we handle om_list_globals._free_list: - prepend_list_to_common(new_blk + 1, &new_blk[_BLOCKSIZE - 1], _BLOCKSIZE - 1, - &om_list_globals._free_list, &om_list_globals._free_count); -} - -// Prepend a list of ObjectMonitors to om_list_globals._free_list. -// 'tail' is the last ObjectMonitor in the list and there are 'count' -// on the list. Also updates om_list_globals._free_count. -static void prepend_list_to_global_free_list(ObjectMonitor* list, - ObjectMonitor* tail, int count) { - prepend_list_to_common(list, tail, count, &om_list_globals._free_list, - &om_list_globals._free_count); -} - -// Prepend a list of ObjectMonitors to om_list_globals._wait_list. -// 'tail' is the last ObjectMonitor in the list and there are 'count' -// on the list. Also updates om_list_globals._wait_count. -static void prepend_list_to_global_wait_list(ObjectMonitor* list, - ObjectMonitor* tail, int count) { - prepend_list_to_common(list, tail, count, &om_list_globals._wait_list, - &om_list_globals._wait_count); -} - -// Prepend a list of ObjectMonitors to om_list_globals._in_use_list. -// 'tail' is the last ObjectMonitor in the list and there are 'count' -// on the list. Also updates om_list_globals._in_use_list. -static void prepend_list_to_global_in_use_list(ObjectMonitor* list, - ObjectMonitor* tail, int count) { - prepend_list_to_common(list, tail, count, &om_list_globals._in_use_list, - &om_list_globals._in_use_count); -} - -// Prepend an ObjectMonitor to the specified list. Also updates -// the specified counter. -static void prepend_to_common(ObjectMonitor* m, ObjectMonitor** list_p, - int* count_p) { - while (true) { - om_lock(m); // Lock m so we can safely update its next field. - ObjectMonitor* cur = NULL; - // Lock the list head to guard against races with a list walker - // or async deflater thread (which only races in om_in_use_list): - if ((cur = get_list_head_locked(list_p)) != NULL) { - // List head is now locked so we can safely switch it. Release - // semantics not needed on this "unlock" since memory is already - // consistent due to the cmpxchg() via get_list_head_locked() above. - m->set_next_om(cur); // m now points to cur (and unlocks m) - OrderAccess::storestore(); // Make sure set_next_om() is seen first. - Atomic::store(list_p, m); // Switch list head to unlocked m. - om_unlock(cur); - break; - } - // The list is empty so try to set the list head. - assert(cur == NULL, "cur must be NULL: cur=" INTPTR_FORMAT, p2i(cur)); - // Release semantics not needed on this "unlock" since memory - // is already consistent. - m->set_next_om(cur); // m now points to NULL (and unlocks m) - if (Atomic::cmpxchg(list_p, cur, m) == cur) { - // List head is now unlocked m. - break; - } - // Implied else: try it all again - } - Atomic::inc(count_p); -} - -// Prepend an ObjectMonitor to a per-thread om_free_list. -// Also updates the per-thread om_free_count. -static void prepend_to_om_free_list(Thread* self, ObjectMonitor* m) { - prepend_to_common(m, &self->om_free_list, &self->om_free_count); -} - -// Prepend an ObjectMonitor to a per-thread om_in_use_list. -// Also updates the per-thread om_in_use_count. -static void prepend_to_om_in_use_list(Thread* self, ObjectMonitor* m) { - prepend_to_common(m, &self->om_in_use_list, &self->om_in_use_count); -} - -// Take an ObjectMonitor from the start of the specified list. Also -// decrements the specified counter. Returns NULL if none are available. -static ObjectMonitor* take_from_start_of_common(ObjectMonitor** list_p, - int* count_p) { - ObjectMonitor* take = NULL; - // Lock the list head to guard against races with a list walker - // or async deflater thread (which only races in om_list_globals._free_list): - if ((take = get_list_head_locked(list_p)) == NULL) { - return NULL; // None are available. - } - ObjectMonitor* next = unmarked_next(take); - // Switch locked list head to next (which unlocks the list head, but - // leaves take locked). Release semantics not needed on this "unlock" - // since memory is already consistent due to the cmpxchg() via - // get_list_head_locked() above. - Atomic::store(list_p, next); - Atomic::dec(count_p); - // Unlock take, but leave the next value for any lagging list - // walkers. It will get cleaned up when take is prepended to - // the in-use list: - om_unlock(take); - return take; -} - -// Take an ObjectMonitor from the start of the om_list_globals._free_list. -// Also updates om_list_globals._free_count. Returns NULL if none are -// available. -static ObjectMonitor* take_from_start_of_global_free_list() { - return take_from_start_of_common(&om_list_globals._free_list, - &om_list_globals._free_count); -} - -// Take an ObjectMonitor from the start of a per-thread free-list. -// Also updates om_free_count. Returns NULL if none are available. -static ObjectMonitor* take_from_start_of_om_free_list(Thread* self) { - return take_from_start_of_common(&self->om_free_list, &self->om_free_count); -} - - // =====================> Quick functions // The quick_* forms are special fast-path variants used to improve @@ -1335,43 +1162,60 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob // Visitors ... void ObjectSynchronizer::monitors_iterate(MonitorClosure* closure) { - PaddedObjectMonitor* block = Atomic::load(&g_block_list); - while (block != NULL) { - assert(block->is_chainmarker(), "must be a block header"); - for (int i = _BLOCKSIZE - 1; i > 0; i--) { - ObjectMonitor* mid = (ObjectMonitor *)(block + i); - if (mid->object_peek() != NULL) { - // Only process with closure if the object is set. - - // monitors_iterate() is only called at a safepoint or when the - // target thread is suspended or when the target thread is - // operating on itself. The current closures in use today are - // only interested in an owned ObjectMonitor and ownership - // cannot be dropped under the calling contexts so the - // ObjectMonitor cannot be async deflated. - closure->do_monitor(mid); - } + MonitorList::Iterator iter = _in_use_list.iterator(); + while (iter.has_next()) { + ObjectMonitor* mid = iter.next(); + if (!mid->is_being_async_deflated() && mid->object_peek() != NULL) { + // Only process with closure if the object is set. + + // monitors_iterate() is only called at a safepoint or when the + // target thread is suspended or when the target thread is + // operating on itself. The current closures in use today are + // only interested in an owned ObjectMonitor and ownership + // cannot be dropped under the calling contexts so the + // ObjectMonitor cannot be async deflated. + closure->do_monitor(mid); } - // unmarked_next() is not needed with g_block_list (no locking - // used with block linkage _next_om fields). - block = (PaddedObjectMonitor*)block->next_om(); } } -static bool monitors_used_above_threshold() { - int population = Atomic::load(&om_list_globals._population); - if (population == 0) { +static bool monitors_used_above_threshold(MonitorList* list) { + // Start with ceiling based on a per-thread estimate: + size_t ceiling = ObjectSynchronizer::in_use_list_ceiling(); + if (ceiling < list->max()) { + // The max used by the system has exceeded the ceiling so use that: + ceiling = list->max(); + } + if (ceiling == 0) { return false; } if (MonitorUsedDeflationThreshold > 0) { - int monitors_used = population - Atomic::load(&om_list_globals._free_count) - - Atomic::load(&om_list_globals._wait_count); - int monitor_usage = (monitors_used * 100LL) / population; - return monitor_usage > MonitorUsedDeflationThreshold; + size_t monitors_used = list->count(); + size_t monitor_usage = (monitors_used * 100LL) / ceiling; + return int(monitor_usage) > MonitorUsedDeflationThreshold; } return false; } +size_t ObjectSynchronizer::in_use_list_ceiling() { + // _in_use_list_ceiling is a jint so this cast could lose precision, + // but in reality the ceiling should never get that high. + return (size_t)_in_use_list_ceiling; +} + +void ObjectSynchronizer::dec_in_use_list_ceiling() { + Atomic::add(&_in_use_list_ceiling, (jint)-AvgMonitorsPerThreadEstimate); +#ifdef ASSERT + size_t l_in_use_list_ceiling = in_use_list_ceiling(); +#endif + assert(l_in_use_list_ceiling > 0, "in_use_list_ceiling=" SIZE_FORMAT + ": must be > 0", l_in_use_list_ceiling); +} + +void ObjectSynchronizer::inc_in_use_list_ceiling() { + Atomic::add(&_in_use_list_ceiling, (jint)AvgMonitorsPerThreadEstimate); +} + bool ObjectSynchronizer::is_async_deflation_needed() { if (is_async_deflation_requested()) { // Async deflation request. @@ -1379,11 +1223,11 @@ bool ObjectSynchronizer::is_async_deflation_needed() { } if (AsyncDeflationInterval > 0 && time_since_last_async_deflation_ms() > AsyncDeflationInterval && - monitors_used_above_threshold()) { + monitors_used_above_threshold(&_in_use_list)) { // It's been longer than our specified deflate interval and there // are too many monitors in use. We don't deflate more frequently // than AsyncDeflationInterval (unless is_async_deflation_requested) - // in order to not swamp the ServiceThread. + // in order to not swamp the MonitorDeflationThread. return true; } return false; @@ -1396,7 +1240,7 @@ bool ObjectSynchronizer::request_deflate_idle_monitors() { jlong last_time = last_async_deflation_time_ns(); set_is_async_deflation_requested(true); { - MonitorLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); + MonitorLocker ml(MonitorDeflation_lock, Mutex::_no_safepoint_check_flag); ml.notify_all(); } const int N_CHECKS = 5; @@ -1425,410 +1269,6 @@ jlong ObjectSynchronizer::time_since_last_async_deflation_ms() { return (os::javaTimeNanos() - last_async_deflation_time_ns()) / (NANOUNITS / MILLIUNITS); } - -// ----------------------------------------------------------------------------- -// ObjectMonitor Lifecycle -// ----------------------- -// Inflation unlinks monitors from om_list_globals._free_list or a per-thread -// free list and associates them with objects. Async deflation disassociates -// idle monitors from objects. Such scavenged monitors are returned to the -// om_list_globals._free_list. -// -// ObjectMonitors reside in type-stable memory (TSM) and are immortal. -// -// Lifecycle: -// -- unassigned and on the om_list_globals._free_list -// -- unassigned and on a per-thread free list -// -- assigned to an object. The object is inflated and the mark refers -// to the ObjectMonitor. - -ObjectMonitor* ObjectSynchronizer::om_alloc(Thread* self) { - // A large MAXPRIVATE value reduces both list lock contention - // and list coherency traffic, but also tends to increase the - // number of ObjectMonitors in circulation as well as the - // scavenge costs. As usual, we lean toward time in space-time - // tradeoffs. - const int MAXPRIVATE = 1024; - NoSafepointVerifier nsv; - - for (;;) { - ObjectMonitor* m; - - // 1: try to allocate from the thread's local om_free_list. - // Threads will attempt to allocate first from their local list, then - // from the global list, and only after those attempts fail will the - // thread attempt to instantiate new monitors. Thread-local free lists - // improve allocation latency, as well as reducing coherency traffic - // on the shared global list. - m = take_from_start_of_om_free_list(self); - if (m != NULL) { - guarantee(m->object_peek() == NULL, "invariant"); - m->set_allocation_state(ObjectMonitor::New); - prepend_to_om_in_use_list(self, m); - return m; - } - - // 2: try to allocate from the global om_list_globals._free_list - // If we're using thread-local free lists then try - // to reprovision the caller's free list. - // Acquire semantics not needed on this list load since memory - // is already consistent due to the cmpxchg() via - // take_from_start_of_om_free_list() above. - if (Atomic::load(&om_list_globals._free_list) != NULL) { - // Reprovision the thread's om_free_list. - // Use bulk transfers to reduce the allocation rate and heat - // on various locks. - for (int i = self->om_free_provision; --i >= 0;) { - ObjectMonitor* take = take_from_start_of_global_free_list(); - if (take == NULL) { - break; // No more are available. - } - guarantee(take->object_peek() == NULL, "invariant"); - // We allowed 3 field values to linger during async deflation. - // Clear or restore them as appropriate. - take->set_header(markWord::zero()); - // DEFLATER_MARKER is the only non-NULL value we should see here. - take->try_set_owner_from(DEFLATER_MARKER, NULL); - if (take->contentions() < 0) { - // Add back max_jint to restore the contentions field to its - // proper value. - take->add_to_contentions(max_jint); - -#ifdef ASSERT - jint l_contentions = take->contentions(); - assert(l_contentions >= 0, "must not be negative: l_contentions=%d, contentions=%d", - l_contentions, take->contentions()); -#endif - } - take->Recycle(); - // Since we're taking from the global free-list, take must be Free. - // om_release() also sets the allocation state to Free because it - // is called from other code paths. - assert(take->is_free(), "invariant"); - om_release(self, take, false); - } - self->om_free_provision += 1 + (self->om_free_provision / 2); - if (self->om_free_provision > MAXPRIVATE) self->om_free_provision = MAXPRIVATE; - continue; - } - - // 3: allocate a block of new ObjectMonitors - // Both the local and global free lists are empty -- resort to malloc(). - // In the current implementation ObjectMonitors are TSM - immortal. - // Ideally, we'd write "new ObjectMonitor[_BLOCKSIZE], but we want - // each ObjectMonitor to start at the beginning of a cache line, - // so we use align_up(). - // A better solution would be to use C++ placement-new. - // BEWARE: As it stands currently, we don't run the ctors! - assert(_BLOCKSIZE > 1, "invariant"); - size_t neededsize = sizeof(PaddedObjectMonitor) * _BLOCKSIZE; - PaddedObjectMonitor* temp; - size_t aligned_size = neededsize + (OM_CACHE_LINE_SIZE - 1); - void* real_malloc_addr = NEW_C_HEAP_ARRAY(char, aligned_size, mtInternal); - temp = (PaddedObjectMonitor*)align_up(real_malloc_addr, OM_CACHE_LINE_SIZE); - (void)memset((void *) temp, 0, neededsize); - - // Format the block. - // initialize the linked list, each monitor points to its next - // forming the single linked free list, the very first monitor - // will points to next block, which forms the block list. - // The trick of using the 1st element in the block as g_block_list - // linkage should be reconsidered. A better implementation would - // look like: class Block { Block * next; int N; ObjectMonitor Body [N] ; } - - for (int i = 1; i < _BLOCKSIZE; i++) { - temp[i].set_next_om((ObjectMonitor*)&temp[i + 1]); - assert(temp[i].is_free(), "invariant"); - } - - // terminate the last monitor as the end of list - temp[_BLOCKSIZE - 1].set_next_om((ObjectMonitor*)NULL); - - // Element [0] is reserved for global list linkage - temp[0].set_allocation_state(ObjectMonitor::ChainMarker); - - // Consider carving out this thread's current request from the - // block in hand. This avoids some lock traffic and redundant - // list activity. - - prepend_block_to_lists(temp); - } -} - -// Place "m" on the caller's private per-thread om_free_list. -// In practice there's no need to clamp or limit the number of -// monitors on a thread's om_free_list as the only non-allocation time -// we'll call om_release() is to return a monitor to the free list after -// a CAS attempt failed. This doesn't allow unbounded #s of monitors to -// accumulate on a thread's free list. -// -// Key constraint: all ObjectMonitors on a thread's free list and the global -// free list must have their object field set to null. This prevents the -// scavenger -- deflate_monitor_list() -- from reclaiming them -// while we are trying to release them. - -void ObjectSynchronizer::om_release(Thread* self, ObjectMonitor* m, - bool from_per_thread_alloc) { - guarantee(m->header().value() == 0, "invariant"); - guarantee(m->object_peek() == NULL, "invariant"); - NoSafepointVerifier nsv; - - if ((m->is_busy() | m->_recursions) != 0) { - stringStream ss; - fatal("freeing in-use monitor: %s, recursions=" INTX_FORMAT, - m->is_busy_to_string(&ss), m->_recursions); - } - m->set_allocation_state(ObjectMonitor::Free); - // _next_om is used for both per-thread in-use and free lists so - // we have to remove 'm' from the in-use list first (as needed). - if (from_per_thread_alloc) { - // Need to remove 'm' from om_in_use_list. - ObjectMonitor* mid = NULL; - ObjectMonitor* next = NULL; - - // This list walk can race with another list walker or with async - // deflation so we have to worry about an ObjectMonitor being - // removed from this list while we are walking it. - - // Lock the list head to avoid racing with another list walker - // or with async deflation. - if ((mid = get_list_head_locked(&self->om_in_use_list)) == NULL) { - fatal("thread=" INTPTR_FORMAT " in-use list must not be empty.", p2i(self)); - } - next = unmarked_next(mid); - if (m == mid) { - // First special case: - // 'm' matches mid, is the list head and is locked. Switch the list - // head to next which unlocks the list head, but leaves the extracted - // mid locked. Release semantics not needed on this "unlock" since - // memory is already consistent due to the get_list_head_locked() - // above. - Atomic::store(&self->om_in_use_list, next); - } else if (m == next) { - // Second special case: - // 'm' matches next after the list head and we already have the list - // head locked so set mid to what we are extracting: - mid = next; - // Lock mid to prevent races with a list walker or an async - // deflater thread that's ahead of us. The locked list head - // prevents races from behind us. - om_lock(mid); - // Update next to what follows mid (if anything): - next = unmarked_next(mid); - // Switch next after the list head to new next which unlocks the - // list head, but leaves the extracted mid locked. Release semantics - // not needed on this "unlock" since memory is already consistent - // due to the get_list_head_locked() above. - self->om_in_use_list->set_next_om(next); - } else { - // We have to search the list to find 'm'. - guarantee(next != NULL, "thread=" INTPTR_FORMAT ": om_in_use_list=" INTPTR_FORMAT - " is too short.", p2i(self), p2i(self->om_in_use_list)); - // Our starting anchor is next after the list head which is the - // last ObjectMonitor we checked: - ObjectMonitor* anchor = next; - // Lock anchor to prevent races with a list walker or an async - // deflater thread that's ahead of us. The locked list head - // prevents races from behind us. - om_lock(anchor); - om_unlock(mid); // Unlock the list head now that anchor is locked. - while ((mid = unmarked_next(anchor)) != NULL) { - if (m == mid) { - // We found 'm' on the per-thread in-use list so extract it. - // Update next to what follows mid (if anything): - next = unmarked_next(mid); - // Switch next after the anchor to new next which unlocks the - // anchor, but leaves the extracted mid locked. Release semantics - // not needed on this "unlock" since memory is already consistent - // due to the om_unlock() above before entering the loop or the - // om_unlock() below before looping again. - anchor->set_next_om(next); - break; - } else { - // Lock the next anchor to prevent races with a list walker - // or an async deflater thread that's ahead of us. The locked - // current anchor prevents races from behind us. - om_lock(mid); - // Unlock current anchor now that next anchor is locked: - om_unlock(anchor); - anchor = mid; // Advance to new anchor and try again. - } - } - } - - if (mid == NULL) { - // Reached end of the list and didn't find 'm' so: - fatal("thread=" INTPTR_FORMAT " must find m=" INTPTR_FORMAT "on om_in_use_list=" - INTPTR_FORMAT, p2i(self), p2i(m), p2i(self->om_in_use_list)); - } - - // At this point mid is disconnected from the in-use list so - // its lock no longer has any effects on the in-use list. - Atomic::dec(&self->om_in_use_count); - // Unlock mid, but leave the next value for any lagging list - // walkers. It will get cleaned up when mid is prepended to - // the thread's free list: - om_unlock(mid); - } - - prepend_to_om_free_list(self, m); - guarantee(m->is_free(), "invariant"); -} - -// Return ObjectMonitors on a moribund thread's free and in-use -// lists to the appropriate global lists. The ObjectMonitors on the -// per-thread in-use list may still be in use by other threads. -// -// We currently call om_flush() from Threads::remove() before the -// thread has been excised from the thread list and is no longer a -// mutator. -// -// deflate_global_idle_monitors() and deflate_per_thread_idle_monitors() -// (in another thread) can run at the same time as om_flush() so we have -// to follow a careful protocol to prevent list corruption. - -void ObjectSynchronizer::om_flush(Thread* self) { - // Process the per-thread in-use list first to be consistent. - int in_use_count = 0; - ObjectMonitor* in_use_list = NULL; - ObjectMonitor* in_use_tail = NULL; - NoSafepointVerifier nsv; - - // This function can race with a list walker or with an async - // deflater thread so we lock the list head to prevent confusion. - // An async deflater thread checks to see if the target thread - // is exiting, but if it has made it past that check before we - // started exiting, then it is racing to get to the in-use list. - if ((in_use_list = get_list_head_locked(&self->om_in_use_list)) != NULL) { - // At this point, we have locked the in-use list head so a racing - // thread cannot come in after us. However, a racing thread could - // be ahead of us; we'll detect that and delay to let it finish. - // - // The thread is going away, however the ObjectMonitors on the - // om_in_use_list may still be in-use by other threads. Link - // them to in_use_tail, which will be linked into the global - // in-use list (om_list_globals._in_use_list) below. - // - // Account for the in-use list head before the loop since it is - // already locked (by this thread): - in_use_tail = in_use_list; - in_use_count++; - for (ObjectMonitor* cur_om = unmarked_next(in_use_list); cur_om != NULL;) { - if (is_locked(cur_om)) { - // cur_om is locked so there must be a racing walker or async - // deflater thread ahead of us so we'll give it a chance to finish. - while (is_locked(cur_om)) { - os::naked_short_sleep(1); - } - // Refetch the possibly changed next field and try again. - cur_om = unmarked_next(in_use_tail); - continue; - } - if (cur_om->object_peek() == NULL) { - // Two reasons for object() to be NULL here: - // 1) cur_om was deflated and the object ref was cleared while it - // was locked. We happened to see it just after it was unlocked - // (and added to the free list). - // 2) The object has been GC'ed so the association with object is - // already broken, but we don't want to do the deflation work now. - - // Refetch the possibly changed next field: - ObjectMonitor* in_use_next = unmarked_next(in_use_tail); - if (cur_om != in_use_next) { - // The NULL is because of async deflation so try again: - cur_om = in_use_next; - continue; - } - // Implied else: The NULL is because of GC, but we leave the - // node on the in-use list to be deflated after it has been - // moved to the global in-use list. - } - in_use_tail = cur_om; - in_use_count++; - cur_om = unmarked_next(cur_om); - } - guarantee(in_use_tail != NULL, "invariant"); -#ifdef ASSERT - int l_om_in_use_count = Atomic::load(&self->om_in_use_count); - assert(l_om_in_use_count == in_use_count, "in-use counts don't match: " - "l_om_in_use_count=%d, in_use_count=%d", l_om_in_use_count, in_use_count); -#endif - Atomic::store(&self->om_in_use_count, 0); - OrderAccess::storestore(); // Make sure counter update is seen first. - // Clear the in-use list head (which also unlocks it): - Atomic::store(&self->om_in_use_list, (ObjectMonitor*)NULL); - om_unlock(in_use_list); - } - - int free_count = 0; - ObjectMonitor* free_list = NULL; - ObjectMonitor* free_tail = NULL; - // This function can race with a list walker thread so we lock the - // list head to prevent confusion. - if ((free_list = get_list_head_locked(&self->om_free_list)) != NULL) { - // At this point, we have locked the free list head so a racing - // thread cannot come in after us. However, a racing thread could - // be ahead of us; we'll detect that and delay to let it finish. - // - // The thread is going away. Set 'free_tail' to the last per-thread free - // monitor which will be linked to om_list_globals._free_list below. - // - // Account for the free list head before the loop since it is - // already locked (by this thread): - free_tail = free_list; - free_count++; - for (ObjectMonitor* s = unmarked_next(free_list); s != NULL; s = unmarked_next(s)) { - if (is_locked(s)) { - // s is locked so there must be a racing walker thread ahead - // of us so we'll give it a chance to finish. - while (is_locked(s)) { - os::naked_short_sleep(1); - } - } - free_tail = s; - free_count++; - guarantee(s->object_peek() == NULL, "invariant"); - if (s->is_busy()) { - stringStream ss; - fatal("must be !is_busy: %s", s->is_busy_to_string(&ss)); - } - } - guarantee(free_tail != NULL, "invariant"); -#ifdef ASSERT - int l_om_free_count = Atomic::load(&self->om_free_count); - assert(l_om_free_count == free_count, "free counts don't match: " - "l_om_free_count=%d, free_count=%d", l_om_free_count, free_count); -#endif - Atomic::store(&self->om_free_count, 0); - OrderAccess::storestore(); // Make sure counter update is seen first. - Atomic::store(&self->om_free_list, (ObjectMonitor*)NULL); - om_unlock(free_list); - } - - if (free_tail != NULL) { - prepend_list_to_global_free_list(free_list, free_tail, free_count); - } - - if (in_use_tail != NULL) { - prepend_list_to_global_in_use_list(in_use_list, in_use_tail, in_use_count); - } - - LogStreamHandle(Debug, monitorinflation) lsh_debug; - LogStreamHandle(Info, monitorinflation) lsh_info; - LogStream* ls = NULL; - if (log_is_enabled(Debug, monitorinflation)) { - ls = &lsh_debug; - } else if ((free_count != 0 || in_use_count != 0) && - log_is_enabled(Info, monitorinflation)) { - ls = &lsh_info; - } - if (ls != NULL) { - ls->print_cr("om_flush: jt=" INTPTR_FORMAT ", free_count=%d" - ", in_use_count=%d" ", om_free_provision=%d", - p2i(self), free_count, in_use_count, self->om_free_provision); - } -} - static void post_monitor_inflate_event(EventJavaMonitorInflate* event, const oop obj, ObjectSynchronizer::InflateCause cause) { @@ -1845,7 +1285,6 @@ void ObjectSynchronizer::inflate_helper(oop obj) { markWord mark = obj->mark(); if (mark.has_monitor()) { ObjectMonitor* monitor = mark.monitor(); - assert(ObjectSynchronizer::verify_objmon_isinpool(monitor), "monitor=" INTPTR_FORMAT " is invalid", p2i(monitor)); markWord dmw = monitor->header(); assert(dmw.is_neutral(), "sanity check: header=" INTPTR_FORMAT, dmw.value()); return; @@ -1877,7 +1316,6 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object, ObjectMonitor* inf = mark.monitor(); markWord dmw = inf->header(); assert(dmw.is_neutral(), "invariant: header=" INTPTR_FORMAT, dmw.value()); - assert(ObjectSynchronizer::verify_objmon_isinpool(inf), "monitor is invalid"); return inf; } @@ -1901,31 +1339,18 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object, // ObjectMonitor into the mark. This was correct, but artificially lengthened // the interval in which INFLATING appeared in the mark, thus increasing // the odds of inflation contention. - // - // We now use per-thread private ObjectMonitor free lists. - // These list are reprovisioned from the global free list outside the - // critical INFLATING...ST interval. A thread can transfer - // multiple ObjectMonitors en-mass from the global free list to its local free list. - // This reduces coherency traffic and lock contention on the global free list. - // Using such local free lists, it doesn't matter if the om_alloc() call appears - // before or after the CAS(INFLATING) operation. - // See the comments in om_alloc(). LogStreamHandle(Trace, monitorinflation) lsh; if (mark.has_locker()) { - ObjectMonitor* m = om_alloc(self); + ObjectMonitor* m = new ObjectMonitor(object); // Optimistically prepare the ObjectMonitor - anticipate successful CAS // We do this before the CAS in order to minimize the length of time // in which INFLATING appears in the mark. - m->Recycle(); - m->_Responsible = NULL; - m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // Consider: maintain by type/class markWord cmp = object->cas_set_mark(markWord::INFLATING(), mark); if (cmp != mark) { - // om_release() will reset the allocation state from New to Free. - om_release(self, m, true); + delete m; continue; // Interference -- just retry } @@ -1972,8 +1397,7 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object, // Note that a thread can inflate an object // that it has stack-locked -- as might happen in wait() -- directly // with CAS. That is, we can avoid the xchg-NULL .... ST idiom. - m->set_owner_from(NULL, DEFLATER_MARKER, mark.locker()); - m->set_object(object); + m->set_owner_from(NULL, mark.locker()); // TODO-FIXME: assert BasicLock->dhw != 0. // Must preserve store ordering. The monitor state must @@ -1984,9 +1408,7 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object, // Once ObjectMonitor is configured and the object is associated // with the ObjectMonitor, it is safe to allow async deflation: - assert(m->is_new(), "freshly allocated monitor must be new"); - // Release semantics needed to keep allocation_state from floating up. - m->release_set_allocation_state(ObjectMonitor::Old); + _in_use_list.add(m); // Hopefully the performance counters are allocated on distinct cache lines // to avoid false sharing on MP systems ... @@ -2015,22 +1437,12 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object, // Catch if the object's header is not neutral (not locked and // not marked is what we care about here). assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value()); - ObjectMonitor* m = om_alloc(self); + ObjectMonitor* m = new ObjectMonitor(object); // prepare m for installation - set monitor to initial state - m->Recycle(); m->set_header(mark); - // DEFLATER_MARKER is the only non-NULL value we should see here. - m->try_set_owner_from(DEFLATER_MARKER, NULL); - m->set_object(object); - m->_Responsible = NULL; - m->_SpinDuration = ObjectMonitor::Knob_SpinLimit; // consider: keep metastats by type/class if (object->cas_set_mark(markWord::encode(m), mark) != mark) { - m->set_header(markWord::zero()); - m->set_object(NULL); - m->Recycle(); - // om_release() will reset the allocation state from New to Free. - om_release(self, m, true); + delete m; m = NULL; continue; // interference - the markword changed - just retry. @@ -2040,10 +1452,7 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object, // Once the ObjectMonitor is configured and object is associated // with the ObjectMonitor, it is safe to allow async deflation: - assert(m->is_new(), "freshly allocated monitor must be new"); - // Release semantics are not needed to keep allocation_state from - // floating up since cas_set_mark() takes care of it. - m->set_allocation_state(ObjectMonitor::Old); + _in_use_list.add(m); // Hopefully the performance counters are allocated on distinct // cache lines to avoid false sharing on MP systems ... @@ -2061,296 +1470,58 @@ ObjectMonitor* ObjectSynchronizer::inflate(Thread* self, oop object, } } - -// An async deflation request is registered with the ServiceThread -// and it is notified. -void ObjectSynchronizer::do_safepoint_work() { - assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); - - log_debug(monitorinflation)("requesting async deflation of idle monitors."); - // Request deflation of idle monitors by the ServiceThread: - set_is_async_deflation_requested(true); - MonitorLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); - ml.notify_all(); - - if (log_is_enabled(Debug, monitorinflation)) { - // The VMThread calls do_final_audit_and_print_stats() which calls - // audit_and_print_stats() at the Info level at VM exit time. - ObjectSynchronizer::audit_and_print_stats(false /* on_exit */); - } -} - -// Deflate the specified ObjectMonitor if not in-use. Returns true if it -// was deflated and false otherwise. -// -// The async deflation protocol sets owner to DEFLATER_MARKER and -// makes contentions negative as signals to contending threads that -// an async deflation is in progress. There are a number of checks -// as part of the protocol to make sure that the calling thread has -// not lost the race to a contending thread. -// -// The ObjectMonitor has been successfully async deflated when: -// (contentions < 0) -// Contending threads that see that condition know to retry their operation. -// -bool ObjectSynchronizer::deflate_monitor(ObjectMonitor* mid, - ObjectMonitor** free_head_p, - ObjectMonitor** free_tail_p) { - // A newly allocated ObjectMonitor should not be seen here so we - // avoid an endless inflate/deflate cycle. - assert(mid->is_old(), "must be old: allocation_state=%d", - (int) mid->allocation_state()); - - if (mid->is_busy()) { - // Easy checks are first - the ObjectMonitor is busy so no deflation. - return false; +void ObjectSynchronizer::chk_for_block_req(JavaThread* self, const char* op_name, + const char* cnt_name, size_t cnt, + LogStream* ls, elapsedTimer* timer_p) { + if (!SafepointMechanism::should_process(self)) { + return; } - const oop obj = mid->object_peek(); - - if (obj == NULL) { - // If the object died, we can recycle the monitor without racing with - // Java threads. The GC already broke the association with the object. - mid->set_owner_from(NULL, DEFLATER_MARKER); - mid->_contentions = -max_jint; - } else { - // Set a NULL owner to DEFLATER_MARKER to force any contending thread - // through the slow path. This is just the first part of the async - // deflation dance. - if (mid->try_set_owner_from(NULL, DEFLATER_MARKER) != NULL) { - // The owner field is no longer NULL so we lost the race since the - // ObjectMonitor is now busy. - return false; - } - - if (mid->contentions() > 0 || mid->_waiters != 0) { - // Another thread has raced to enter the ObjectMonitor after - // mid->is_busy() above or has already entered and waited on - // it which makes it busy so no deflation. Restore owner to - // NULL if it is still DEFLATER_MARKER. - if (mid->try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) { - // Deferred decrement for the JT EnterI() that cancelled the async deflation. - mid->add_to_contentions(-1); - } - return false; - } - - // Make a zero contentions field negative to force any contending threads - // to retry. This is the second part of the async deflation dance. - if (Atomic::cmpxchg(&mid->_contentions, (jint)0, -max_jint) != 0) { - // Contentions was no longer 0 so we lost the race since the - // ObjectMonitor is now busy. Restore owner to NULL if it is - // still DEFLATER_MARKER: - if (mid->try_set_owner_from(DEFLATER_MARKER, NULL) != DEFLATER_MARKER) { - // Deferred decrement for the JT EnterI() that cancelled the async deflation. - mid->add_to_contentions(-1); - } - return false; - } + // A safepoint/handshake has started. + if (ls != NULL) { + timer_p->stop(); + ls->print_cr("pausing %s: %s=" SIZE_FORMAT ", in_use_list stats: ceiling=" + SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, + op_name, cnt_name, cnt, in_use_list_ceiling(), + _in_use_list.count(), _in_use_list.max()); } - // Sanity checks for the races: - guarantee(mid->owner_is_DEFLATER_MARKER(), "must be deflater marker"); - guarantee(mid->contentions() < 0, "must be negative: contentions=%d", - mid->contentions()); - guarantee(mid->_waiters == 0, "must be 0: waiters=%d", mid->_waiters); - guarantee(mid->_cxq == NULL, "must be no contending threads: cxq=" - INTPTR_FORMAT, p2i(mid->_cxq)); - guarantee(mid->_EntryList == NULL, - "must be no entering threads: EntryList=" INTPTR_FORMAT, - p2i(mid->_EntryList)); - - if (obj != NULL) { - if (log_is_enabled(Trace, monitorinflation)) { - ResourceMark rm; - log_trace(monitorinflation)("deflate_monitor: object=" INTPTR_FORMAT - ", mark=" INTPTR_FORMAT ", type='%s'", - p2i(obj), obj->mark().value(), - obj->klass()->external_name()); - } - - // Install the old mark word if nobody else has already done it. - mid->install_displaced_markword_in_object(obj); + { + // Honor block request. + ThreadBlockInVM tbivm(self); } - mid->clear_common(); - assert(mid->object_peek() == NULL, "must be NULL: object=" INTPTR_FORMAT, - p2i(mid->object_peek())); - assert(mid->is_free(), "must be free: allocation_state=%d", - (int)mid->allocation_state()); - - // Move the deflated ObjectMonitor to the working free list - // defined by free_head_p and free_tail_p. - if (*free_head_p == NULL) { - // First one on the list. - *free_head_p = mid; - } - if (*free_tail_p != NULL) { - // We append to the list so the caller can use mid->_next_om - // to fix the linkages in its context. - ObjectMonitor* prevtail = *free_tail_p; - // prevtail should have been cleaned up by the caller: -#ifdef ASSERT - ObjectMonitor* l_next_om = unmarked_next(prevtail); - assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om)); -#endif - om_lock(prevtail); - prevtail->set_next_om(mid); // prevtail now points to mid (and is unlocked) + if (ls != NULL) { + ls->print_cr("resuming %s: in_use_list stats: ceiling=" SIZE_FORMAT + ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, op_name, + in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max()); + timer_p->start(); } - *free_tail_p = mid; - - // At this point, mid->_next_om still refers to its current - // value and another ObjectMonitor's _next_om field still - // refers to this ObjectMonitor. Those linkages have to be - // cleaned up by the caller who has the complete context. - - // We leave owner == DEFLATER_MARKER and contentions < 0 - // to force any racing threads to retry. - return true; // Success, ObjectMonitor has been deflated. } -// Walk a given ObjectMonitor list and deflate idle ObjectMonitors. -// Returns the number of deflated ObjectMonitors. The given -// list could be a per-thread in-use list or the global in-use list. -// If self is a JavaThread and a safepoint has started, then we save state -// via saved_mid_in_use_p and return to the caller to honor the safepoint. -// -int ObjectSynchronizer::deflate_monitor_list(Thread* self, - ObjectMonitor** list_p, - int* count_p, - ObjectMonitor** free_head_p, - ObjectMonitor** free_tail_p, - ObjectMonitor** saved_mid_in_use_p) { - ObjectMonitor* cur_mid_in_use = NULL; - ObjectMonitor* mid = NULL; - ObjectMonitor* next = NULL; - ObjectMonitor* next_next = NULL; - int deflated_count = 0; - NoSafepointVerifier nsv; +// Walk the in-use list and deflate (at most MonitorDeflationMax) idle +// ObjectMonitors. Returns the number of deflated ObjectMonitors. +size_t ObjectSynchronizer::deflate_monitor_list(Thread *self, LogStream* ls, + elapsedTimer* timer_p) { + MonitorList::Iterator iter = _in_use_list.iterator(); + size_t deflated_count = 0; - // We use the more complicated lock-cur_mid_in_use-and-mid-as-we-go - // protocol because om_release() can do list deletions in parallel; - // this also prevents races with a list walker thread. We also - // lock-next-next-as-we-go to prevent an om_flush() that is behind - // this thread from passing us. - if (*saved_mid_in_use_p == NULL) { - // No saved state so start at the beginning. - // Lock the list head so we can possibly deflate it: - if ((mid = get_list_head_locked(list_p)) == NULL) { - return 0; // The list is empty so nothing to deflate. - } - next = unmarked_next(mid); - } else { - // We're restarting after a safepoint so restore the necessary state - // before we resume. - cur_mid_in_use = *saved_mid_in_use_p; - // Lock cur_mid_in_use so we can possibly update its - // next field to extract a deflated ObjectMonitor. - om_lock(cur_mid_in_use); - mid = unmarked_next(cur_mid_in_use); - if (mid == NULL) { - om_unlock(cur_mid_in_use); - *saved_mid_in_use_p = NULL; - return 0; // The remainder is empty so nothing more to deflate. - } - // Lock mid so we can possibly deflate it: - om_lock(mid); - next = unmarked_next(mid); - } - - while (true) { - // The current mid is locked at this point. If we have a - // cur_mid_in_use, then it is also locked at this point. - - if (next != NULL) { - // We lock next so that an om_flush() thread that is behind us - // cannot pass us when we unlock the current mid. - om_lock(next); - next_next = unmarked_next(next); + while (iter.has_next()) { + if (deflated_count >= (size_t)MonitorDeflationMax) { + break; } - - // Only try to deflate if mid is old (is not newly allocated and - // is not newly freed). - if (mid->is_old() && deflate_monitor(mid, free_head_p, free_tail_p)) { - // Deflation succeeded and already updated free_head_p and - // free_tail_p as needed. Finish the move to the local free list - // by unlinking mid from the global or per-thread in-use list. - if (cur_mid_in_use == NULL) { - // mid is the list head and it is locked. Switch the list head - // to next which is also locked (if not NULL) and also leave - // mid locked. Release semantics needed since not all code paths - // in deflate_monitor() ensure memory consistency. - Atomic::release_store(list_p, next); - } else { - ObjectMonitor* locked_next = mark_om_ptr(next); - // mid and cur_mid_in_use are locked. Switch cur_mid_in_use's - // next field to locked_next and also leave mid locked. - // Release semantics needed since not all code paths in - // deflate_monitor() ensure memory consistency. - cur_mid_in_use->release_set_next_om(locked_next); - } - // At this point mid is disconnected from the in-use list so - // its lock longer has any effects on in-use list. + ObjectMonitor* mid = iter.next(); + if (mid->deflate_monitor()) { deflated_count++; - Atomic::dec(count_p); - // mid is current tail in the free_head_p list so NULL terminate - // it (which also unlocks it). No release semantics needed since - // Atomic::dec() already provides it. - mid->set_next_om(NULL); - - // All the list management is done so move on to the next one: - mid = next; // mid keeps non-NULL next's locked state - next = next_next; - } else { - // mid is considered in-use if mid is not old or deflation did not - // succeed. A mid->is_new() node can be seen here when it is freshly - // returned by om_alloc() (and skips the deflation code path). - // A mid->is_old() node can be seen here when deflation failed. - // A mid->is_free() node can be seen here when a fresh node from - // om_alloc() is released by om_release() due to losing the race - // in inflate(). - - // All the list management is done so move on to the next one: - if (cur_mid_in_use != NULL) { - om_unlock(cur_mid_in_use); - } - // The next cur_mid_in_use keeps mid's lock state so - // that it is stable for a possible next field change. It - // cannot be modified by om_release() while it is locked. - cur_mid_in_use = mid; - mid = next; // mid keeps non-NULL next's locked state - next = next_next; - - if (self->is_Java_thread() && - SafepointMechanism::should_process(self->as_Java_thread()) && - // Acquire semantics are not needed on this list load since - // it is not dependent on the following load which does have - // acquire semantics. - cur_mid_in_use != Atomic::load(list_p) && cur_mid_in_use->is_old()) { - // If a safepoint has started and cur_mid_in_use is not the list - // head and is old, then it is safe to use as saved state. Return - // to the caller before blocking. - *saved_mid_in_use_p = cur_mid_in_use; - om_unlock(cur_mid_in_use); - if (mid != NULL) { - om_unlock(mid); - } - return deflated_count; - } - } - if (mid == NULL) { - if (cur_mid_in_use != NULL) { - om_unlock(cur_mid_in_use); - } - break; // Reached end of the list so nothing more to deflate. } - // The current mid's next field is locked at this point. If we have - // a cur_mid_in_use, then it is also locked at this point. + if (self->is_Java_thread()) { + // A JavaThread must check for a safepoint/handshake and honor it. + chk_for_block_req(self->as_Java_thread(), "deflation", "deflated_count", + deflated_count, ls, timer_p); + } } - // We finished the list without a safepoint starting so there's - // no need to save state. - *saved_mid_in_use_p = NULL; + return deflated_count; } @@ -2364,192 +1535,100 @@ class HandshakeForDeflation : public HandshakeClosure { } }; -// This function is called by the ServiceThread to deflate monitors. -// It is also called by do_final_audit_and_print_stats() by the VMThread. -void ObjectSynchronizer::deflate_idle_monitors() { +// This function is called by the MonitorDeflationThread to deflate +// ObjectMonitors. It is also called via do_final_audit_and_print_stats() +// by the VMThread. +size_t ObjectSynchronizer::deflate_idle_monitors() { Thread* self = Thread::current(); - // Deflate any global idle monitors. - deflate_global_idle_monitors(self); - - int count = 0; - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - if (Atomic::load(&jt->om_in_use_count) > 0 && !jt->is_exiting()) { - // This JavaThread is using ObjectMonitors so deflate any that - // are idle unless this JavaThread is exiting; do not race with - // ObjectSynchronizer::om_flush(). - deflate_per_thread_idle_monitors(self, jt); - count++; - } - } - if (count > 0) { - log_debug(monitorinflation)("did async deflation of idle monitors for %d thread(s).", count); - } - - log_info(monitorinflation)("async global_population=%d, global_in_use_count=%d, " - "global_free_count=%d, global_wait_count=%d", - Atomic::load(&om_list_globals._population), - Atomic::load(&om_list_globals._in_use_count), - Atomic::load(&om_list_globals._free_count), - Atomic::load(&om_list_globals._wait_count)); - - GVars.stw_random = os::random(); - if (self->is_Java_thread()) { // The async deflation request has been processed. _last_async_deflation_time_ns = os::javaTimeNanos(); set_is_async_deflation_requested(false); } - if (Atomic::load(&om_list_globals._wait_count) > 0) { - // There are deflated ObjectMonitors waiting for a handshake - // (or a safepoint) for safety. - - ObjectMonitor* list = Atomic::load(&om_list_globals._wait_list); - assert(list != NULL, "om_list_globals._wait_list must not be NULL"); - int count = Atomic::load(&om_list_globals._wait_count); - Atomic::store(&om_list_globals._wait_count, 0); - OrderAccess::storestore(); // Make sure counter update is seen first. - Atomic::store(&om_list_globals._wait_list, (ObjectMonitor*)NULL); - - // Find the tail for prepend_list_to_common(). No need to mark - // ObjectMonitors for this list walk since only the deflater - // thread manages the wait list. -#ifdef ASSERT - int l_count = 0; -#endif - ObjectMonitor* tail = NULL; - for (ObjectMonitor* n = list; n != NULL; n = unmarked_next(n)) { - tail = n; -#ifdef ASSERT - l_count++; -#endif - } - assert(count == l_count, "count=%d != l_count=%d", count, l_count); - - if (self->is_Java_thread()) { - // A JavaThread needs to handshake in order to safely free the - // monitors that were deflated in this cycle. - HandshakeForDeflation hfd_hc; - Handshake::execute(&hfd_hc); - } - - prepend_list_to_common(list, tail, count, &om_list_globals._free_list, - &om_list_globals._free_count); - - log_info(monitorinflation)("moved %d idle monitors from global waiting list to global free list", count); + LogStreamHandle(Debug, monitorinflation) lsh_debug; + LogStreamHandle(Info, monitorinflation) lsh_info; + LogStream* ls = NULL; + if (log_is_enabled(Debug, monitorinflation)) { + ls = &lsh_debug; + } else if (log_is_enabled(Info, monitorinflation)) { + ls = &lsh_info; } -} - -// Deflate global idle ObjectMonitors. -// -void ObjectSynchronizer::deflate_global_idle_monitors(Thread* self) { - deflate_common_idle_monitors(self, true /* is_global */, NULL /* target */); -} - -// Deflate the specified JavaThread's idle ObjectMonitors. -// -void ObjectSynchronizer::deflate_per_thread_idle_monitors(Thread* self, - JavaThread* target) { - deflate_common_idle_monitors(self, false /* !is_global */, target); -} -// Deflate global or per-thread idle ObjectMonitors. -// -void ObjectSynchronizer::deflate_common_idle_monitors(Thread* self, - bool is_global, - JavaThread* target) { - int deflated_count = 0; - ObjectMonitor* free_head_p = NULL; // Local SLL of scavenged ObjectMonitors - ObjectMonitor* free_tail_p = NULL; - ObjectMonitor* saved_mid_in_use_p = NULL; elapsedTimer timer; - - if (log_is_enabled(Info, monitorinflation)) { + if (ls != NULL) { + ls->print_cr("begin deflating: in_use_list stats: ceiling=" SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, + in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max()); timer.start(); } - if (is_global) { - OM_PERFDATA_OP(MonExtant, set_value(Atomic::load(&om_list_globals._in_use_count))); - } else { - OM_PERFDATA_OP(MonExtant, inc(Atomic::load(&target->om_in_use_count))); - } + // Deflate some idle ObjectMonitors. + size_t deflated_count = deflate_monitor_list(self, ls, &timer); + if (deflated_count > 0 || is_final_audit()) { + // There are ObjectMonitors that have been deflated or this is the + // final audit and all the remaining ObjectMonitors have been + // deflated, BUT the MonitorDeflationThread blocked for the final + // safepoint during unlinking. - do { - int local_deflated_count; - if (is_global) { - local_deflated_count = - deflate_monitor_list(self, &om_list_globals._in_use_list, - &om_list_globals._in_use_count, - &free_head_p, &free_tail_p, - &saved_mid_in_use_p); - } else { - local_deflated_count = - deflate_monitor_list(self, &target->om_in_use_list, - &target->om_in_use_count, &free_head_p, - &free_tail_p, &saved_mid_in_use_p); - } - deflated_count += local_deflated_count; - - if (free_head_p != NULL) { - // Move the deflated ObjectMonitors to the global free list. - guarantee(free_tail_p != NULL && local_deflated_count > 0, "free_tail_p=" INTPTR_FORMAT ", local_deflated_count=%d", p2i(free_tail_p), local_deflated_count); - // Note: The target thread can be doing an om_alloc() that - // is trying to prepend an ObjectMonitor on its in-use list - // at the same time that we have deflated the current in-use - // list head and put it on the local free list. prepend_to_common() - // will detect the race and retry which avoids list corruption, - // but the next field in free_tail_p can flicker to marked - // and then unmarked while prepend_to_common() is sorting it - // all out. -#ifdef ASSERT - ObjectMonitor* l_next_om = unmarked_next(free_tail_p); - assert(l_next_om == NULL, "must be NULL: _next_om=" INTPTR_FORMAT, p2i(l_next_om)); -#endif - - prepend_list_to_global_wait_list(free_head_p, free_tail_p, local_deflated_count); + // Unlink deflated ObjectMonitors from the in-use list. + ResourceMark rm; + GrowableArray delete_list((int)deflated_count); + size_t unlinked_count = _in_use_list.unlink_deflated(self, ls, &timer, + &delete_list); + if (self->is_Java_thread()) { + if (ls != NULL) { + timer.stop(); + ls->print_cr("before handshaking: unlinked_count=" SIZE_FORMAT + ", in_use_list stats: ceiling=" SIZE_FORMAT ", count=" + SIZE_FORMAT ", max=" SIZE_FORMAT, + unlinked_count, in_use_list_ceiling(), + _in_use_list.count(), _in_use_list.max()); + } - OM_PERFDATA_OP(Deflations, inc(local_deflated_count)); - } + // A JavaThread needs to handshake in order to safely free the + // ObjectMonitors that were deflated in this cycle. + HandshakeForDeflation hfd_hc; + Handshake::execute(&hfd_hc); - if (saved_mid_in_use_p != NULL) { - // deflate_monitor_list() detected a safepoint starting. - timer.stop(); - { - if (is_global) { - log_debug(monitorinflation)("pausing deflation of global idle monitors for a safepoint."); - } else { - log_debug(monitorinflation)("jt=" INTPTR_FORMAT ": pausing deflation of per-thread idle monitors for a safepoint.", p2i(target)); - } - assert(self->is_Java_thread() && - SafepointMechanism::should_process(self->as_Java_thread()), - "sanity check"); - ThreadBlockInVM blocker(self->as_Java_thread()); - } - // Prepare for another loop after the safepoint. - free_head_p = NULL; - free_tail_p = NULL; - if (log_is_enabled(Info, monitorinflation)) { + if (ls != NULL) { + ls->print_cr("after handshaking: in_use_list stats: ceiling=" + SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, + in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max()); timer.start(); } } - } while (saved_mid_in_use_p != NULL); - timer.stop(); - LogStreamHandle(Debug, monitorinflation) lsh_debug; - LogStreamHandle(Info, monitorinflation) lsh_info; - LogStream* ls = NULL; - if (log_is_enabled(Debug, monitorinflation)) { - ls = &lsh_debug; - } else if (deflated_count != 0 && log_is_enabled(Info, monitorinflation)) { - ls = &lsh_info; + // After the handshake, safely free the ObjectMonitors that were + // deflated in this cycle. + size_t deleted_count = 0; + for (ObjectMonitor* monitor: delete_list) { + delete monitor; + deleted_count++; + + if (self->is_Java_thread()) { + // A JavaThread must check for a safepoint/handshake and honor it. + chk_for_block_req(self->as_Java_thread(), "deletion", "deleted_count", + deleted_count, ls, &timer); + } + } } + if (ls != NULL) { - if (is_global) { - ls->print_cr("async-deflating global idle monitors, %3.7f secs, %d monitors", timer.seconds(), deflated_count); - } else { - ls->print_cr("jt=" INTPTR_FORMAT ": async-deflating per-thread idle monitors, %3.7f secs, %d monitors", p2i(target), timer.seconds(), deflated_count); + timer.stop(); + if (deflated_count != 0 || log_is_enabled(Debug, monitorinflation)) { + ls->print_cr("deflated " SIZE_FORMAT " monitors in %3.7f secs", + deflated_count, timer.seconds()); } + ls->print_cr("end deflating: in_use_list stats: ceiling=" SIZE_FORMAT ", count=" SIZE_FORMAT ", max=" SIZE_FORMAT, + in_use_list_ceiling(), _in_use_list.count(), _in_use_list.max()); } + + OM_PERFDATA_OP(MonExtant, set_value(_in_use_list.count())); + OM_PERFDATA_OP(Deflations, inc(deflated_count)); + + GVars.stw_random = os::random(); + + return deflated_count; } // Monitor cleanup on JavaThread::exit @@ -2627,6 +1706,29 @@ u_char* ObjectSynchronizer::get_gvars_stw_random_addr() { return (u_char*)&GVars.stw_random; } +// Do the final audit and print of ObjectMonitor stats; must be done +// by the VMThread at VM exit time. +void ObjectSynchronizer::do_final_audit_and_print_stats() { + assert(Thread::current()->is_VM_thread(), "sanity check"); + + if (is_final_audit()) { // Only do the audit once. + return; + } + set_is_final_audit(); + + if (log_is_enabled(Info, monitorinflation)) { + // Do a deflation in order to reduce the in-use monitor population + // that is reported by ObjectSynchronizer::log_in_use_monitor_details() + // which is called by ObjectSynchronizer::audit_and_print_stats(). + while (ObjectSynchronizer::deflate_idle_monitors() != 0) { + ; // empty + } + // The other audit_and_print_stats() call is done at the Debug + // level at a safepoint in ObjectSynchronizer::do_safepoint_work(). + ObjectSynchronizer::audit_and_print_stats(true /* on_exit */); + } +} + // This function can be called at a safepoint or it can be called when // we are trying to exit the VM. When we are trying to exit the VM, the // list walker functions can run in parallel with the other list @@ -2653,50 +1755,15 @@ void ObjectSynchronizer::audit_and_print_stats(bool on_exit) { } assert(ls != NULL, "sanity check"); - // Log counts for the global and per-thread monitor lists: - int chk_om_population = log_monitor_list_counts(ls); int error_cnt = 0; - ls->print_cr("Checking global lists:"); - - // Check om_list_globals._population: - if (Atomic::load(&om_list_globals._population) == chk_om_population) { - ls->print_cr("global_population=%d equals chk_om_population=%d", - Atomic::load(&om_list_globals._population), chk_om_population); - } else { - // With fine grained locks on the monitor lists, it is possible for - // log_monitor_list_counts() to return a value that doesn't match - // om_list_globals._population. So far a higher value has been - // seen in testing so something is being double counted by - // log_monitor_list_counts(). - ls->print_cr("WARNING: global_population=%d is not equal to " - "chk_om_population=%d", - Atomic::load(&om_list_globals._population), chk_om_population); - } - - // Check om_list_globals._in_use_list and om_list_globals._in_use_count: - chk_global_in_use_list_and_count(ls, &error_cnt); - - // Check om_list_globals._free_list and om_list_globals._free_count: - chk_global_free_list_and_count(ls, &error_cnt); - - // Check om_list_globals._wait_list and om_list_globals._wait_count: - chk_global_wait_list_and_count(ls, &error_cnt); - - ls->print_cr("Checking per-thread lists:"); - - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - // Check om_in_use_list and om_in_use_count: - chk_per_thread_in_use_list_and_count(jt, ls, &error_cnt); - - // Check om_free_list and om_free_count: - chk_per_thread_free_list_and_count(jt, ls, &error_cnt); - } + ls->print_cr("Checking in_use_list:"); + chk_in_use_list(ls, &error_cnt); if (error_cnt == 0) { - ls->print_cr("No errors found in monitor list checks."); + ls->print_cr("No errors found in in_use_list checks."); } else { - log_error(monitorinflation)("found monitor list errors: error_cnt=%d", error_cnt); + log_error(monitorinflation)("found in_use_list errors: error_cnt=%d", error_cnt); } if ((on_exit && log_is_enabled(Info, monitorinflation)) || @@ -2712,407 +1779,102 @@ void ObjectSynchronizer::audit_and_print_stats(bool on_exit) { guarantee(error_cnt == 0, "ERROR: found monitor list errors: error_cnt=%d", error_cnt); } -// Check a free monitor entry; log any errors. -void ObjectSynchronizer::chk_free_entry(JavaThread* jt, ObjectMonitor* n, - outputStream * out, int *error_cnt_p) { - stringStream ss; - if (n->is_busy()) { - if (jt != NULL) { - out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT - ": free per-thread monitor must not be busy: %s", p2i(jt), - p2i(n), n->is_busy_to_string(&ss)); - } else { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor " - "must not be busy: %s", p2i(n), n->is_busy_to_string(&ss)); - } - *error_cnt_p = *error_cnt_p + 1; - } - if (n->header().value() != 0) { - if (jt != NULL) { - out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT - ": free per-thread monitor must have NULL _header " - "field: _header=" INTPTR_FORMAT, p2i(jt), p2i(n), - n->header().value()); - *error_cnt_p = *error_cnt_p + 1; - } - } - if (n->object_peek() != NULL) { - if (jt != NULL) { - out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT - ": free per-thread monitor must have NULL _object " - "field: _object=" INTPTR_FORMAT, p2i(jt), p2i(n), - p2i(n->object_peek())); - } else { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": free global monitor " - "must have NULL _object field: _object=" INTPTR_FORMAT, - p2i(n), p2i(n->object_peek())); - } - *error_cnt_p = *error_cnt_p + 1; - } -} - -// Lock the next ObjectMonitor for traversal and unlock the current -// ObjectMonitor. Returns the next ObjectMonitor if there is one. -// Otherwise returns NULL (after unlocking the current ObjectMonitor). -// This function is used by the various list walker functions to -// safely walk a list without allowing an ObjectMonitor to be moved -// to another list in the middle of a walk. -static ObjectMonitor* lock_next_for_traversal(ObjectMonitor* cur) { - assert(is_locked(cur), "cur=" INTPTR_FORMAT " must be locked", p2i(cur)); - ObjectMonitor* next = unmarked_next(cur); - if (next == NULL) { // Reached the end of the list. - om_unlock(cur); - return NULL; - } - om_lock(next); // Lock next before unlocking current to keep - om_unlock(cur); // from being by-passed by another thread. - return next; -} +// Check the in_use_list; log the results of the checks. +void ObjectSynchronizer::chk_in_use_list(outputStream* out, int *error_cnt_p) { + size_t l_in_use_count = _in_use_list.count(); + size_t l_in_use_max = _in_use_list.max(); + out->print_cr("count=" SIZE_FORMAT ", max=" SIZE_FORMAT, l_in_use_count, + l_in_use_max); -// Check the global free list and count; log the results of the checks. -void ObjectSynchronizer::chk_global_free_list_and_count(outputStream * out, - int *error_cnt_p) { - int chk_om_free_count = 0; - ObjectMonitor* cur = NULL; - if ((cur = get_list_head_locked(&om_list_globals._free_list)) != NULL) { - // Marked the global free list head so process the list. - while (true) { - chk_free_entry(NULL /* jt */, cur, out, error_cnt_p); - chk_om_free_count++; - - cur = lock_next_for_traversal(cur); - if (cur == NULL) { - break; - } - } + size_t ck_in_use_count = 0; + MonitorList::Iterator iter = _in_use_list.iterator(); + while (iter.has_next()) { + ObjectMonitor* mid = iter.next(); + chk_in_use_entry(mid, out, error_cnt_p); + ck_in_use_count++; } - int l_free_count = Atomic::load(&om_list_globals._free_count); - if (l_free_count == chk_om_free_count) { - out->print_cr("global_free_count=%d equals chk_om_free_count=%d", - l_free_count, chk_om_free_count); - } else { - // With fine grained locks on om_list_globals._free_list, it - // is possible for an ObjectMonitor to be prepended to - // om_list_globals._free_list after we started calculating - // chk_om_free_count so om_list_globals._free_count may not - // match anymore. - out->print_cr("WARNING: global_free_count=%d is not equal to " - "chk_om_free_count=%d", l_free_count, chk_om_free_count); - } -} -// Check the global wait list and count; log the results of the checks. -void ObjectSynchronizer::chk_global_wait_list_and_count(outputStream * out, - int *error_cnt_p) { - int chk_om_wait_count = 0; - ObjectMonitor* cur = NULL; - if ((cur = get_list_head_locked(&om_list_globals._wait_list)) != NULL) { - // Marked the global wait list head so process the list. - while (true) { - // Rules for om_list_globals._wait_list are the same as for - // om_list_globals._free_list: - chk_free_entry(NULL /* jt */, cur, out, error_cnt_p); - chk_om_wait_count++; - - cur = lock_next_for_traversal(cur); - if (cur == NULL) { - break; - } - } - } - if (Atomic::load(&om_list_globals._wait_count) == chk_om_wait_count) { - out->print_cr("global_wait_count=%d equals chk_om_wait_count=%d", - Atomic::load(&om_list_globals._wait_count), chk_om_wait_count); + if (l_in_use_count == ck_in_use_count) { + out->print_cr("in_use_count=" SIZE_FORMAT " equals ck_in_use_count=" + SIZE_FORMAT, l_in_use_count, ck_in_use_count); } else { - out->print_cr("ERROR: global_wait_count=%d is not equal to " - "chk_om_wait_count=%d", - Atomic::load(&om_list_globals._wait_count), chk_om_wait_count); - *error_cnt_p = *error_cnt_p + 1; + out->print_cr("WARNING: in_use_count=" SIZE_FORMAT " is not equal to " + "ck_in_use_count=" SIZE_FORMAT, l_in_use_count, + ck_in_use_count); } -} -// Check the global in-use list and count; log the results of the checks. -void ObjectSynchronizer::chk_global_in_use_list_and_count(outputStream * out, - int *error_cnt_p) { - int chk_om_in_use_count = 0; - ObjectMonitor* cur = NULL; - if ((cur = get_list_head_locked(&om_list_globals._in_use_list)) != NULL) { - // Marked the global in-use list head so process the list. - while (true) { - chk_in_use_entry(NULL /* jt */, cur, out, error_cnt_p); - chk_om_in_use_count++; - - cur = lock_next_for_traversal(cur); - if (cur == NULL) { - break; - } - } - } - int l_in_use_count = Atomic::load(&om_list_globals._in_use_count); - if (l_in_use_count == chk_om_in_use_count) { - out->print_cr("global_in_use_count=%d equals chk_om_in_use_count=%d", - l_in_use_count, chk_om_in_use_count); + size_t ck_in_use_max = _in_use_list.max(); + if (l_in_use_max == ck_in_use_max) { + out->print_cr("in_use_max=" SIZE_FORMAT " equals ck_in_use_max=" + SIZE_FORMAT, l_in_use_max, ck_in_use_max); } else { - // With fine grained locks on the monitor lists, it is possible for - // an exiting JavaThread to put its in-use ObjectMonitors on the - // global in-use list after chk_om_in_use_count is calculated above. - out->print_cr("WARNING: global_in_use_count=%d is not equal to chk_om_in_use_count=%d", - l_in_use_count, chk_om_in_use_count); + out->print_cr("WARNING: in_use_max=" SIZE_FORMAT " is not equal to " + "ck_in_use_max=" SIZE_FORMAT, l_in_use_max, ck_in_use_max); } } // Check an in-use monitor entry; log any errors. -void ObjectSynchronizer::chk_in_use_entry(JavaThread* jt, ObjectMonitor* n, - outputStream * out, int *error_cnt_p) { +void ObjectSynchronizer::chk_in_use_entry(ObjectMonitor* n, outputStream* out, + int* error_cnt_p) { + if (n->owner_is_DEFLATER_MARKER()) { + // This should not happen, but if it does, it is not fatal. + out->print_cr("WARNING: monitor=" INTPTR_FORMAT ": in-use monitor is " + "deflated.", p2i(n)); + return; + } if (n->header().value() == 0) { - if (jt != NULL) { - out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT - ": in-use per-thread monitor must have non-NULL _header " - "field.", p2i(jt), p2i(n)); - } else { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global monitor " - "must have non-NULL _header field.", p2i(n)); - } + out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor must " + "have non-NULL _header field.", p2i(n)); *error_cnt_p = *error_cnt_p + 1; } const oop obj = n->object_peek(); if (obj != NULL) { const markWord mark = obj->mark(); if (!mark.has_monitor()) { - if (jt != NULL) { - out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT - ": in-use per-thread monitor's object does not think " - "it has a monitor: obj=" INTPTR_FORMAT ", mark=" - INTPTR_FORMAT, p2i(jt), p2i(n), p2i(obj), mark.value()); - } else { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global " - "monitor's object does not think it has a monitor: obj=" - INTPTR_FORMAT ", mark=" INTPTR_FORMAT, p2i(n), - p2i(obj), mark.value()); - } + out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " + "object does not think it has a monitor: obj=" + INTPTR_FORMAT ", mark=" INTPTR_FORMAT, p2i(n), + p2i(obj), mark.value()); *error_cnt_p = *error_cnt_p + 1; } ObjectMonitor* const obj_mon = mark.monitor(); if (n != obj_mon) { - if (jt != NULL) { - out->print_cr("ERROR: jt=" INTPTR_FORMAT ", monitor=" INTPTR_FORMAT - ": in-use per-thread monitor's object does not refer " - "to the same monitor: obj=" INTPTR_FORMAT ", mark=" - INTPTR_FORMAT ", obj_mon=" INTPTR_FORMAT, p2i(jt), - p2i(n), p2i(obj), mark.value(), p2i(obj_mon)); - } else { - out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use global " - "monitor's object does not refer to the same monitor: obj=" - INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", obj_mon=" - INTPTR_FORMAT, p2i(n), p2i(obj), mark.value(), p2i(obj_mon)); - } + out->print_cr("ERROR: monitor=" INTPTR_FORMAT ": in-use monitor's " + "object does not refer to the same monitor: obj=" + INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", obj_mon=" + INTPTR_FORMAT, p2i(n), p2i(obj), mark.value(), p2i(obj_mon)); *error_cnt_p = *error_cnt_p + 1; } } } -// Check the thread's free list and count; log the results of the checks. -void ObjectSynchronizer::chk_per_thread_free_list_and_count(JavaThread *jt, - outputStream * out, - int *error_cnt_p) { - int chk_om_free_count = 0; - ObjectMonitor* cur = NULL; - if ((cur = get_list_head_locked(&jt->om_free_list)) != NULL) { - // Marked the per-thread free list head so process the list. - while (true) { - chk_free_entry(jt, cur, out, error_cnt_p); - chk_om_free_count++; - - cur = lock_next_for_traversal(cur); - if (cur == NULL) { - break; - } - } - } - int l_om_free_count = Atomic::load(&jt->om_free_count); - if (l_om_free_count == chk_om_free_count) { - out->print_cr("jt=" INTPTR_FORMAT ": om_free_count=%d equals " - "chk_om_free_count=%d", p2i(jt), l_om_free_count, chk_om_free_count); - } else { - out->print_cr("ERROR: jt=" INTPTR_FORMAT ": om_free_count=%d is not " - "equal to chk_om_free_count=%d", p2i(jt), l_om_free_count, - chk_om_free_count); - *error_cnt_p = *error_cnt_p + 1; - } -} - -// Check the thread's in-use list and count; log the results of the checks. -void ObjectSynchronizer::chk_per_thread_in_use_list_and_count(JavaThread *jt, - outputStream * out, - int *error_cnt_p) { - int chk_om_in_use_count = 0; - ObjectMonitor* cur = NULL; - if ((cur = get_list_head_locked(&jt->om_in_use_list)) != NULL) { - // Marked the per-thread in-use list head so process the list. - while (true) { - chk_in_use_entry(jt, cur, out, error_cnt_p); - chk_om_in_use_count++; - - cur = lock_next_for_traversal(cur); - if (cur == NULL) { - break; - } - } - } - int l_om_in_use_count = Atomic::load(&jt->om_in_use_count); - if (l_om_in_use_count == chk_om_in_use_count) { - out->print_cr("jt=" INTPTR_FORMAT ": om_in_use_count=%d equals " - "chk_om_in_use_count=%d", p2i(jt), l_om_in_use_count, - chk_om_in_use_count); - } else { - out->print_cr("ERROR: jt=" INTPTR_FORMAT ": om_in_use_count=%d is not " - "equal to chk_om_in_use_count=%d", p2i(jt), l_om_in_use_count, - chk_om_in_use_count); - *error_cnt_p = *error_cnt_p + 1; - } -} - -// Do the final audit and print of ObjectMonitor stats; must be done -// by the VMThread (at VM exit time). -void ObjectSynchronizer::do_final_audit_and_print_stats() { - assert(Thread::current()->is_VM_thread(), "sanity check"); - - if (is_final_audit()) { // Only do the audit once. - return; - } - set_is_final_audit(); - - if (log_is_enabled(Info, monitorinflation)) { - // Do a deflation in order to reduce the in-use monitor population - // that is reported by ObjectSynchronizer::log_in_use_monitor_details() - // which is called by ObjectSynchronizer::audit_and_print_stats(). - ObjectSynchronizer::deflate_idle_monitors(); - // The other audit_and_print_stats() call is done at the Debug - // level at a safepoint in ObjectSynchronizer::do_safepoint_work(). - ObjectSynchronizer::audit_and_print_stats(true /* on_exit */); - } -} - -// Log details about ObjectMonitors on the in-use lists. The 'BHL' +// Log details about ObjectMonitors on the in_use_list. The 'BHL' // flags indicate why the entry is in-use, 'object' and 'object type' // indicate the associated object and its type. -void ObjectSynchronizer::log_in_use_monitor_details(outputStream * out) { +void ObjectSynchronizer::log_in_use_monitor_details(outputStream* out) { stringStream ss; - if (Atomic::load(&om_list_globals._in_use_count) > 0) { - out->print_cr("In-use global monitor info:"); + if (_in_use_list.count() > 0) { + out->print_cr("In-use monitor info:"); out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)"); out->print_cr("%18s %s %18s %18s", "monitor", "BHL", "object", "object type"); out->print_cr("================== === ================== =================="); - ObjectMonitor* cur = NULL; - if ((cur = get_list_head_locked(&om_list_globals._in_use_list)) != NULL) { - // Marked the global in-use list head so process the list. - while (true) { - const oop obj = cur->object_peek(); - const markWord mark = cur->header(); - ResourceMark rm; - out->print(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(cur), - cur->is_busy() != 0, mark.hash() != 0, cur->owner() != NULL, - p2i(obj), obj == NULL ? "" : obj->klass()->external_name()); - if (cur->is_busy() != 0) { - out->print(" (%s)", cur->is_busy_to_string(&ss)); - ss.reset(); - } - out->cr(); - - cur = lock_next_for_traversal(cur); - if (cur == NULL) { - break; - } - } - } - } - - out->print_cr("In-use per-thread monitor info:"); - out->print_cr("(B -> is_busy, H -> has hash code, L -> lock status)"); - out->print_cr("%18s %18s %s %18s %18s", - "jt", "monitor", "BHL", "object", "object type"); - out->print_cr("================== ================== === ================== =================="); - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - ObjectMonitor* cur = NULL; - if ((cur = get_list_head_locked(&jt->om_in_use_list)) != NULL) { - // Marked the global in-use list head so process the list. - while (true) { - const oop obj = cur->object_peek(); - const markWord mark = cur->header(); - ResourceMark rm; - out->print(INTPTR_FORMAT " " INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT - " %s", p2i(jt), p2i(cur), cur->is_busy() != 0, - mark.hash() != 0, cur->owner() != NULL, p2i(obj), - obj == NULL ? "" : obj->klass()->external_name()); - if (cur->is_busy() != 0) { - out->print(" (%s)", cur->is_busy_to_string(&ss)); - ss.reset(); - } - out->cr(); - - cur = lock_next_for_traversal(cur); - if (cur == NULL) { - break; - } + MonitorList::Iterator iter = _in_use_list.iterator(); + while (iter.has_next()) { + ObjectMonitor* mid = iter.next(); + const oop obj = mid->object_peek(); + const markWord mark = mid->header(); + ResourceMark rm; + out->print(INTPTR_FORMAT " %d%d%d " INTPTR_FORMAT " %s", p2i(mid), + mid->is_busy() != 0, mark.hash() != 0, mid->owner() != NULL, + p2i(obj), obj == NULL ? "" : obj->klass()->external_name()); + if (mid->is_busy() != 0) { + out->print(" (%s)", mid->is_busy_to_string(&ss)); + ss.reset(); } + out->cr(); } } out->flush(); } - -// Log counts for the global and per-thread monitor lists and return -// the population count. -int ObjectSynchronizer::log_monitor_list_counts(outputStream * out) { - int pop_count = 0; - out->print_cr("%18s %10s %10s %10s %10s", - "Global Lists:", "InUse", "Free", "Wait", "Total"); - out->print_cr("================== ========== ========== ========== =========="); - int l_in_use_count = Atomic::load(&om_list_globals._in_use_count); - int l_free_count = Atomic::load(&om_list_globals._free_count); - int l_wait_count = Atomic::load(&om_list_globals._wait_count); - out->print_cr("%18s %10d %10d %10d %10d", "", l_in_use_count, - l_free_count, l_wait_count, - Atomic::load(&om_list_globals._population)); - pop_count += l_in_use_count + l_free_count + l_wait_count; - - out->print_cr("%18s %10s %10s %10s", - "Per-Thread Lists:", "InUse", "Free", "Provision"); - out->print_cr("================== ========== ========== =========="); - - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { - int l_om_in_use_count = Atomic::load(&jt->om_in_use_count); - int l_om_free_count = Atomic::load(&jt->om_free_count); - out->print_cr(INTPTR_FORMAT " %10d %10d %10d", p2i(jt), - l_om_in_use_count, l_om_free_count, jt->om_free_provision); - pop_count += l_om_in_use_count + l_om_free_count; - } - return pop_count; -} - -#ifndef PRODUCT - -// Check if monitor belongs to the monitor cache -// The list is grow-only so it's *relatively* safe to traverse -// the list of extant blocks without taking a lock. - -int ObjectSynchronizer::verify_objmon_isinpool(ObjectMonitor *monitor) { - PaddedObjectMonitor* block = Atomic::load(&g_block_list); - while (block != NULL) { - assert(block->is_chainmarker(), "must be a block header"); - if (monitor > &block[0] && monitor < &block[_BLOCKSIZE]) { - address mon = (address)monitor; - address blk = (address)block; - size_t diff = mon - blk; - assert((diff % sizeof(PaddedObjectMonitor)) == 0, "must be aligned"); - return 1; - } - // unmarked_next() is not needed with g_block_list (no locking - // used with block linkage _next_om fields). - block = (PaddedObjectMonitor*)block->next_om(); - } - return 0; -} - -#endif diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp index 63426eecd90..526c5eb6484 100644 --- a/src/hotspot/share/runtime/synchronizer.hpp +++ b/src/hotspot/share/runtime/synchronizer.hpp @@ -31,19 +31,13 @@ #include "runtime/handles.hpp" #include "runtime/perfData.hpp" +class LogStream; class ObjectMonitor; class ThreadsList; -#ifndef OM_CACHE_LINE_SIZE -// Use DEFAULT_CACHE_LINE_SIZE if not already specified for -// the current build platform. -#define OM_CACHE_LINE_SIZE DEFAULT_CACHE_LINE_SIZE -#endif - -typedef PaddedEnd PaddedObjectMonitor; - class ObjectSynchronizer : AllStatic { friend class VMStructs; + public: typedef enum { owner_self, @@ -99,12 +93,6 @@ class ObjectSynchronizer : AllStatic { static intx complete_exit(Handle obj, TRAPS); static void reenter (Handle obj, intx recursions, TRAPS); - // thread-specific and global ObjectMonitor free list accessors - static ObjectMonitor* om_alloc(Thread* self); - static void om_release(Thread* self, ObjectMonitor* m, - bool FromPerThreadAlloc); - static void om_flush(Thread* self); - // Inflate light weight monitor to heavy weight monitor static ObjectMonitor* inflate(Thread* self, oop obj, const InflateCause cause); // This version is only for internal use @@ -127,23 +115,18 @@ class ObjectSynchronizer : AllStatic { static void monitors_iterate(MonitorClosure* m); // GC: we current use aggressive monitor deflation policy - // Basically we deflate all monitors that are not busy. - // An adaptive profile-based deflation policy could be used if needed - static void deflate_idle_monitors(); - static void deflate_global_idle_monitors(Thread* self); - static void deflate_per_thread_idle_monitors(Thread* self, - JavaThread* target); - static void deflate_common_idle_monitors(Thread* self, bool is_global, - JavaThread* target); - - // For a given in-use monitor list: global or per-thread, deflate idle - // monitors. - static int deflate_monitor_list(Thread* self, ObjectMonitor** list_p, - int* count_p, ObjectMonitor** free_head_p, - ObjectMonitor** free_tail_p, - ObjectMonitor** saved_mid_in_use_p); - static bool deflate_monitor(ObjectMonitor* mid, ObjectMonitor** free_head_p, - ObjectMonitor** free_tail_p); + // Basically we try to deflate all monitors that are not busy. + static size_t deflate_idle_monitors(); + + // Deflate idle monitors: + static void chk_for_block_req(JavaThread* self, const char* op_name, + const char* cnt_name, size_t cnt, LogStream* ls, + elapsedTimer* timer_p); + static size_t deflate_monitor_list(Thread* self, LogStream* ls, + elapsedTimer* timer_p); + static size_t in_use_list_ceiling(); + static void dec_in_use_list_ceiling(); + static void inc_in_use_list_ceiling(); static bool is_async_deflation_needed(); static bool is_async_deflation_requested() { return _is_async_deflation_requested; } static bool is_final_audit() { return _is_final_audit; } @@ -155,42 +138,19 @@ class ObjectSynchronizer : AllStatic { // debugging static void audit_and_print_stats(bool on_exit); - static void chk_free_entry(JavaThread* jt, ObjectMonitor* n, - outputStream * out, int *error_cnt_p); - static void chk_global_free_list_and_count(outputStream * out, - int *error_cnt_p); - static void chk_global_wait_list_and_count(outputStream * out, - int *error_cnt_p); - static void chk_global_in_use_list_and_count(outputStream * out, - int *error_cnt_p); - static void chk_in_use_entry(JavaThread* jt, ObjectMonitor* n, - outputStream * out, int *error_cnt_p); - static void chk_per_thread_in_use_list_and_count(JavaThread *jt, - outputStream * out, - int *error_cnt_p); - static void chk_per_thread_free_list_and_count(JavaThread *jt, - outputStream * out, - int *error_cnt_p); + static void chk_in_use_list(outputStream* out, int* error_cnt_p); + static void chk_in_use_entry(ObjectMonitor* n, outputStream* out, + int* error_cnt_p); static void do_final_audit_and_print_stats(); - static void log_in_use_monitor_details(outputStream * out); - static int log_monitor_list_counts(outputStream * out); - static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0; - - static void do_safepoint_work(); + static void log_in_use_monitor_details(outputStream* out); private: friend class SynchronizerTest; - enum { _BLOCKSIZE = 128 }; - // global list of blocks of monitors - static PaddedObjectMonitor* g_block_list; static volatile bool _is_async_deflation_requested; static volatile bool _is_final_audit; static jlong _last_async_deflation_time_ns; - // Function to prepend new blocks to the appropriate lists: - static void prepend_block_to_lists(PaddedObjectMonitor* new_blk); - // Support for SynchronizerTest access to GVars fields: static u_char* get_gvars_addr(); static u_char* get_gvars_hc_sequence_addr(); diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 46c6c7e469b..e45d65b499c 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -82,6 +82,7 @@ #include "runtime/jniHandles.inline.hpp" #include "runtime/jniPeriodicChecker.hpp" #include "runtime/memprofiler.hpp" +#include "runtime/monitorDeflationThread.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/objectMonitor.hpp" #include "runtime/orderAccess.hpp" @@ -263,11 +264,6 @@ Thread::Thread() { _current_pending_monitor_is_from_java = true; _current_waiting_monitor = NULL; _current_pending_raw_monitor = NULL; - om_free_list = NULL; - om_free_count = 0; - om_free_provision = 32; - om_in_use_list = NULL; - om_in_use_count = 0; #ifdef ASSERT _visited_for_critical_count = false; @@ -3692,6 +3688,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { // and other cleanups. Needs to start before the compilers start posting events. ServiceThread::initialize(); + // Start the monitor deflation thread: + MonitorDeflationThread::initialize(); + // initialize compiler(s) #if defined(COMPILER1) || COMPILER2_OR_JVMCI #if INCLUDE_JVMCI @@ -4234,6 +4233,9 @@ void Threads::add(JavaThread* p, bool force_daemon) { // Maintain fast thread list ThreadsSMRSupport::add_thread(p); + // Increase the ObjectMonitor ceiling for the new thread. + ObjectSynchronizer::inc_in_use_list_ceiling(); + // Possible GC point. Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p)); @@ -4242,19 +4244,14 @@ void Threads::add(JavaThread* p, bool force_daemon) { } void Threads::remove(JavaThread* p, bool is_daemon) { - - // Reclaim the ObjectMonitors from the om_in_use_list and om_free_list of the moribund thread. - ObjectSynchronizer::om_flush(p); - // Extra scope needed for Thread_lock, so we can check // that we do not remove thread without safepoint code notice { MonitorLocker ml(Threads_lock); - // We must flush any deferred card marks and other various GC barrier - // related buffers (e.g. G1 SATB buffer and G1 dirty card queue buffer) - // before removing a thread from the list of active threads. - // This must be done after ObjectSynchronizer::om_flush(), as GC barriers - // are used in om_flush(). + // BarrierSet state must be destroyed after the last thread transition + // before the thread terminates. Thread transitions result in calls to + // StackWatermarkSet::on_safepoint(), which performs GC processing, + // requiring the GC state to be alive. BarrierSet::barrier_set()->on_thread_detach(p); assert(ThreadsSMRSupport::get_java_thread_list()->includes(p), "p must be present"); @@ -4284,6 +4281,9 @@ void Threads::remove(JavaThread* p, bool is_daemon) { EscapeBarrier::thread_removed(p); } // unlock Threads_lock + // Reduce the ObjectMonitor ceiling for the exiting thread. + ObjectSynchronizer::dec_in_use_list_ceiling(); + // Since Events::log uses a lock, we grab it outside the Threads_lock Events::log(p, "Thread exited: " INTPTR_FORMAT, p2i(p)); } diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 0f5a2b48f6b..db94648c2b5 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -416,14 +416,6 @@ class Thread: public ThreadShadow { // ObjectMonitor on which this thread called Object.wait() ObjectMonitor* _current_waiting_monitor; - // Per-thread ObjectMonitor lists: - public: - ObjectMonitor* om_free_list; // SLL of free ObjectMonitors - int om_free_count; // # on om_free_list - int om_free_provision; // # to try to allocate next - ObjectMonitor* om_in_use_list; // SLL of in-use ObjectMonitors - int om_in_use_count; // # on om_in_use_list - #ifdef ASSERT private: volatile uint64_t _visited_for_critical_count; @@ -486,6 +478,7 @@ class Thread: public ThreadShadow { virtual bool is_Compiler_thread() const { return false; } virtual bool is_Code_cache_sweeper_thread() const { return false; } virtual bool is_service_thread() const { return false; } + virtual bool is_monitor_deflation_thread() const { return false; } virtual bool is_hidden_from_external_view() const { return false; } virtual bool is_jvmti_agent_thread() const { return false; } // True iff the thread can perform GC operations at a safepoint. diff --git a/src/hotspot/share/runtime/timer.cpp b/src/hotspot/share/runtime/timer.cpp index d810f4524db..94a410df6c8 100644 --- a/src/hotspot/share/runtime/timer.cpp +++ b/src/hotspot/share/runtime/timer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,22 +47,6 @@ jlong TimeHelper::micros_to_counter(jlong micros) { return micros * freq; } -elapsedTimer::elapsedTimer(jlong time, jlong timeUnitsPerSecond) { - _active = false; - jlong osTimeUnitsPerSecond = os::elapsed_frequency(); - assert(osTimeUnitsPerSecond % 1000 == 0, "must be"); - assert(timeUnitsPerSecond % 1000 == 0, "must be"); - while (osTimeUnitsPerSecond < timeUnitsPerSecond) { - timeUnitsPerSecond /= 1000; - time *= 1000; - } - while (osTimeUnitsPerSecond > timeUnitsPerSecond) { - timeUnitsPerSecond *= 1000; - time /= 1000; - } - _counter = time; -} - void elapsedTimer::add(elapsedTimer t) { _counter += t._counter; } diff --git a/src/hotspot/share/runtime/timer.hpp b/src/hotspot/share/runtime/timer.hpp index 9e29072a124..5a22d8e2e44 100644 --- a/src/hotspot/share/runtime/timer.hpp +++ b/src/hotspot/share/runtime/timer.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,6 @@ class elapsedTimer { bool _active; public: elapsedTimer() { _active = false; reset(); } - elapsedTimer(jlong time, jlong timeUnitsPerSecond); void add(elapsedTimer t); void start(); void stop(); diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index 226bb4642eb..773069913ef 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -669,7 +669,7 @@ void javaVFrame::print() { } tty->cr(); tty->print("\t "); - monitor->lock()->print_on(tty); + monitor->lock()->print_on(tty, monitor->owner()); tty->cr(); } } diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index b2949d0814f..b2cefee12e9 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -86,6 +86,7 @@ #include "runtime/globals.hpp" #include "runtime/java.hpp" #include "runtime/javaCalls.hpp" +#include "runtime/monitorDeflationThread.hpp" #include "runtime/notificationThread.hpp" #include "runtime/os.hpp" #include "runtime/perfMemory.hpp" @@ -887,7 +888,6 @@ typedef HashtableEntry KlassHashtableEntry; volatile_nonstatic_field(ObjectMonitor, _recursions, intx) \ nonstatic_field(BasicObjectLock, _lock, BasicLock) \ nonstatic_field(BasicObjectLock, _obj, oop) \ - static_field(ObjectSynchronizer, g_block_list, PaddedObjectMonitor*) \ \ /*********************/ \ /* Matcher (C2 only) */ \ @@ -1338,6 +1338,7 @@ typedef HashtableEntry KlassHashtableEntry; declare_type(WatcherThread, NonJavaThread) \ declare_type(JavaThread, Thread) \ declare_type(JvmtiAgentThread, JavaThread) \ + declare_type(MonitorDeflationThread, JavaThread) \ declare_type(ServiceThread, JavaThread) \ declare_type(NotificationThread, JavaThread) \ declare_type(CompilerThread, JavaThread) \ @@ -1462,7 +1463,6 @@ typedef HashtableEntry KlassHashtableEntry; /************/ \ \ declare_toplevel_type(ObjectMonitor) \ - declare_toplevel_type(PaddedObjectMonitor) \ declare_toplevel_type(ObjectSynchronizer) \ declare_toplevel_type(BasicLock) \ declare_toplevel_type(BasicObjectLock) \ @@ -1994,7 +1994,6 @@ typedef HashtableEntry KlassHashtableEntry; declare_toplevel_type(nmethod*) \ COMPILER2_PRESENT(declare_unsigned_integer_type(node_idx_t)) \ declare_toplevel_type(ObjectMonitor*) \ - declare_toplevel_type(PaddedObjectMonitor*) \ declare_toplevel_type(oop*) \ declare_toplevel_type(OopMapCache*) \ declare_toplevel_type(VMReg) \ @@ -2528,12 +2527,6 @@ typedef HashtableEntry KlassHashtableEntry; declare_constant(JNIHandleBlock::block_size_in_oops) \ \ /**********************/ \ - /* ObjectSynchronizer */ \ - /**********************/ \ - \ - declare_constant(ObjectSynchronizer::_BLOCKSIZE) \ - \ - /**********************/ \ /* PcDesc */ \ /**********************/ \ \ diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 9567eabb54d..16e3b8e11c2 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -1420,10 +1420,12 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt // are handled properly. reset_signal_handlers(); } else { - // If UseOsErrorReporting we call this for each level of the call stack +#if defined(_WINDOWS) + // If UseOSErrorReporting we call this for each level of the call stack // while searching for the exception handler. Only the first level needs // to be reported. if (UseOSErrorReporting && log_done) return; +#endif // This is not the first error, see if it happened in a different thread // or in the same thread during error reporting. @@ -1613,7 +1615,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt OnError = NULL; } - if (!UseOSErrorReporting) { + if (WINDOWS_ONLY(!UseOSErrorReporting) NOT_WINDOWS(true)) { // os::abort() will call abort hooks, try it first. static bool skip_os_abort = false; if (!skip_os_abort) { diff --git a/src/hotspot/share/utilities/vmError.hpp b/src/hotspot/share/utilities/vmError.hpp index 172ddb52fb8..84baf8fec62 100644 --- a/src/hotspot/share/utilities/vmError.hpp +++ b/src/hotspot/share/utilities/vmError.hpp @@ -116,9 +116,6 @@ class VMError : public AllStatic { // and the offending address points into CDS store. static void check_failing_cds_access(outputStream* st, const void* siginfo); - static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, - void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7); - // Timeout handling. // Hook functions for platform dependend functionality: static void reporting_started(); @@ -146,6 +143,9 @@ class VMError : public AllStatic { static void print_vm_info(outputStream* st); // main error reporting function + static void report_and_die(Thread* thread, unsigned int sig, address pc, void* siginfo, + void* context, const char* detail_fmt, ...) ATTRIBUTE_PRINTF(6, 7); + static void report_and_die(int id, const char* message, const char* detail_fmt, va_list detail_args, Thread* thread, address pc, void* siginfo, void* context, const char* filename, int lineno, size_t size) ATTRIBUTE_PRINTF(3, 0); diff --git a/src/java.base/share/classes/java/io/DataInputStream.java b/src/java.base/share/classes/java/io/DataInputStream.java index 401a9764c62..b784a5ab50e 100644 --- a/src/java.base/share/classes/java/io/DataInputStream.java +++ b/src/java.base/share/classes/java/io/DataInputStream.java @@ -33,9 +33,10 @@ * way. An application uses a data output stream to write data that * can later be read by a data input stream. *

    - * DataInputStream is not necessarily safe for multithreaded access. - * Thread safety is optional and is the responsibility of users of - * methods in this class. + * A DataInputStream is not safe for use by multiple concurrent + * threads. If a DataInputStream is to be used by more than one + * thread then access to the data input stream should be controlled + * by appropriate synchronization. * * @author Arthur van Hoff * @see java.io.DataOutputStream diff --git a/src/java.base/share/classes/java/io/DataOutputStream.java b/src/java.base/share/classes/java/io/DataOutputStream.java index 4d7d68cfb06..e5c90a257f9 100644 --- a/src/java.base/share/classes/java/io/DataOutputStream.java +++ b/src/java.base/share/classes/java/io/DataOutputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,12 @@ * A data output stream lets an application write primitive Java data * types to an output stream in a portable way. An application can * then use a data input stream to read the data back in. + *

    + * A DataOutputStream is not safe for use by multiple concurrent + * threads. If a DataOutputStream is to be used by more than one + * thread then access to the data output stream should be controlled + * by appropriate synchronization. * - * @author unascribed * @see java.io.DataInputStream * @since 1.0 */ @@ -163,8 +167,9 @@ public final void writeByte(int v) throws IOException { * @see java.io.FilterOutputStream#out */ public final void writeShort(int v) throws IOException { - out.write((v >>> 8) & 0xFF); - out.write((v >>> 0) & 0xFF); + writeBuffer[0] = (byte)(v >>> 8); + writeBuffer[1] = (byte)(v >>> 0); + out.write(writeBuffer, 0, 2); incCount(2); } @@ -178,8 +183,9 @@ public final void writeShort(int v) throws IOException { * @see java.io.FilterOutputStream#out */ public final void writeChar(int v) throws IOException { - out.write((v >>> 8) & 0xFF); - out.write((v >>> 0) & 0xFF); + writeBuffer[0] = (byte)(v >>> 8); + writeBuffer[1] = (byte)(v >>> 0); + out.write(writeBuffer, 0, 2); incCount(2); } @@ -193,10 +199,11 @@ public final void writeChar(int v) throws IOException { * @see java.io.FilterOutputStream#out */ public final void writeInt(int v) throws IOException { - out.write((v >>> 24) & 0xFF); - out.write((v >>> 16) & 0xFF); - out.write((v >>> 8) & 0xFF); - out.write((v >>> 0) & 0xFF); + writeBuffer[0] = (byte)(v >>> 24); + writeBuffer[1] = (byte)(v >>> 16); + writeBuffer[2] = (byte)(v >>> 8); + writeBuffer[3] = (byte)(v >>> 0); + out.write(writeBuffer, 0, 4); incCount(4); } diff --git a/src/java.base/share/classes/java/io/Externalizable.java b/src/java.base/share/classes/java/io/Externalizable.java index 09f21fdf646..84029fc5f3a 100644 --- a/src/java.base/share/classes/java/io/Externalizable.java +++ b/src/java.base/share/classes/java/io/Externalizable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,6 @@ * the writeReplace and readResolve methods documented in the Serializable * interface.
    * - * @author unascribed * @see java.io.ObjectOutputStream * @see java.io.ObjectInputStream * @see java.io.ObjectOutput diff --git a/src/java.base/share/classes/java/io/File.java b/src/java.base/share/classes/java/io/File.java index 553f4ef00c4..ca49cc9d228 100644 --- a/src/java.base/share/classes/java/io/File.java +++ b/src/java.base/share/classes/java/io/File.java @@ -142,7 +142,6 @@ * additional file operations, file attributes, and I/O exceptions to help * diagnose errors when an operation on a file fails. * - * @author unascribed * @since 1.0 */ diff --git a/src/java.base/share/classes/java/io/FileNotFoundException.java b/src/java.base/share/classes/java/io/FileNotFoundException.java index 4bfdd34aff1..8d13aa3fdb9 100644 --- a/src/java.base/share/classes/java/io/FileNotFoundException.java +++ b/src/java.base/share/classes/java/io/FileNotFoundException.java @@ -36,7 +36,6 @@ * constructors if the file does exist but for some reason is inaccessible, for * example when an attempt is made to open a read-only file for writing. * - * @author unascribed * @since 1.0 */ diff --git a/src/java.base/share/classes/java/io/IOException.java b/src/java.base/share/classes/java/io/IOException.java index fd19dce4e19..7a81bd1e621 100644 --- a/src/java.base/share/classes/java/io/IOException.java +++ b/src/java.base/share/classes/java/io/IOException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * class is the general class of exceptions produced by failed or * interrupted I/O operations. * - * @author unascribed * @see java.io.InputStream * @see java.io.OutputStream * @since 1.0 diff --git a/src/java.base/share/classes/java/io/InterruptedIOException.java b/src/java.base/share/classes/java/io/InterruptedIOException.java index 7d3ac73acbc..cdd45a7d981 100644 --- a/src/java.base/share/classes/java/io/InterruptedIOException.java +++ b/src/java.base/share/classes/java/io/InterruptedIOException.java @@ -33,7 +33,6 @@ * indicates how many bytes were successfully transferred before * the interruption occurred. * - * @author unascribed * @see java.io.InputStream * @see java.io.OutputStream * @see java.lang.Thread#interrupt() diff --git a/src/java.base/share/classes/java/io/InvalidClassException.java b/src/java.base/share/classes/java/io/InvalidClassException.java index 71fd5d18c77..6de0e70f760 100644 --- a/src/java.base/share/classes/java/io/InvalidClassException.java +++ b/src/java.base/share/classes/java/io/InvalidClassException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,6 @@ * Specification * * - * @author unascribed * @since 1.1 */ public class InvalidClassException extends ObjectStreamException { diff --git a/src/java.base/share/classes/java/io/InvalidObjectException.java b/src/java.base/share/classes/java/io/InvalidObjectException.java index 01b7ebbb19a..c6e626b238f 100644 --- a/src/java.base/share/classes/java/io/InvalidObjectException.java +++ b/src/java.base/share/classes/java/io/InvalidObjectException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ * @see ObjectInputValidation * @since 1.1 * - * @author unascribed * @since 1.1 */ public class InvalidObjectException extends ObjectStreamException { diff --git a/src/java.base/share/classes/java/io/NotActiveException.java b/src/java.base/share/classes/java/io/NotActiveException.java index 318f9f920e2..3b8b281cbf4 100644 --- a/src/java.base/share/classes/java/io/NotActiveException.java +++ b/src/java.base/share/classes/java/io/NotActiveException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ /** * Thrown when serialization or deserialization is not active. * - * @author unascribed * @since 1.1 */ public class NotActiveException extends ObjectStreamException { diff --git a/src/java.base/share/classes/java/io/NotSerializableException.java b/src/java.base/share/classes/java/io/NotSerializableException.java index 93c48da69c1..d1010188272 100644 --- a/src/java.base/share/classes/java/io/NotSerializableException.java +++ b/src/java.base/share/classes/java/io/NotSerializableException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * The serialization runtime or the class of the instance can throw * this exception. The argument should be the name of the class. * - * @author unascribed * @since 1.1 */ public class NotSerializableException extends ObjectStreamException { diff --git a/src/java.base/share/classes/java/io/ObjectInput.java b/src/java.base/share/classes/java/io/ObjectInput.java index ac1a9b5c542..c4098a2f458 100644 --- a/src/java.base/share/classes/java/io/ObjectInput.java +++ b/src/java.base/share/classes/java/io/ObjectInput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * objects. DataInput includes methods for the input of primitive types, * ObjectInput extends that interface to include objects, arrays, and Strings. * - * @author unascribed * @see java.io.InputStream * @see java.io.ObjectOutputStream * @see java.io.ObjectInputStream diff --git a/src/java.base/share/classes/java/io/ObjectInputValidation.java b/src/java.base/share/classes/java/io/ObjectInputValidation.java index de1d8a53825..e22bf884a27 100644 --- a/src/java.base/share/classes/java/io/ObjectInputValidation.java +++ b/src/java.base/share/classes/java/io/ObjectInputValidation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * Allows an object to be called when a complete graph of objects has * been deserialized. * - * @author unascribed * @see ObjectInputStream * @see ObjectInputStream#registerValidation(java.io.ObjectInputValidation, int) * @since 1.1 diff --git a/src/java.base/share/classes/java/io/ObjectOutput.java b/src/java.base/share/classes/java/io/ObjectOutput.java index b8a8d5c095a..8a825ade99d 100644 --- a/src/java.base/share/classes/java/io/ObjectOutput.java +++ b/src/java.base/share/classes/java/io/ObjectOutput.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * DataOutput includes methods for output of primitive types, ObjectOutput * extends that interface to include objects, arrays, and Strings. * - * @author unascribed * @see java.io.InputStream * @see java.io.ObjectOutputStream * @see java.io.ObjectInputStream diff --git a/src/java.base/share/classes/java/io/ObjectStreamConstants.java b/src/java.base/share/classes/java/io/ObjectStreamConstants.java index 4f7bdf4586e..93c2587034a 100644 --- a/src/java.base/share/classes/java/io/ObjectStreamConstants.java +++ b/src/java.base/share/classes/java/io/ObjectStreamConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ /** * Constants written into the Object Serialization Stream. * - * @author unascribed * @since 1.1 */ public interface ObjectStreamConstants { diff --git a/src/java.base/share/classes/java/io/ObjectStreamException.java b/src/java.base/share/classes/java/io/ObjectStreamException.java index 1e4fb7a46aa..779cc0627d3 100644 --- a/src/java.base/share/classes/java/io/ObjectStreamException.java +++ b/src/java.base/share/classes/java/io/ObjectStreamException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ /** * Superclass of all exceptions specific to Object Stream classes. * - * @author unascribed * @since 1.1 */ public abstract class ObjectStreamException extends IOException { diff --git a/src/java.base/share/classes/java/io/OptionalDataException.java b/src/java.base/share/classes/java/io/OptionalDataException.java index cf1d074a4f4..f98bf079e8e 100644 --- a/src/java.base/share/classes/java/io/OptionalDataException.java +++ b/src/java.base/share/classes/java/io/OptionalDataException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ * is set to 0. * * - * @author unascribed * @since 1.1 */ public class OptionalDataException extends ObjectStreamException { diff --git a/src/java.base/share/classes/java/io/RandomAccessFile.java b/src/java.base/share/classes/java/io/RandomAccessFile.java index d72011f0159..5f6bcfaa6ac 100644 --- a/src/java.base/share/classes/java/io/RandomAccessFile.java +++ b/src/java.base/share/classes/java/io/RandomAccessFile.java @@ -55,7 +55,6 @@ * than {@code EOFException} is thrown. In particular, an * {@code IOException} may be thrown if the stream has been closed. * - * @author unascribed * @since 1.0 */ diff --git a/src/java.base/share/classes/java/io/Serializable.java b/src/java.base/share/classes/java/io/Serializable.java index 0b92cec448a..4686d062108 100644 --- a/src/java.base/share/classes/java/io/Serializable.java +++ b/src/java.base/share/classes/java/io/Serializable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,7 +174,6 @@ * the default computed value, but the requirement for matching * serialVersionUID values is waived for array classes. * - * @author unascribed * @see java.io.ObjectOutputStream * @see java.io.ObjectInputStream * @see java.io.ObjectOutput diff --git a/src/java.base/share/classes/java/io/StreamCorruptedException.java b/src/java.base/share/classes/java/io/StreamCorruptedException.java index 1aa31c1650e..5124c5ce657 100644 --- a/src/java.base/share/classes/java/io/StreamCorruptedException.java +++ b/src/java.base/share/classes/java/io/StreamCorruptedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * Thrown when control information that was read from an object stream * violates internal consistency checks. * - * @author unascribed * @since 1.1 */ public class StreamCorruptedException extends ObjectStreamException { diff --git a/src/java.base/share/classes/java/io/WriteAbortedException.java b/src/java.base/share/classes/java/io/WriteAbortedException.java index a2c86451850..5b82d0999f1 100644 --- a/src/java.base/share/classes/java/io/WriteAbortedException.java +++ b/src/java.base/share/classes/java/io/WriteAbortedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,6 @@ * cause, and may be accessed via the {@link Throwable#getCause()} * method, as well as the aforementioned "legacy field." * - * @author unascribed * @since 1.1 */ public class WriteAbortedException extends ObjectStreamException { diff --git a/src/java.base/share/classes/java/lang/AbstractMethodError.java b/src/java.base/share/classes/java/lang/AbstractMethodError.java index 5c128313c15..a37fa418eae 100644 --- a/src/java.base/share/classes/java/lang/AbstractMethodError.java +++ b/src/java.base/share/classes/java/lang/AbstractMethodError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ * incompatibly changed since the currently executing method was last * compiled. * - * @author unascribed * @since 1.0 */ public class AbstractMethodError extends IncompatibleClassChangeError { diff --git a/src/java.base/share/classes/java/lang/ArithmeticException.java b/src/java.base/share/classes/java/lang/ArithmeticException.java index aa3efbd5053..da74380ad59 100644 --- a/src/java.base/share/classes/java/lang/ArithmeticException.java +++ b/src/java.base/share/classes/java/lang/ArithmeticException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ * Throwable, boolean, boolean) suppression were disabled and/or the * stack trace was not writable}. * - * @author unascribed * @since 1.0 */ public class ArithmeticException extends RuntimeException { diff --git a/src/java.base/share/classes/java/lang/ArrayStoreException.java b/src/java.base/share/classes/java/lang/ArrayStoreException.java index 2fb68bf6386..118c59706ab 100644 --- a/src/java.base/share/classes/java/lang/ArrayStoreException.java +++ b/src/java.base/share/classes/java/lang/ArrayStoreException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ * x[0] = new Integer(0); * * - * @author unascribed * @since 1.0 */ public class ArrayStoreException extends RuntimeException { diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index df1f07c12e3..c82286b25e7 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -186,7 +186,6 @@ * Class}. Use {@code Class} if the class being modeled is * unknown. * - * @author unascribed * @see java.lang.ClassLoader#defineClass(byte[], int, int) * @since 1.0 * @jls 15.8.2 Class Literals diff --git a/src/java.base/share/classes/java/lang/ClassCastException.java b/src/java.base/share/classes/java/lang/ClassCastException.java index 73b00f44741..a436f546953 100644 --- a/src/java.base/share/classes/java/lang/ClassCastException.java +++ b/src/java.base/share/classes/java/lang/ClassCastException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ * System.out.println((String)x); * * - * @author unascribed * @since 1.0 */ public class ClassCastException extends RuntimeException { diff --git a/src/java.base/share/classes/java/lang/ClassCircularityError.java b/src/java.base/share/classes/java/lang/ClassCircularityError.java index afd38cd96fa..52f03f6d792 100644 --- a/src/java.base/share/classes/java/lang/ClassCircularityError.java +++ b/src/java.base/share/classes/java/lang/ClassCircularityError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * Thrown when the Java Virtual Machine detects a circularity in the * superclass hierarchy of a class being loaded. * - * @author unascribed * @since 1.0 */ public class ClassCircularityError extends LinkageError { diff --git a/src/java.base/share/classes/java/lang/ClassFormatError.java b/src/java.base/share/classes/java/lang/ClassFormatError.java index 61145956042..2fdc8d56e5b 100644 --- a/src/java.base/share/classes/java/lang/ClassFormatError.java +++ b/src/java.base/share/classes/java/lang/ClassFormatError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * file and determines that the file is malformed or otherwise cannot * be interpreted as a class file. * - * @author unascribed * @since 1.0 */ public class ClassFormatError extends LinkageError { diff --git a/src/java.base/share/classes/java/lang/ClassNotFoundException.java b/src/java.base/share/classes/java/lang/ClassNotFoundException.java index 2647c947d7d..2a26786a297 100644 --- a/src/java.base/share/classes/java/lang/ClassNotFoundException.java +++ b/src/java.base/share/classes/java/lang/ClassNotFoundException.java @@ -49,7 +49,6 @@ * now known as the cause, and may be accessed via the {@link * Throwable#getCause()} method, as well as the aforementioned "legacy method." * - * @author unascribed * @see java.lang.Class#forName(java.lang.String) * @see java.lang.ClassLoader#findSystemClass(java.lang.String) * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean) diff --git a/src/java.base/share/classes/java/lang/CloneNotSupportedException.java b/src/java.base/share/classes/java/lang/CloneNotSupportedException.java index 58d9731feca..a3fea187bd6 100644 --- a/src/java.base/share/classes/java/lang/CloneNotSupportedException.java +++ b/src/java.base/share/classes/java/lang/CloneNotSupportedException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ * throw this exception to indicate that an object could not or * should not be cloned. * - * @author unascribed * @see java.lang.Cloneable * @see java.lang.Object#clone() * @since 1.0 diff --git a/src/java.base/share/classes/java/lang/Cloneable.java b/src/java.base/share/classes/java/lang/Cloneable.java index 7f65223ce7a..1dfb8176a46 100644 --- a/src/java.base/share/classes/java/lang/Cloneable.java +++ b/src/java.base/share/classes/java/lang/Cloneable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,6 @@ * fact that it implements this interface. Even if the clone method is invoked * reflectively, there is no guarantee that it will succeed. * - * @author unascribed * @see java.lang.CloneNotSupportedException * @see java.lang.Object#clone() * @since 1.0 diff --git a/src/java.base/share/classes/java/lang/IllegalAccessError.java b/src/java.base/share/classes/java/lang/IllegalAccessError.java index 64b8cd40916..8773c1d4e35 100644 --- a/src/java.base/share/classes/java/lang/IllegalAccessError.java +++ b/src/java.base/share/classes/java/lang/IllegalAccessError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ * only occur at run time if the definition of a class has * incompatibly changed. * - * @author unascribed * @since 1.0 */ public class IllegalAccessError extends IncompatibleClassChangeError { diff --git a/src/java.base/share/classes/java/lang/IllegalAccessException.java b/src/java.base/share/classes/java/lang/IllegalAccessException.java index 64b3822bcb3..e2a3a1b2b80 100644 --- a/src/java.base/share/classes/java/lang/IllegalAccessException.java +++ b/src/java.base/share/classes/java/lang/IllegalAccessException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ * executing method does not have access to the definition of * the specified class, field, method or constructor. * - * @author unascribed * @see Class#newInstance() * @see java.lang.reflect.Field#set(Object, Object) * @see java.lang.reflect.Field#setBoolean(Object, boolean) diff --git a/src/java.base/share/classes/java/lang/IllegalArgumentException.java b/src/java.base/share/classes/java/lang/IllegalArgumentException.java index a6e1dd43022..10794ee06de 100644 --- a/src/java.base/share/classes/java/lang/IllegalArgumentException.java +++ b/src/java.base/share/classes/java/lang/IllegalArgumentException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * Thrown to indicate that a method has been passed an illegal or * inappropriate argument. * - * @author unascribed * @since 1.0 */ public class IllegalArgumentException extends RuntimeException { diff --git a/src/java.base/share/classes/java/lang/IllegalMonitorStateException.java b/src/java.base/share/classes/java/lang/IllegalMonitorStateException.java index 12da87d5151..7ff87a8b0aa 100644 --- a/src/java.base/share/classes/java/lang/IllegalMonitorStateException.java +++ b/src/java.base/share/classes/java/lang/IllegalMonitorStateException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * object's monitor or to notify other threads waiting on an object's * monitor without owning the specified monitor. * - * @author unascribed * @see java.lang.Object#notify() * @see java.lang.Object#notifyAll() * @see java.lang.Object#wait() diff --git a/src/java.base/share/classes/java/lang/IllegalThreadStateException.java b/src/java.base/share/classes/java/lang/IllegalThreadStateException.java index 1937a9f8d45..0fae6ef4fb5 100644 --- a/src/java.base/share/classes/java/lang/IllegalThreadStateException.java +++ b/src/java.base/share/classes/java/lang/IllegalThreadStateException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ * {@code suspend} and {@code resume} methods in class * {@code Thread}. * - * @author unascribed * @see java.lang.Thread#resume() * @see java.lang.Thread#suspend() * @since 1.0 diff --git a/src/java.base/share/classes/java/lang/IncompatibleClassChangeError.java b/src/java.base/share/classes/java/lang/IncompatibleClassChangeError.java index fc76a89151b..6468a1a6f24 100644 --- a/src/java.base/share/classes/java/lang/IncompatibleClassChangeError.java +++ b/src/java.base/share/classes/java/lang/IncompatibleClassChangeError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * definition. The definition of some class, on which the currently * executing method depends, has since changed. * - * @author unascribed * @since 1.0 */ public class IncompatibleClassChangeError extends LinkageError { diff --git a/src/java.base/share/classes/java/lang/InstantiationError.java b/src/java.base/share/classes/java/lang/InstantiationError.java index 565447001da..0c06ef409df 100644 --- a/src/java.base/share/classes/java/lang/InstantiationError.java +++ b/src/java.base/share/classes/java/lang/InstantiationError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ * only occur at run time if the definition of a class has * incompatibly changed. * - * @author unascribed * @since 1.0 */ diff --git a/src/java.base/share/classes/java/lang/InstantiationException.java b/src/java.base/share/classes/java/lang/InstantiationException.java index 9c22bd58b09..ed3af1bf30a 100644 --- a/src/java.base/share/classes/java/lang/InstantiationException.java +++ b/src/java.base/share/classes/java/lang/InstantiationException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,6 @@ *

  • the class has no nullary constructor * * - * @author unascribed * @see java.lang.Class#newInstance() * @since 1.0 */ diff --git a/src/java.base/share/classes/java/lang/InternalError.java b/src/java.base/share/classes/java/lang/InternalError.java index f701ed19b05..eda8344523e 100644 --- a/src/java.base/share/classes/java/lang/InternalError.java +++ b/src/java.base/share/classes/java/lang/InternalError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * Thrown to indicate some unexpected internal error has occurred in * the Java Virtual Machine. * - * @author unascribed * @since 1.0 */ public class InternalError extends VirtualMachineError { diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 03834741d12..ff7ceff6cf2 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -99,7 +99,6 @@ * occurs only with a specific minimum or maximum value and * should be checked against the minimum or maximum as appropriate. * - * @author unascribed * @author Joseph D. Darcy * @since 1.0 */ diff --git a/src/java.base/share/classes/java/lang/NegativeArraySizeException.java b/src/java.base/share/classes/java/lang/NegativeArraySizeException.java index 73d7740dfd8..a0f5eba0d80 100644 --- a/src/java.base/share/classes/java/lang/NegativeArraySizeException.java +++ b/src/java.base/share/classes/java/lang/NegativeArraySizeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ /** * Thrown if an application tries to create an array with negative size. * - * @author unascribed * @since 1.0 */ public class NegativeArraySizeException extends RuntimeException { diff --git a/src/java.base/share/classes/java/lang/NoClassDefFoundError.java b/src/java.base/share/classes/java/lang/NoClassDefFoundError.java index 334b03804d9..52387242c82 100644 --- a/src/java.base/share/classes/java/lang/NoClassDefFoundError.java +++ b/src/java.base/share/classes/java/lang/NoClassDefFoundError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ * executing class was compiled, but the definition can no longer be * found. * - * @author unascribed * @since 1.0 */ public class NoClassDefFoundError extends LinkageError { diff --git a/src/java.base/share/classes/java/lang/NoSuchFieldError.java b/src/java.base/share/classes/java/lang/NoSuchFieldError.java index af31a3e2974..2b3a0b25a5c 100644 --- a/src/java.base/share/classes/java/lang/NoSuchFieldError.java +++ b/src/java.base/share/classes/java/lang/NoSuchFieldError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ * only occur at run time if the definition of a class has * incompatibly changed. * - * @author unascribed * @since 1.0 */ public class NoSuchFieldError extends IncompatibleClassChangeError { diff --git a/src/java.base/share/classes/java/lang/NoSuchFieldException.java b/src/java.base/share/classes/java/lang/NoSuchFieldException.java index 759f6c7ab9c..d25ba977c82 100644 --- a/src/java.base/share/classes/java/lang/NoSuchFieldException.java +++ b/src/java.base/share/classes/java/lang/NoSuchFieldException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ /** * Signals that the class doesn't have a field of a specified name. * - * @author unascribed * @since 1.1 */ public class NoSuchFieldException extends ReflectiveOperationException { diff --git a/src/java.base/share/classes/java/lang/NoSuchMethodError.java b/src/java.base/share/classes/java/lang/NoSuchMethodError.java index 1dc7a9ac7f6..9ef207e60e4 100644 --- a/src/java.base/share/classes/java/lang/NoSuchMethodError.java +++ b/src/java.base/share/classes/java/lang/NoSuchMethodError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ * only occur at run time if the definition of a class has * incompatibly changed. * - * @author unascribed * @since 1.0 */ public class NoSuchMethodError extends IncompatibleClassChangeError { diff --git a/src/java.base/share/classes/java/lang/NoSuchMethodException.java b/src/java.base/share/classes/java/lang/NoSuchMethodException.java index abcd687dbbd..3bd0193d186 100644 --- a/src/java.base/share/classes/java/lang/NoSuchMethodException.java +++ b/src/java.base/share/classes/java/lang/NoSuchMethodException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ /** * Thrown when a particular method cannot be found. * - * @author unascribed * @since 1.0 */ public class NoSuchMethodException extends ReflectiveOperationException { diff --git a/src/java.base/share/classes/java/lang/NullPointerException.java b/src/java.base/share/classes/java/lang/NullPointerException.java index ff1fd66e5ab..7258b711b62 100644 --- a/src/java.base/share/classes/java/lang/NullPointerException.java +++ b/src/java.base/share/classes/java/lang/NullPointerException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,6 @@ * Throwable, boolean, boolean) suppression were disabled and/or the * stack trace was not writable}. * - * @author unascribed * @since 1.0 */ public class NullPointerException extends RuntimeException { diff --git a/src/java.base/share/classes/java/lang/NumberFormatException.java b/src/java.base/share/classes/java/lang/NumberFormatException.java index a7d023c1a15..7a317304f6e 100644 --- a/src/java.base/share/classes/java/lang/NumberFormatException.java +++ b/src/java.base/share/classes/java/lang/NumberFormatException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * a string to one of the numeric types, but that the string does not * have the appropriate format. * - * @author unascribed * @see java.lang.Integer#parseInt(String) * @since 1.0 */ diff --git a/src/java.base/share/classes/java/lang/Object.java b/src/java.base/share/classes/java/lang/Object.java index 6f293dc5300..6c1720193b3 100644 --- a/src/java.base/share/classes/java/lang/Object.java +++ b/src/java.base/share/classes/java/lang/Object.java @@ -36,7 +36,6 @@ * Every class has {@code Object} as a superclass. All objects, * including arrays, implement the methods of this class. * - * @author unascribed * @see java.lang.Class * @since 1.0 */ diff --git a/src/java.base/share/classes/java/lang/OutOfMemoryError.java b/src/java.base/share/classes/java/lang/OutOfMemoryError.java index 45cd03facfb..94bf8aea195 100644 --- a/src/java.base/share/classes/java/lang/OutOfMemoryError.java +++ b/src/java.base/share/classes/java/lang/OutOfMemoryError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,6 @@ * boolean, boolean) suppression were disabled and/or the stack trace was not * writable}. * - * @author unascribed * @since 1.0 */ public class OutOfMemoryError extends VirtualMachineError { diff --git a/src/java.base/share/classes/java/lang/Runtime.java b/src/java.base/share/classes/java/lang/Runtime.java index 499624804dd..dae8be95ce6 100644 --- a/src/java.base/share/classes/java/lang/Runtime.java +++ b/src/java.base/share/classes/java/lang/Runtime.java @@ -48,7 +48,6 @@ *

    * An application cannot create its own instance of this class. * - * @author unascribed * @see java.lang.Runtime#getRuntime() * @since 1.0 */ diff --git a/src/java.base/share/classes/java/lang/SecurityException.java b/src/java.base/share/classes/java/lang/SecurityException.java index b704749e815..4e4f966f76a 100644 --- a/src/java.base/share/classes/java/lang/SecurityException.java +++ b/src/java.base/share/classes/java/lang/SecurityException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ /** * Thrown by the security manager to indicate a security violation. * - * @author unascribed * @see java.lang.SecurityManager * @since 1.0 */ diff --git a/src/java.base/share/classes/java/lang/StackOverflowError.java b/src/java.base/share/classes/java/lang/StackOverflowError.java index 95ec9a30d48..45a6af30280 100644 --- a/src/java.base/share/classes/java/lang/StackOverflowError.java +++ b/src/java.base/share/classes/java/lang/StackOverflowError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * Thrown when a stack overflow occurs because an application * recurses too deeply. * - * @author unascribed * @since 1.0 */ public class StackOverflowError extends VirtualMachineError { diff --git a/src/java.base/share/classes/java/lang/StrictMath.java b/src/java.base/share/classes/java/lang/StrictMath.java index d511847d9f6..941834381be 100644 --- a/src/java.base/share/classes/java/lang/StrictMath.java +++ b/src/java.base/share/classes/java/lang/StrictMath.java @@ -74,7 +74,6 @@ * occurs only with a specific minimum or maximum value and * should be checked against the minimum or maximum as appropriate. * - * @author unascribed * @author Joseph D. Darcy * @since 1.3 */ diff --git a/src/java.base/share/classes/java/lang/Thread.java b/src/java.base/share/classes/java/lang/Thread.java index 7692b4179e0..f50b024f9d2 100644 --- a/src/java.base/share/classes/java/lang/Thread.java +++ b/src/java.base/share/classes/java/lang/Thread.java @@ -133,7 +133,6 @@ * or method in this class will cause a {@link NullPointerException} to be * thrown. * - * @author unascribed * @see Runnable * @see Runtime#exit(int) * @see #run() diff --git a/src/java.base/share/classes/java/lang/ThreadGroup.java b/src/java.base/share/classes/java/lang/ThreadGroup.java index c942a038b8b..5252b2c56a5 100644 --- a/src/java.base/share/classes/java/lang/ThreadGroup.java +++ b/src/java.base/share/classes/java/lang/ThreadGroup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,7 +38,6 @@ * group, but not to access information about its thread group's * parent thread group or any other thread groups. * - * @author unascribed * @since 1.0 */ /* The locking strategy for this code is to try to lock only one level of the diff --git a/src/java.base/share/classes/java/lang/Throwable.java b/src/java.base/share/classes/java/lang/Throwable.java index 7bca70ec96e..72948a36485 100644 --- a/src/java.base/share/classes/java/lang/Throwable.java +++ b/src/java.base/share/classes/java/lang/Throwable.java @@ -106,7 +106,6 @@ * {@code String} (the detail message) and a {@code Throwable} (the * cause). * - * @author unascribed * @author Josh Bloch (Added exception chaining and programmatic access to * stack trace in 1.4.) * @jls 11.2 Compile-Time Checking of Exceptions diff --git a/src/java.base/share/classes/java/lang/UnknownError.java b/src/java.base/share/classes/java/lang/UnknownError.java index 3d2bbaaac9d..d6ced29f921 100644 --- a/src/java.base/share/classes/java/lang/UnknownError.java +++ b/src/java.base/share/classes/java/lang/UnknownError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * Thrown when an unknown but serious exception has occurred in the * Java Virtual Machine. * - * @author unascribed * @since 1.0 */ public class UnknownError extends VirtualMachineError { diff --git a/src/java.base/share/classes/java/lang/UnsatisfiedLinkError.java b/src/java.base/share/classes/java/lang/UnsatisfiedLinkError.java index e171bd1ca92..2a6e8596146 100644 --- a/src/java.base/share/classes/java/lang/UnsatisfiedLinkError.java +++ b/src/java.base/share/classes/java/lang/UnsatisfiedLinkError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * Thrown if the Java Virtual Machine cannot find an appropriate * native-language definition of a method declared {@code native}. * - * @author unascribed * @see java.lang.Runtime * @since 1.0 */ diff --git a/src/java.base/share/classes/java/lang/VerifyError.java b/src/java.base/share/classes/java/lang/VerifyError.java index 1e3be9122fb..7409fc6665c 100644 --- a/src/java.base/share/classes/java/lang/VerifyError.java +++ b/src/java.base/share/classes/java/lang/VerifyError.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * though well formed, contains some sort of internal inconsistency * or security problem. * - * @author unascribed * @since 1.0 */ public class VerifyError extends LinkageError { diff --git a/src/java.base/share/classes/java/lang/Void.java b/src/java.base/share/classes/java/lang/Void.java index 581d0d6f488..3ea0e79e61c 100644 --- a/src/java.base/share/classes/java/lang/Void.java +++ b/src/java.base/share/classes/java/lang/Void.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * reference to the {@code Class} object representing the Java keyword * void. * - * @author unascribed * @since 1.1 */ public final diff --git a/src/java.base/share/classes/java/lang/invoke/IndirectVarHandle.java b/src/java.base/share/classes/java/lang/invoke/IndirectVarHandle.java index 85e17a640c8..2ef81c14519 100644 --- a/src/java.base/share/classes/java/lang/invoke/IndirectVarHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/IndirectVarHandle.java @@ -53,7 +53,12 @@ private final Class[] coordinates; IndirectVarHandle(VarHandle target, Class value, Class[] coordinates, BiFunction handleFactory) { - super(new VarForm(value, coordinates)); + this(target, value, coordinates, handleFactory, new VarForm(value, coordinates), false); + } + + private IndirectVarHandle(VarHandle target, Class value, Class[] coordinates, + BiFunction handleFactory, VarForm form, boolean exact) { + super(form, exact); this.handleFactory = handleFactory; this.target = target; this.directTarget = target.asDirect(); @@ -72,8 +77,8 @@ public List> coordinateTypes() { } @Override - MethodType accessModeTypeUncached(AccessMode accessMode) { - return accessMode.at.accessModeType(directTarget.getClass(), value, coordinates); + MethodType accessModeTypeUncached(AccessType at) { + return at.accessModeType(null, value, coordinates); } @Override @@ -90,6 +95,20 @@ VarHandle target() { return target; } + @Override + public VarHandle withInvokeExactBehavior() { + return hasInvokeExactBehavior() + ? this + : new IndirectVarHandle(target, value, coordinates, handleFactory, vform, true); + } + + @Override + public VarHandle withInvokeBehavior() { + return !hasInvokeExactBehavior() + ? this + : new IndirectVarHandle(target, value, coordinates, handleFactory, vform, false); + } + @Override @ForceInline MethodHandle getMethodHandle(int mode) { diff --git a/src/java.base/share/classes/java/lang/invoke/Invokers.java b/src/java.base/share/classes/java/lang/invoke/Invokers.java index 9e44de43337..ee1f9baa3da 100644 --- a/src/java.base/share/classes/java/lang/invoke/Invokers.java +++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java @@ -27,6 +27,7 @@ import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Hidden; import jdk.internal.vm.annotation.Stable; import java.lang.reflect.Array; @@ -463,7 +464,12 @@ private static LambdaForm varHandleMethodInvokerHandleForm(VarHandle.AccessMode @ForceInline /*non-public*/ + @Hidden static MethodHandle checkVarHandleGenericType(VarHandle handle, VarHandle.AccessDescriptor ad) { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } // Test for exact match on invoker types // TODO match with erased types and add cast of return value to lambda form MethodHandle mh = handle.getMethodHandle(ad.mode); diff --git a/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java b/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java index dee289fa157..0176cbf6d47 100644 --- a/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java +++ b/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleBase.java @@ -42,8 +42,8 @@ abstract class MemoryAccessVarHandleBase extends VarHandle { /** alignment constraint (in bytes, expressed as a bit mask) **/ final long alignmentMask; - MemoryAccessVarHandleBase(VarForm form, boolean be, long length, long offset, long alignmentMask) { - super(form); + MemoryAccessVarHandleBase(VarForm form, boolean be, long length, long offset, long alignmentMask, boolean exact) { + super(form, exact); this.be = be; this.length = length; this.offset = offset; diff --git a/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleGenerator.java b/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleGenerator.java index 6e66fc1ab42..addd09f82b7 100644 --- a/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/MemoryAccessVarHandleGenerator.java @@ -71,6 +71,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; import static jdk.internal.org.objectweb.asm.Opcodes.LLOAD; +import static jdk.internal.org.objectweb.asm.Opcodes.NEW; import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY; import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC; @@ -95,6 +96,12 @@ class MemoryAccessVarHandleGenerator { private final static MethodHandle ADD_OFFSETS_HANDLE; private final static MethodHandle MUL_OFFSETS_HANDLE; + private final static MethodType CONSTR_TYPE = MethodType.methodType(void.class, VarForm.class, + boolean.class, long.class, long.class, long.class, boolean.class, long[].class); + // MemoryAccessVarHandleBase + private final static MethodType SUPER_CONTR_TYPE = MethodType.methodType(void.class, VarForm.class, + boolean.class, long.class, long.class, long.class, boolean.class); + static { helperClassCache = new HashMap<>(); helperClassCache.put(byte.class, MemoryAccessVarHandleByteHelper.class); @@ -140,7 +147,7 @@ class MemoryAccessVarHandleGenerator { Arrays.fill(components, long.class); this.form = new VarForm(BASE_CLASS, MemoryAddressProxy.class, carrier, components); this.helperClass = helperClassCache.get(carrier); - this.implClassName = helperClass.getName().replace('.', '/') + dimensions; + this.implClassName = internalName(helperClass) + dimensions; // live constants Class[] intermediate = new Class[dimensions]; Arrays.fill(intermediate, long.class); @@ -164,8 +171,7 @@ MethodHandle generateHandleFactory() { VarForm form = new VarForm(implCls, MemoryAddressProxy.class, carrier, components); - MethodType constrType = MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class, long[].class); - MethodHandle constr = lookup.findConstructor(implCls, constrType); + MethodHandle constr = lookup.findConstructor(implCls, CONSTR_TYPE); constr = MethodHandles.insertArguments(constr, 0, form); return constr; } catch (Throwable ex) { @@ -202,6 +208,9 @@ byte[] generateClassBytes() { addCarrierAccessor(cw); + addAsExact(cw); + addAsGeneric(cw); + for (VarHandle.AccessMode mode : VarHandle.AccessMode.values()) { addAccessModeMethodIfNeeded(mode, cw); } @@ -253,23 +262,23 @@ void addStaticInitializer(ClassWriter cw) { } void addConstructor(ClassWriter cw) { - MethodType constrType = MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class, long[].class); - MethodVisitor mv = cw.visitMethod(0, "", constrType.toMethodDescriptorString(), null, null); + MethodVisitor mv = cw.visitMethod(0, "", CONSTR_TYPE.toMethodDescriptorString(), null, null); mv.visitCode(); //super call mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 1); + mv.visitVarInsn(ALOAD, 1); // vform mv.visitTypeInsn(CHECKCAST, Type.getInternalName(VarForm.class)); - mv.visitVarInsn(ILOAD, 2); - mv.visitVarInsn(LLOAD, 3); - mv.visitVarInsn(LLOAD, 5); - mv.visitVarInsn(LLOAD, 7); + mv.visitVarInsn(ILOAD, 2); // be + mv.visitVarInsn(LLOAD, 3); // length + mv.visitVarInsn(LLOAD, 5); // offset + mv.visitVarInsn(LLOAD, 7); // alignmentMask + mv.visitVarInsn(ILOAD, 9); // exact mv.visitMethodInsn(INVOKESPECIAL, Type.getInternalName(BASE_CLASS), "", - MethodType.methodType(void.class, VarForm.class, boolean.class, long.class, long.class, long.class).toMethodDescriptorString(), false); + SUPER_CONTR_TYPE.toMethodDescriptorString(), false); //init dimensions for (int i = 0 ; i < dimensions ; i++) { mv.visitVarInsn(ALOAD, 0); - mv.visitVarInsn(ALOAD, 9); + mv.visitVarInsn(ALOAD, 10); mv.visitLdcInsn(i); mv.visitInsn(LALOAD); mv.visitFieldInsn(PUTFIELD, implClassName, "dim" + i, "J"); @@ -280,11 +289,10 @@ void addConstructor(ClassWriter cw) { } void addAccessModeTypeMethod(ClassWriter cw) { - MethodType modeMethType = MethodType.methodType(MethodType.class, VarHandle.AccessMode.class); + MethodType modeMethType = MethodType.methodType(MethodType.class, VarHandle.AccessType.class); MethodVisitor mv = cw.visitMethod(ACC_FINAL, "accessModeTypeUncached", modeMethType.toMethodDescriptorString(), null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 1); - mv.visitFieldInsn(GETFIELD, Type.getInternalName(VarHandle.AccessMode.class), "at", VarHandle.AccessType.class.descriptorString()); mv.visitLdcInsn(Type.getType(MemoryAddressProxy.class)); mv.visitTypeInsn(CHECKCAST, Type.getInternalName(Class.class)); mv.visitFieldInsn(GETSTATIC, implClassName, "carrier", Class.class.descriptorString()); @@ -409,6 +417,38 @@ void addCarrierAccessor(ClassWriter cw) { mv.visitEnd(); } + private void addAsExact(ClassWriter cw) { + addAsExactOrAsGeneric(cw, "asExact", true); + } + + private void addAsGeneric(ClassWriter cw) { + addAsExactOrAsGeneric(cw, "asGeneric", false); + } + + private void addAsExactOrAsGeneric(ClassWriter cw, String name, boolean exact) { + MethodVisitor mv = cw.visitMethod(ACC_FINAL, name, "()Ljava/lang/invoke/VarHandle;", null, null); + mv.visitCode(); + mv.visitTypeInsn(NEW, implClassName); + mv.visitInsn(DUP); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, internalName(VarHandle.class), "vform", VarForm.class.descriptorString()); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "be", boolean.class.descriptorString()); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "length", long.class.descriptorString()); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "offset", long.class.descriptorString()); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, internalName(MemoryAccessVarHandleBase.class), "alignmentMask", long.class.descriptorString()); + mv.visitIntInsn(BIPUSH, exact ? 1 : 0); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKEVIRTUAL, implClassName, "strides", "()[J", false); + mv.visitMethodInsn(INVOKESPECIAL, implClassName, "", CONSTR_TYPE.descriptorString(), false); + mv.visitInsn(ARETURN); + mv.visitMaxs(0, 0); + mv.visitEnd(); + } + // shared code generation helpers private static int getSlotsForType(Class c) { @@ -418,6 +458,10 @@ private static int getSlotsForType(Class c) { return 1; } + private static String internalName(Class cls) { + return cls.getName().replace('.', '/'); + } + /** * Emits an actual return instruction conforming to the given return type. */ diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/src/java.base/share/classes/java/lang/invoke/VarHandle.java index 4f7d5a54db0..698eb8374a1 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java @@ -282,8 +282,8 @@ * match fails, it means that the access mode method which the caller is * invoking is not present on the individual VarHandle being invoked. * - *

    - * Invocation of an access mode method behaves as if an invocation of + *

    + * Invocation of an access mode method behaves, by default, as if an invocation of * {@link MethodHandle#invoke}, where the receiving method handle accepts the * VarHandle instance as the leading argument. More specifically, the * following, where {@code {access-mode}} corresponds to the access mode method @@ -318,7 +318,7 @@ * widen primitive values, as if by {@link MethodHandle#asType asType} (see also * {@link MethodHandles#varHandleInvoker}). * - * More concisely, such behaviour is equivalent to: + * More concisely, such behavior is equivalent to: *

     {@code
      * VarHandle vh = ..
      * VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
    @@ -328,6 +328,37 @@
      * }
    * Where, in this case, the method handle is bound to the VarHandle instance. * + *

    + * A VarHandle's invocation behavior can be adjusted (see {@link #withInvokeExactBehavior}) such that invocation of + * an access mode method behaves as if invocation of {@link MethodHandle#invokeExact}, + * where the receiving method handle accepts the VarHandle instance as the leading argument. + * More specifically, the following, where {@code {access-mode}} corresponds to the access mode method + * name: + *

     {@code
    + * VarHandle vh = ..
    + * R r = (R) vh.{access-mode}(p1, p2, ..., pN);
    + * }
    + * behaves as if: + *
     {@code
    + * VarHandle vh = ..
    + * VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
    + * MethodHandle mh = MethodHandles.varHandleExactInvoker(
    + *                       am,
    + *                       vh.accessModeType(am));
    + *
    + * R r = (R) mh.invokeExact(vh, p1, p2, ..., pN)
    + * }
    + * (modulo access mode methods do not declare throwing of {@code Throwable}). + * + * More concisely, such behavior is equivalent to: + *
     {@code
    + * VarHandle vh = ..
    + * VarHandle.AccessMode am = VarHandle.AccessMode.valueFromMethodName("{access-mode}");
    + * MethodHandle mh = vh.toMethodHandle(am);
    + *
    + * R r = (R) mh.invokeExact(p1, p2, ..., pN)
    + * }
    + * Where, in this case, the method handle is bound to the VarHandle instance. * *

    Invocation checking

    * In typical programs, VarHandle access mode type matching will usually @@ -425,7 +456,7 @@ * {@link java.lang.invoke.MethodHandles#varHandleInvoker}. The * {@link java.lang.invoke.MethodHandles.Lookup#findVirtual Lookup.findVirtual} * API is also able to return a method handle to call an access mode method for - * any specified access mode type and is equivalent in behaviour to + * any specified access mode type and is equivalent in behavior to * {@link java.lang.invoke.MethodHandles#varHandleInvoker}. * *

    Interoperation between VarHandles and Java generics

    @@ -446,9 +477,15 @@ */ public abstract class VarHandle implements Constable { final VarForm vform; + final boolean exact; VarHandle(VarForm vform) { + this(vform, false); + } + + VarHandle(VarForm vform, boolean exact) { this.vform = vform; + this.exact = exact; } RuntimeException unsupported() { @@ -465,6 +502,18 @@ VarHandle asDirect() { VarHandle target() { return null; } + /** + * Returns {@code true} if this VarHandle has invoke-exact behavior. + * + * @see #withInvokeExactBehavior() + * @see #withInvokeBehavior() + * @return {@code true} if this VarHandle has invoke-exact behavior. + * @since 16 + */ + public boolean hasInvokeExactBehavior() { + return exact; + } + // Plain accessors /** @@ -1541,6 +1590,44 @@ VarHandle asDirect() { @IntrinsicCandidate Object getAndBitwiseXorRelease(Object... args); + /** + * Returns a VarHandle, with access to the same variable(s) as this VarHandle, but whose + * invocation behavior of access mode methods is adjusted to + * invoke-exact behavior. + *

    + * If this VarHandle already has invoke-exact behavior this VarHandle is returned. + *

    + * Invoking {@link #hasInvokeExactBehavior()} on the returned var handle + * is guaranteed to return {@code true}. + * + * @apiNote + * Invoke-exact behavior guarantees that upon invocation of an access mode method + * the types and arity of the arguments must match the {@link #accessModeType(AccessMode) access mode type}, + * otherwise a {@link WrongMethodTypeException} is thrown. + * + * @see #withInvokeBehavior() + * @see #hasInvokeExactBehavior() + * @return a VarHandle with invoke-exact behavior + * @since 16 + */ + public abstract VarHandle withInvokeExactBehavior(); + + /** + * Returns a VarHandle, with access to the same variable(s) as this VarHandle, but whose + * invocation behavior of access mode methods is adjusted to + * invoke behavior. + *

    + * If this VarHandle already has invoke behavior this VarHandle is returned. + *

    + * Invoking {@link #hasInvokeExactBehavior()} on the returned var handle + * is guaranteed to return {@code false}. + * + * @see #withInvokeExactBehavior() + * @see #hasInvokeExactBehavior() + * @return a VarHandle with invoke behavior + * @since 16 + */ + public abstract VarHandle withInvokeBehavior(); enum AccessType { GET(Object.class), @@ -1859,6 +1946,7 @@ static MemberName getMemberName(int ordinal, VarForm vform) { } static final class AccessDescriptor { + final MethodType symbolicMethodTypeExact; final MethodType symbolicMethodTypeErased; final MethodType symbolicMethodTypeInvoker; final Class returnType; @@ -1866,6 +1954,7 @@ static final class AccessDescriptor { final int mode; public AccessDescriptor(MethodType symbolicMethodType, int type, int mode) { + this.symbolicMethodTypeExact = symbolicMethodType; this.symbolicMethodTypeErased = symbolicMethodType.erase(); this.symbolicMethodTypeInvoker = symbolicMethodType.insertParameterTypes(0, VarHandle.class); this.returnType = symbolicMethodType.returnType(); @@ -1922,15 +2011,25 @@ public List> coordinateTypes() { * @return the access mode type for the given access mode */ public final MethodType accessModeType(AccessMode accessMode) { + return accessModeType(accessMode.at.ordinal()); + } + + @ForceInline + final MethodType accessModeType(int accessTypeOrdinal) { TypesAndInvokers tis = getTypesAndInvokers(); - MethodType mt = tis.methodType_table[accessMode.at.ordinal()]; + MethodType mt = tis.methodType_table[accessTypeOrdinal]; if (mt == null) { - mt = tis.methodType_table[accessMode.at.ordinal()] = - accessModeTypeUncached(accessMode); + mt = tis.methodType_table[accessTypeOrdinal] = + accessModeTypeUncached(accessTypeOrdinal); } return mt; } - abstract MethodType accessModeTypeUncached(AccessMode accessMode); + + final MethodType accessModeTypeUncached(int accessTypeOrdinal) { + return accessModeTypeUncached(AccessType.values()[accessTypeOrdinal]); + } + + abstract MethodType accessModeTypeUncached(AccessType accessMode); /** * Returns {@code true} if the given access mode is supported, otherwise diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java b/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java index 9df0fe1a540..36bf67f0559 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandleGuards.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,18 +25,23 @@ package java.lang.invoke; import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Hidden; // This class is auto-generated by java.lang.invoke.VarHandles$GuardMethodGenerator. Do not edit. final class VarHandleGuards { @ForceInline @LambdaForm.Compiled + @Hidden final static Object guard_L_L(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { Object r = MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); return ad.returnType.cast(r); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -44,14 +49,17 @@ final static Object guard_L_L(VarHandle handle, Object arg0, VarHandle.AccessDes @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LL_V(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -59,49 +67,65 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static Object guard_LL_L(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); + @Hidden + final static boolean guard_LLL_Z(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LLL_Z(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static Object guard_LLL_L(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + return ad.returnType.cast(r); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static Object guard_LLL_L(VarHandle handle, Object arg0, Object arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { + @Hidden + final static Object guard_LL_L(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + Object r = MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); return ad.returnType.cast(r); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled + @Hidden final static int guard_L_I(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (int) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -109,14 +133,17 @@ final static int guard_L_I(VarHandle handle, Object arg0, VarHandle.AccessDescri @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LI_V(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -124,47 +151,63 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static int guard_LI_I(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_LII_Z(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LII_Z(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static int guard_LII_I(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static int guard_LII_I(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static int guard_LI_I(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled + @Hidden final static long guard_L_J(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (long) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -172,14 +215,17 @@ final static long guard_L_J(VarHandle handle, Object arg0, VarHandle.AccessDescr @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LJ_V(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -187,47 +233,63 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static long guard_LJ_J(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_LJJ_Z(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LJJ_Z(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static long guard_LJJ_J(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static long guard_LJJ_J(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static long guard_LJ_J(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled + @Hidden final static float guard_L_F(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (float) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -235,14 +297,17 @@ final static float guard_L_F(VarHandle handle, Object arg0, VarHandle.AccessDesc @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LF_V(VarHandle handle, Object arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -250,47 +315,63 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static float guard_LF_F(VarHandle handle, Object arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_LFF_Z(VarHandle handle, Object arg0, float arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LFF_Z(VarHandle handle, Object arg0, float arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static float guard_LFF_F(VarHandle handle, Object arg0, float arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static float guard_LFF_F(VarHandle handle, Object arg0, float arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static float guard_LF_F(VarHandle handle, Object arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled + @Hidden final static double guard_L_D(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (double) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -298,14 +379,17 @@ final static double guard_L_D(VarHandle handle, Object arg0, VarHandle.AccessDes @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LD_V(VarHandle handle, Object arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -313,48 +397,64 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static double guard_LD_D(VarHandle handle, Object arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_LDD_Z(VarHandle handle, Object arg0, double arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LDD_Z(VarHandle handle, Object arg0, double arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static double guard_LDD_D(VarHandle handle, Object arg0, double arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled - final static double guard_LDD_D(VarHandle handle, Object arg0, double arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static double guard_LD_D(VarHandle handle, Object arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled + @Hidden final static Object guard__L(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { Object r = MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); return ad.returnType.cast(r); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); } @@ -362,14 +462,17 @@ final static Object guard__L(VarHandle handle, VarHandle.AccessDescriptor ad) th @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_L_V(VarHandle handle, Object arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -377,11 +480,15 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled + @Hidden final static boolean guard_LL_Z(VarHandle handle, Object arg0, Object arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -389,11 +496,15 @@ final static boolean guard_LL_Z(VarHandle handle, Object arg0, Object arg1, VarH @ForceInline @LambdaForm.Compiled + @Hidden final static int guard__I(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (int) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); } @@ -401,14 +512,17 @@ final static int guard__I(VarHandle handle, VarHandle.AccessDescriptor ad) throw @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_I_V(VarHandle handle, int arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -416,47 +530,63 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static int guard_I_I(VarHandle handle, int arg0, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_II_Z(VarHandle handle, int arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_II_Z(VarHandle handle, int arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static int guard_II_I(VarHandle handle, int arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled - final static int guard_II_I(VarHandle handle, int arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static int guard_I_I(VarHandle handle, int arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (int) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } } @ForceInline @LambdaForm.Compiled + @Hidden final static long guard__J(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (long) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); } @@ -464,14 +594,17 @@ final static long guard__J(VarHandle handle, VarHandle.AccessDescriptor ad) thro @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_J_V(VarHandle handle, long arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -479,47 +612,63 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static long guard_J_J(VarHandle handle, long arg0, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_JJ_Z(VarHandle handle, long arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_JJ_Z(VarHandle handle, long arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static long guard_JJ_J(VarHandle handle, long arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled - final static long guard_JJ_J(VarHandle handle, long arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static long guard_J_J(VarHandle handle, long arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (long) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } } @ForceInline @LambdaForm.Compiled + @Hidden final static float guard__F(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (float) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); } @@ -527,14 +676,17 @@ final static float guard__F(VarHandle handle, VarHandle.AccessDescriptor ad) thr @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_F_V(VarHandle handle, float arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -542,47 +694,63 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static float guard_F_F(VarHandle handle, float arg0, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_FF_Z(VarHandle handle, float arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_FF_Z(VarHandle handle, float arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static float guard_FF_F(VarHandle handle, float arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled - final static float guard_FF_F(VarHandle handle, float arg0, float arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static float guard_F_F(VarHandle handle, float arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (float) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } } @ForceInline @LambdaForm.Compiled + @Hidden final static double guard__D(VarHandle handle, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (double) MethodHandle.linkToStatic(handle, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect()); } @@ -590,14 +758,17 @@ final static double guard__D(VarHandle handle, VarHandle.AccessDescriptor ad) th @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_D_V(VarHandle handle, double arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } @@ -605,48 +776,64 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static double guard_D_D(VarHandle handle, double arg0, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_DD_Z(VarHandle handle, double arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_DD_Z(VarHandle handle, double arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static double guard_DD_D(VarHandle handle, double arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } } @ForceInline @LambdaForm.Compiled - final static double guard_DD_D(VarHandle handle, double arg0, double arg1, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); + @Hidden + final static double guard_D_D(VarHandle handle, double arg0, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (double) MethodHandle.linkToStatic(handle, arg0, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); + return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0); } } @ForceInline @LambdaForm.Compiled + @Hidden final static Object guard_LI_L(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { Object r = MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); return ad.returnType.cast(r); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -654,14 +841,17 @@ final static Object guard_LI_L(VarHandle handle, Object arg0, int arg1, VarHandl @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LIL_V(VarHandle handle, Object arg0, int arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } @@ -669,52 +859,67 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static Object guard_LIL_L(VarHandle handle, Object arg0, int arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - return ad.returnType.cast(r); + @Hidden + final static boolean guard_LILL_Z(VarHandle handle, Object arg0, int arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LILL_Z(VarHandle handle, Object arg0, int arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + @Hidden + final static Object guard_LILL_L(VarHandle handle, Object arg0, int arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + return ad.returnType.cast(r); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static Object guard_LILL_L(VarHandle handle, Object arg0, int arg1, Object arg2, Object arg3, VarHandle.AccessDescriptor ad) throws Throwable { + @Hidden + final static Object guard_LIL_L(VarHandle handle, Object arg0, int arg1, Object arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + Object r = MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); return ad.returnType.cast(r); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LII_V(VarHandle handle, Object arg0, int arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } @@ -722,11 +927,15 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled + @Hidden final static boolean guard_LIII_Z(VarHandle handle, Object arg0, int arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } @@ -734,11 +943,15 @@ final static boolean guard_LIII_Z(VarHandle handle, Object arg0, int arg1, int a @ForceInline @LambdaForm.Compiled + @Hidden final static int guard_LIII_I(VarHandle handle, Object arg0, int arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } @@ -746,11 +959,15 @@ final static int guard_LIII_I(VarHandle handle, Object arg0, int arg1, int arg2, @ForceInline @LambdaForm.Compiled + @Hidden final static long guard_LI_J(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (long) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -758,14 +975,17 @@ final static long guard_LI_J(VarHandle handle, Object arg0, int arg1, VarHandle. @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LIJ_V(VarHandle handle, Object arg0, int arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } @@ -773,47 +993,63 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static long guard_LIJ_J(VarHandle handle, Object arg0, int arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_LIJJ_Z(VarHandle handle, Object arg0, int arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LIJJ_Z(VarHandle handle, Object arg0, int arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + @Hidden + final static long guard_LIJJ_J(VarHandle handle, Object arg0, int arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static long guard_LIJJ_J(VarHandle handle, Object arg0, int arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + @Hidden + final static long guard_LIJ_J(VarHandle handle, Object arg0, int arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled + @Hidden final static float guard_LI_F(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (float) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -821,14 +1057,17 @@ final static float guard_LI_F(VarHandle handle, Object arg0, int arg1, VarHandle @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LIF_V(VarHandle handle, Object arg0, int arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } @@ -836,47 +1075,63 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static float guard_LIF_F(VarHandle handle, Object arg0, int arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_LIFF_Z(VarHandle handle, Object arg0, int arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LIFF_Z(VarHandle handle, Object arg0, int arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + @Hidden + final static float guard_LIFF_F(VarHandle handle, Object arg0, int arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static float guard_LIFF_F(VarHandle handle, Object arg0, int arg1, float arg2, float arg3, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + @Hidden + final static float guard_LIF_F(VarHandle handle, Object arg0, int arg1, float arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (float) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return (float) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled + @Hidden final static double guard_LI_D(VarHandle handle, Object arg0, int arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (double) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -884,14 +1139,17 @@ final static double guard_LI_D(VarHandle handle, Object arg0, int arg1, VarHandl @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LID_V(VarHandle handle, Object arg0, int arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } @@ -899,47 +1157,63 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static double guard_LID_D(VarHandle handle, Object arg0, int arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_LIDD_Z(VarHandle handle, Object arg0, int arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LIDD_Z(VarHandle handle, Object arg0, int arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + @Hidden + final static double guard_LIDD_D(VarHandle handle, Object arg0, int arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static double guard_LIDD_D(VarHandle handle, Object arg0, int arg1, double arg2, double arg3, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + @Hidden + final static double guard_LID_D(VarHandle handle, Object arg0, int arg1, double arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (double) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return (double) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled + @Hidden final static int guard_LJ_I(VarHandle handle, Object arg0, long arg1, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (int) MethodHandle.linkToStatic(handle, arg0, arg1, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1); } @@ -947,14 +1221,17 @@ final static int guard_LJ_I(VarHandle handle, Object arg0, long arg1, VarHandle. @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LJI_V(VarHandle handle, Object arg0, long arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } @@ -962,50 +1239,65 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled - final static int guard_LJI_I(VarHandle handle, Object arg0, long arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + @Hidden + final static boolean guard_LJII_Z(VarHandle handle, Object arg0, long arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); + return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static boolean guard_LJII_Z(VarHandle handle, Object arg0, long arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + @Hidden + final static int guard_LJII_I(VarHandle handle, Object arg0, long arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } } @ForceInline @LambdaForm.Compiled - final static int guard_LJII_I(VarHandle handle, Object arg0, long arg1, int arg2, int arg3, VarHandle.AccessDescriptor ad) throws Throwable { - if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { - return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); + @Hidden + final static int guard_LJI_I(VarHandle handle, Object arg0, long arg1, int arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); } - else { + if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { + return (int) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); - return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); + return (int) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } } @ForceInline @LambdaForm.Compiled + @Hidden final static void guard_LJJ_V(VarHandle handle, Object arg0, long arg1, long arg2, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { + } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { MethodHandle.linkToStatic(handle, arg0, arg1, arg2, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2); } @@ -1013,11 +1305,15 @@ else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbol @ForceInline @LambdaForm.Compiled + @Hidden final static boolean guard_LJJJ_Z(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (boolean) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (boolean) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } @@ -1025,11 +1321,15 @@ final static boolean guard_LJJJ_Z(VarHandle handle, Object arg0, long arg1, long @ForceInline @LambdaForm.Compiled + @Hidden final static long guard_LJJJ_J(VarHandle handle, Object arg0, long arg1, long arg2, long arg3, VarHandle.AccessDescriptor ad) throws Throwable { + if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { + throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " + + ad.symbolicMethodTypeExact); + } if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { return (long) MethodHandle.linkToStatic(handle, arg0, arg1, arg2, arg3, handle.vform.getMemberName(ad.mode)); - } - else { + } else { MethodHandle mh = handle.getMethodHandle(ad.mode); return (long) mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(handle.asDirect(), arg0, arg1, arg2, arg3); } diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandles.java b/src/java.base/share/classes/java/lang/invoke/VarHandles.java index 0a169951752..db2e0f7f886 100644 --- a/src/java.base/share/classes/java/lang/invoke/VarHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/VarHandles.java @@ -31,8 +31,10 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.lang.reflect.Parameter; import java.nio.ByteOrder; import java.util.ArrayList; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -43,6 +45,8 @@ import static java.lang.invoke.MethodHandleStatics.UNSAFE; import static java.lang.invoke.MethodHandleStatics.VAR_HANDLE_IDENTITY_ADAPT; import static java.lang.invoke.MethodHandleStatics.newIllegalArgumentException; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; final class VarHandles { @@ -349,7 +353,8 @@ static VarHandle makeMemoryAddressViewHandle(Class carrier, long alignmentMas .generateHandleFactory()); try { - return maybeAdapt((VarHandle)fac.invoke(be, size, offset, alignmentMask, strides)); + boolean exact = false; + return maybeAdapt((VarHandle)fac.invoke(be, size, offset, alignmentMask, exact, strides)); } catch (Throwable ex) { throw new IllegalStateException(ex); } @@ -359,7 +364,7 @@ private static VarHandle maybeAdapt(VarHandle target) { if (!VAR_HANDLE_IDENTITY_ADAPT) return target; target = filterValue(target, MethodHandles.identity(target.varType()), MethodHandles.identity(target.varType())); - MethodType mtype = target.accessModeType(VarHandle.AccessMode.GET).dropParameterTypes(0, 1); + MethodType mtype = target.accessModeType(VarHandle.AccessMode.GET); for (int i = 0 ; i < mtype.parameterCount() ; i++) { target = filterCoordinates(target, i, MethodHandles.identity(mtype.parameterType(i))); } @@ -689,33 +694,42 @@ private static boolean isCheckedException(Class clazz) { // static final String GUARD_METHOD_SIG_TEMPLATE = " _()"; // // static final String GUARD_METHOD_TEMPLATE = -// "@ForceInline\n" + -// "@LambdaForm.Compiled\n" + -// "final static throws Throwable {\n" + -// " if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodType) {\n" + -// " MethodHandle.linkToStatic();\n" + -// " }\n" + -// " else {\n" + -// " MethodHandle mh = handle.getMethodHandle(ad.mode);\n" + -// " mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic();\n" + -// " }\n" + -// "}"; +// """ +// @ForceInline +// @LambdaForm.Compiled +// @Hidden +// final static throws Throwable { +// if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { +// throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " +// + ad.symbolicMethodTypeExact); +// } +// if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { +// MethodHandle.linkToStatic(); +// } else { +// MethodHandle mh = handle.getMethodHandle(ad.mode); +// mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); +// } +// }"""; // // static final String GUARD_METHOD_TEMPLATE_V = -// "@ForceInline\n" + -// "@LambdaForm.Compiled\n" + -// "final static throws Throwable {\n" + -// " if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodType) {\n" + -// " MethodHandle.linkToStatic();\n" + -// " }\n" + -// " else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodType) {\n" + -// " MethodHandle.linkToStatic();\n" + -// " }\n" + -// " else {\n" + -// " MethodHandle mh = handle.getMethodHandle(ad.mode);\n" + -// " mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic();\n" + -// " }\n" + -// "}"; +// """ +// @ForceInline +// @LambdaForm.Compiled +// @Hidden +// final static throws Throwable { +// if (handle.hasInvokeExactBehavior() && handle.accessModeType(ad.type) != ad.symbolicMethodTypeExact) { +// throw new WrongMethodTypeException("expected " + handle.accessModeType(ad.type) + " but found " +// + ad.symbolicMethodTypeExact); +// } +// if (handle.isDirect() && handle.vform.methodType_table[ad.type] == ad.symbolicMethodTypeErased) { +// MethodHandle.linkToStatic(); +// } else if (handle.isDirect() && handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodTypeErased) { +// MethodHandle.linkToStatic(); +// } else { +// MethodHandle mh = handle.getMethodHandle(ad.mode); +// mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(); +// } +// }"""; // // // A template for deriving the operations // // could be supported by annotating VarHandle directly with the @@ -751,6 +765,7 @@ private static boolean isCheckedException(Class clazz) { // System.out.println("package java.lang.invoke;"); // System.out.println(); // System.out.println("import jdk.internal.vm.annotation.ForceInline;"); +// System.out.println("import jdk.internal.vm.annotation.Hidden;"); // System.out.println(); // System.out.println("// This class is auto-generated by " + // GuardMethodGenerator.class.getName() + @@ -803,11 +818,8 @@ private static boolean isCheckedException(Class clazz) { // hts.flatMap(ht -> Stream.of(VarHandleTemplate.class.getMethods()). // map(m -> generateMethodType(m, ht.receiver, ht.value, ht.intermediates))). // distinct(). -// map(mt -> generateMethod(mt)). -// forEach(s -> { -// System.out.println(s); -// System.out.println(); -// }); +// map(GuardMethodGenerator::generateMethod). +// forEach(System.out::println); // // System.out.println("}"); // } @@ -863,6 +875,7 @@ private static boolean isCheckedException(Class clazz) { // // List LINK_TO_INVOKER_ARGS = params.keySet().stream(). // collect(toList()); +// LINK_TO_INVOKER_ARGS.set(0, LINK_TO_INVOKER_ARGS.get(0) + ".asDirect()"); // // RETURN = returnType == void.class // ? "" @@ -878,7 +891,7 @@ private static boolean isCheckedException(Class clazz) { // // String RETURN_ERASED = returnType != Object.class // ? "" -// : " return ad.returnType.cast(r);"; +// : "\n return ad.returnType.cast(r);"; // // String template = returnType == void.class // ? GUARD_METHOD_TEMPLATE_V @@ -895,7 +908,7 @@ private static boolean isCheckedException(Class clazz) { // collect(joining(", "))). // replace("", LINK_TO_INVOKER_ARGS.stream(). // collect(joining(", "))) -// ; +// .indent(4); // } // // static String className(Class c) { diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template index ef6c0257247..0e1a998d620 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template @@ -45,12 +45,12 @@ final class VarHandle$Type$s { #end[Object] FieldInstanceReadOnly(Class receiverType, long fieldOffset{#if[Object]?, Class fieldType}) { - this(receiverType, fieldOffset{#if[Object]?, fieldType}, FieldInstanceReadOnly.FORM); + this(receiverType, fieldOffset{#if[Object]?, fieldType}, FieldInstanceReadOnly.FORM, false); } protected FieldInstanceReadOnly(Class receiverType, long fieldOffset{#if[Object]?, Class fieldType}, - VarForm form) { - super(form); + VarForm form, boolean exact) { + super(form, exact); this.fieldOffset = fieldOffset; this.receiverType = receiverType; #if[Object] @@ -59,8 +59,22 @@ final class VarHandle$Type$s { } @Override - final MethodType accessModeTypeUncached(AccessMode accessMode) { - return accessMode.at.accessModeType(receiverType, {#if[Object]?fieldType:$type$.class}); + public FieldInstanceReadOnly withInvokeExactBehavior() { + return hasInvokeExactBehavior() + ? this + : new FieldInstanceReadOnly(receiverType, fieldOffset{#if[Object]?, fieldType}, vform, true); + } + + @Override + public FieldInstanceReadOnly withInvokeBehavior() { + return !hasInvokeExactBehavior() + ? this + : new FieldInstanceReadOnly(receiverType, fieldOffset{#if[Object]?, fieldType}, vform, false); + } + + @Override + final MethodType accessModeTypeUncached(AccessType at) { + return at.accessModeType(receiverType, {#if[Object]?fieldType:$type$.class}); } @Override @@ -109,7 +123,26 @@ final class VarHandle$Type$s { static final class FieldInstanceReadWrite extends FieldInstanceReadOnly { FieldInstanceReadWrite(Class receiverType, long fieldOffset{#if[Object]?, Class fieldType}) { - super(receiverType, fieldOffset{#if[Object]?, fieldType}, FieldInstanceReadWrite.FORM); + this(receiverType, fieldOffset{#if[Object]?, fieldType}, false); + } + + private FieldInstanceReadWrite(Class receiverType, long fieldOffset{#if[Object]?, Class fieldType}, + boolean exact) { + super(receiverType, fieldOffset{#if[Object]?, fieldType}, FieldInstanceReadWrite.FORM, exact); + } + + @Override + public FieldInstanceReadWrite withInvokeExactBehavior() { + return hasInvokeExactBehavior() + ? this + : new FieldInstanceReadWrite(receiverType, fieldOffset{#if[Object]?, fieldType}, true); + } + + @Override + public FieldInstanceReadWrite withInvokeBehavior() { + return !hasInvokeExactBehavior() + ? this + : new FieldInstanceReadWrite(receiverType, fieldOffset{#if[Object]?, fieldType}, false); } #if[Object] @@ -364,12 +397,12 @@ final class VarHandle$Type$s { #end[Object] FieldStaticReadOnly(Object base, long fieldOffset{#if[Object]?, Class fieldType}) { - this(base, fieldOffset{#if[Object]?, fieldType}, FieldStaticReadOnly.FORM); + this(base, fieldOffset{#if[Object]?, fieldType}, FieldStaticReadOnly.FORM, false); } protected FieldStaticReadOnly(Object base, long fieldOffset{#if[Object]?, Class fieldType}, - VarForm form) { - super(form); + VarForm form, boolean exact) { + super(form, exact); this.base = base; this.fieldOffset = fieldOffset; #if[Object] @@ -377,6 +410,20 @@ final class VarHandle$Type$s { #end[Object] } + @Override + public FieldStaticReadOnly withInvokeExactBehavior() { + return hasInvokeExactBehavior() + ? this + : new FieldStaticReadOnly(base, fieldOffset{#if[Object]?, fieldType}, vform, true); + } + + @Override + public FieldStaticReadOnly withInvokeBehavior() { + return !hasInvokeExactBehavior() + ? this + : new FieldStaticReadOnly(base, fieldOffset{#if[Object]?, fieldType}, vform, false); + } + @Override public Optional describeConstable() { var fieldTypeRef = {#if[Object]?fieldType:$type$.class}.describeConstable(); @@ -393,8 +440,8 @@ final class VarHandle$Type$s { } @Override - final MethodType accessModeTypeUncached(AccessMode accessMode) { - return accessMode.at.accessModeType(null, {#if[Object]?fieldType:$type$.class}); + final MethodType accessModeTypeUncached(AccessType at) { + return at.accessModeType(null, {#if[Object]?fieldType:$type$.class}); } @ForceInline @@ -430,7 +477,26 @@ final class VarHandle$Type$s { static final class FieldStaticReadWrite extends FieldStaticReadOnly { FieldStaticReadWrite(Object base, long fieldOffset{#if[Object]?, Class fieldType}) { - super(base, fieldOffset{#if[Object]?, fieldType}, FieldStaticReadWrite.FORM); + this(base, fieldOffset{#if[Object]?, fieldType}, false); + } + + private FieldStaticReadWrite(Object base, long fieldOffset{#if[Object]?, Class fieldType}, + boolean exact) { + super(base, fieldOffset{#if[Object]?, fieldType}, FieldStaticReadWrite.FORM, exact); + } + + @Override + public FieldStaticReadWrite withInvokeExactBehavior() { + return hasInvokeExactBehavior() + ? this + : new FieldStaticReadWrite(base, fieldOffset{#if[Object]?, fieldType}, true); + } + + @Override + public FieldStaticReadWrite withInvokeBehavior() { + return !hasInvokeExactBehavior() + ? this + : new FieldStaticReadWrite(base, fieldOffset{#if[Object]?, fieldType}, false); } #if[Object] @@ -693,7 +759,11 @@ final class VarHandle$Type$s { #end[Object] Array(int abase, int ashift{#if[Object]?, Class arrayType}) { - super(Array.FORM); + this(abase, ashift{#if[Object]?, arrayType}, false); + } + + private Array(int abase, int ashift{#if[Object]?, Class arrayType}, boolean exact) { + super(Array.FORM, exact); this.abase = abase; this.ashift = ashift; #if[Object] @@ -702,6 +772,20 @@ final class VarHandle$Type$s { #end[Object] } + @Override + public Array withInvokeExactBehavior() { + return hasInvokeExactBehavior() + ? this + : new Array(abase, ashift{#if[Object]?, arrayType}, true); + } + + @Override + public Array withInvokeBehavior() { + return !hasInvokeExactBehavior() + ? this + : new Array(abase, ashift{#if[Object]?, arrayType}, false); + } + @Override public Optional describeConstable() { var arrayTypeRef = {#if[Object]?arrayType:$type$[].class}.describeConstable(); @@ -712,8 +796,8 @@ final class VarHandle$Type$s { } @Override - final MethodType accessModeTypeUncached(AccessMode accessMode) { - return accessMode.at.accessModeType({#if[Object]?arrayType:$type$[].class}, {#if[Object]?arrayType.getComponentType():$type$.class}, int.class); + final MethodType accessModeTypeUncached(AccessType at) { + return at.accessModeType({#if[Object]?arrayType:$type$[].class}, {#if[Object]?arrayType.getComponentType():$type$.class}, int.class); } #if[Object] diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template index 9ac3d25866e..cdbe6df68c4 100644 --- a/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template +++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template @@ -68,8 +68,8 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { private static abstract class ByteArrayViewVarHandle extends VarHandle { final boolean be; - ByteArrayViewVarHandle(VarForm form, boolean be) { - super(form); + ByteArrayViewVarHandle(VarForm form, boolean be, boolean exact) { + super(form, exact); this.be = be; } } @@ -77,12 +77,30 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { static final class ArrayHandle extends ByteArrayViewVarHandle { ArrayHandle(boolean be) { - super(ArrayHandle.FORM, be); + this(be, false); + } + + private ArrayHandle(boolean be, boolean exact) { + super(ArrayHandle.FORM, be, exact); + } + + @Override + public ArrayHandle withInvokeExactBehavior() { + return hasInvokeExactBehavior() + ? this + : new ArrayHandle(be, true); + } + + @Override + public ArrayHandle withInvokeBehavior() { + return !hasInvokeExactBehavior() + ? this + : new ArrayHandle(be, false); } @Override - final MethodType accessModeTypeUncached(AccessMode accessMode) { - return accessMode.at.accessModeType(byte[].class, $type$.class, int.class); + final MethodType accessModeTypeUncached(AccessType at) { + return at.accessModeType(byte[].class, $type$.class, int.class); } @ForceInline @@ -555,12 +573,30 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase { static final class ByteBufferHandle extends ByteArrayViewVarHandle { ByteBufferHandle(boolean be) { - super(ByteBufferHandle.FORM, be); + this(be, false); + } + + private ByteBufferHandle(boolean be, boolean exact) { + super(ByteBufferHandle.FORM, be, exact); + } + + @Override + public ByteBufferHandle withInvokeExactBehavior() { + return hasInvokeExactBehavior() + ? this + : new ByteBufferHandle(be, true); + } + + @Override + public ByteBufferHandle withInvokeBehavior() { + return !hasInvokeExactBehavior() + ? this + : new ByteBufferHandle(be, false); } @Override - final MethodType accessModeTypeUncached(AccessMode accessMode) { - return accessMode.at.accessModeType(ByteBuffer.class, $type$.class, int.class); + final MethodType accessModeTypeUncached(AccessType at) { + return at.accessModeType(ByteBuffer.class, $type$.class, int.class); } @ForceInline diff --git a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java index 1020248796d..09da26d705e 100644 --- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java +++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java @@ -354,7 +354,6 @@ public String toString() { } } - /** *

    A package exported by a module, may be qualified or unqualified.

    @@ -892,7 +891,6 @@ public String toString() { } - /** * A module's version string. diff --git a/src/java.base/share/classes/java/lang/ref/Finalizer.java b/src/java.base/share/classes/java/lang/ref/Finalizer.java index 59c59c528be..54b1283bb44 100644 --- a/src/java.base/share/classes/java/lang/ref/Finalizer.java +++ b/src/java.base/share/classes/java/lang/ref/Finalizer.java @@ -82,7 +82,7 @@ private void runFinalizer(JavaLangAccess jla) { } try { - Object finalizee = this.get(); + Object finalizee = this.getInactive(); if (finalizee != null && !(finalizee instanceof java.lang.Enum)) { jla.invokeFinalize(finalizee); diff --git a/src/java.base/share/classes/java/lang/ref/Reference.java b/src/java.base/share/classes/java/lang/ref/Reference.java index 4c119e3d4b9..0cc1bbe3af2 100644 --- a/src/java.base/share/classes/java/lang/ref/Reference.java +++ b/src/java.base/share/classes/java/lang/ref/Reference.java @@ -342,6 +342,20 @@ public T get() { return this.referent; } + /** + * Load referent with strong semantics. Treating the referent + * as strong referent is ok when the Reference is inactive, + * because then the referent is switched to strong semantics + * anyway. + * + * This is only used from Finalizer to bypass the intrinsic, + * which might return a null referent, even though it is not + * null, and would subsequently not finalize the referent/finalizee. + */ + T getInactive() { + return this.referent; + } + /** * Tests if the referent of this reference object is {@code obj}. * Using a {@code null} {@code obj} returns {@code true} if the diff --git a/src/java.base/share/classes/java/net/ServerSocket.java b/src/java.base/share/classes/java/net/ServerSocket.java index 0397d860aa9..249c09b9674 100644 --- a/src/java.base/share/classes/java/net/ServerSocket.java +++ b/src/java.base/share/classes/java/net/ServerSocket.java @@ -75,7 +75,6 @@ * * Additional (implementation specific) options may also be supported. * - * @author unascribed * @see java.net.SocketImpl * @see java.net.ServerSocket#setSocketFactory(java.net.SocketImplFactory) * @see java.nio.channels.ServerSocketChannel diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java index 43b2a31df60..3357dbfe777 100644 --- a/src/java.base/share/classes/java/net/Socket.java +++ b/src/java.base/share/classes/java/net/Socket.java @@ -96,7 +96,6 @@ * * Additional (implementation specific) options may also be supported. * - * @author unascribed * @see java.net.Socket#setSocketImplFactory(java.net.SocketImplFactory) * @see java.net.SocketImpl * @see java.nio.channels.SocketChannel diff --git a/src/java.base/share/classes/java/net/SocketImpl.java b/src/java.base/share/classes/java/net/SocketImpl.java index 4c3e9c08970..a747cfff014 100644 --- a/src/java.base/share/classes/java/net/SocketImpl.java +++ b/src/java.base/share/classes/java/net/SocketImpl.java @@ -60,7 +60,6 @@ * to use the old implementation. The property and old implementation will be * removed in a future version. * - * @author unascribed * @since 1.0 */ public abstract class SocketImpl implements SocketOptions { diff --git a/src/java.base/share/classes/java/net/UnknownServiceException.java b/src/java.base/share/classes/java/net/UnknownServiceException.java index fb48dd8bd60..3664e19f8e0 100644 --- a/src/java.base/share/classes/java/net/UnknownServiceException.java +++ b/src/java.base/share/classes/java/net/UnknownServiceException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ * not make sense, or the application is attempting to write to a * read-only URL connection. * - * @author unascribed * @since 1.0 */ public class UnknownServiceException extends IOException { diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template index 09c48e86bfc..07c7d3c7d26 100644 --- a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template @@ -416,6 +416,16 @@ class Direct$Type$Buffer$RW$$BO$ #end[rw] } + public $Type$Buffer put(int index, $Type$Buffer src, int offset, int length) { +#if[rw] + checkSegment(); + super.put(index, src, offset, length); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + public $Type$Buffer put($type$[] src, int offset, int length) { #if[rw] checkSegment(); diff --git a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template index 263e699ac1f..e4a89efc6d8 100644 --- a/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/Heap-X-Buffer.java.template @@ -251,6 +251,16 @@ class Heap$Type$Buffer$RW$ #end[rw] } + public $Type$Buffer put(int index, $Type$Buffer src, int offset, int length) { +#if[rw] + checkSegment(); + super.put(index, src, offset, length); + return this; +#else[rw] + throw new ReadOnlyBufferException(); +#end[rw] + } + public $Type$Buffer put(int index, $type$[] src, int offset, int length) { #if[rw] checkSegment(); diff --git a/src/java.base/share/classes/java/nio/X-Buffer.java.template b/src/java.base/share/classes/java/nio/X-Buffer.java.template index 4804f4b4319..8a5be7ceaf6 100644 --- a/src/java.base/share/classes/java/nio/X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/X-Buffer.java.template @@ -956,6 +956,76 @@ public abstract class $Type$Buffer if (n > limit() - pos) throw new BufferOverflowException(); + putBuffer(pos, src, srcPos, n); + + position(pos + n); + src.position(srcPos + n); + + return this; + } + + /** + * Absolute bulk put method  (optional operation). + * + *

    This method transfers {@code length} $type$s into this buffer from + * the given source buffer, starting at the given {@code offset} in the + * source buffer and the given {@code index} in this buffer. The positions + * of both buffers are unchanged. + * + *

    In other words, an invocation of this method of the form + * dst.put(index, src, offset, length) + * has exactly the same effect as the loop + * + *

    {@code
    +     * for (int i = offset, j = index; i < offset + length; i++, j++)
    +     *     dst.put(j, src.get(i));
    +     * }
    + * + * except that it first checks the consistency of the supplied parameters + * and it is potentially much more efficient. If this buffer and + * the source buffer share the same backing array or memory, then the + * result will be as if the source elements were first copied to an + * intermediate location before being written into this buffer. + * + * @param index + * The index in this buffer at which the first $type$ will be + * written; must be non-negative and less than {@code limit()} + * + * @param src + * The buffer from which $type$s are to be read + * + * @param offset + * The index within the source buffer of the first $type$ to be + * read; must be non-negative and less than {@code src.limit()} + * + * @param length + * The number of $type$s to be read from the given buffer; + * must be non-negative and no larger than the smaller of + * {@code limit() - index} and {@code src.limit() - offset} + * + * @return This buffer + * + * @throws IndexOutOfBoundsException + * If the preconditions on the {@code index}, {@code offset}, and + * {@code length} parameters do not hold + * + * @throws ReadOnlyBufferException + * If this buffer is read-only + * + * @since 16 + */ + public $Type$Buffer put(int index, $Type$Buffer src, int offset, int length) { + Objects.checkFromIndexSize(index, length, limit()); + Objects.checkFromIndexSize(offset, length, src.limit()); + if (isReadOnly()) + throw new ReadOnlyBufferException(); + + putBuffer(index, src, offset, length); + + return this; + } + + void putBuffer(int pos, $Type$Buffer src, int srcPos, int n) { Object srcBase = src.base(); #if[char] @@ -999,18 +1069,14 @@ public abstract class $Type$Buffer } } #end[!byte] - - position(pos + n); - src.position(srcPos + n); #if[char] } else { // src.isAddressable() == false assert StringCharBuffer.class.isInstance(src); - for (int i = 0; i < n; i++) - put(src.get()); + int posMax = pos + n; + for (int i = pos, j = srcPos; i < posMax; i++, j++) + put(i, src.get(j)); } #end[char] - - return this; } /** diff --git a/src/java.base/share/classes/java/util/Dictionary.java b/src/java.base/share/classes/java/util/Dictionary.java index 162de2b5d62..653894765eb 100644 --- a/src/java.base/share/classes/java/util/Dictionary.java +++ b/src/java.base/share/classes/java/util/Dictionary.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -39,7 +39,6 @@ * NOTE: This class is obsolete. New implementations should * implement the Map interface, rather than extending this class. * - * @author unascribed * @see java.util.Map * @see java.lang.Object#equals(java.lang.Object) * @see java.lang.Object#hashCode() diff --git a/src/java.base/share/classes/java/util/InputMismatchException.java b/src/java.base/share/classes/java/util/InputMismatchException.java index 3367a8a6fb5..522a5532cd4 100644 --- a/src/java.base/share/classes/java/util/InputMismatchException.java +++ b/src/java.base/share/classes/java/util/InputMismatchException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ * retrieved does not match the pattern for the expected type, or * that the token is out of range for the expected type. * - * @author unascribed * @see java.util.Scanner * @since 1.5 */ diff --git a/src/java.base/share/classes/java/util/NoSuchElementException.java b/src/java.base/share/classes/java/util/NoSuchElementException.java index 243ecb4ca02..28c20367958 100644 --- a/src/java.base/share/classes/java/util/NoSuchElementException.java +++ b/src/java.base/share/classes/java/util/NoSuchElementException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * Thrown by various accessor methods to indicate that the element being requested * does not exist. * - * @author unascribed * @see java.util.Enumeration#nextElement() * @see java.util.Iterator#next() * @since 1.0 diff --git a/src/java.base/share/classes/java/util/StringTokenizer.java b/src/java.base/share/classes/java/util/StringTokenizer.java index 8e8a09b9828..f30f7b863a4 100644 --- a/src/java.base/share/classes/java/util/StringTokenizer.java +++ b/src/java.base/share/classes/java/util/StringTokenizer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,6 @@ * test * * - * @author unascribed * @see java.io.StreamTokenizer * @since 1.0 */ diff --git a/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java b/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java index 4b60fbb9ec0..f58034aad3c 100644 --- a/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java +++ b/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * Unchecked exception thrown to indicate a syntax error in a * regular-expression pattern. * - * @author unascribed * @since 1.4 */ diff --git a/src/java.base/share/classes/java/util/zip/Adler32.java b/src/java.base/share/classes/java/util/zip/Adler32.java index ee7c06e619d..33aac1ad79d 100644 --- a/src/java.base/share/classes/java/util/zip/Adler32.java +++ b/src/java.base/share/classes/java/util/zip/Adler32.java @@ -25,6 +25,7 @@ package java.util.zip; +import java.lang.ref.Reference; import java.nio.ByteBuffer; import sun.nio.ch.DirectBuffer; @@ -96,8 +97,12 @@ public void update(ByteBuffer buffer) { int rem = limit - pos; if (rem <= 0) return; - if (buffer instanceof DirectBuffer) { - adler = updateByteBuffer(adler, ((DirectBuffer)buffer).address(), pos, rem); + if (buffer.isDirect()) { + try { + adler = updateByteBuffer(adler, ((DirectBuffer)buffer).address(), pos, rem); + } finally { + Reference.reachabilityFence(buffer); + } } else if (buffer.hasArray()) { adler = updateBytes(adler, buffer.array(), pos + buffer.arrayOffset(), rem); } else { diff --git a/src/java.base/share/classes/java/util/zip/CRC32.java b/src/java.base/share/classes/java/util/zip/CRC32.java index a70afb90e51..17264eb1798 100644 --- a/src/java.base/share/classes/java/util/zip/CRC32.java +++ b/src/java.base/share/classes/java/util/zip/CRC32.java @@ -25,6 +25,7 @@ package java.util.zip; +import java.lang.ref.Reference; import java.nio.ByteBuffer; import java.util.Objects; @@ -95,8 +96,12 @@ public void update(ByteBuffer buffer) { int rem = limit - pos; if (rem <= 0) return; - if (buffer instanceof DirectBuffer) { - crc = updateByteBuffer(crc, ((DirectBuffer)buffer).address(), pos, rem); + if (buffer.isDirect()) { + try { + crc = updateByteBuffer(crc, ((DirectBuffer)buffer).address(), pos, rem); + } finally { + Reference.reachabilityFence(buffer); + } } else if (buffer.hasArray()) { crc = updateBytes(crc, buffer.array(), pos + buffer.arrayOffset(), rem); } else { diff --git a/src/java.base/share/classes/java/util/zip/CRC32C.java b/src/java.base/share/classes/java/util/zip/CRC32C.java index 0359a798816..fa138d4d3f6 100644 --- a/src/java.base/share/classes/java/util/zip/CRC32C.java +++ b/src/java.base/share/classes/java/util/zip/CRC32C.java @@ -24,6 +24,7 @@ */ package java.util.zip; +import java.lang.ref.Reference; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -170,9 +171,13 @@ public void update(ByteBuffer buffer) { return; } - if (buffer instanceof DirectBuffer) { - crc = updateDirectByteBuffer(crc, ((DirectBuffer) buffer).address(), - pos, limit); + if (buffer.isDirect()) { + try { + crc = updateDirectByteBuffer(crc, ((DirectBuffer) buffer).address(), + pos, limit); + } finally { + Reference.reachabilityFence(buffer); + } } else if (buffer.hasArray()) { crc = updateBytes(crc, buffer.array(), pos + buffer.arrayOffset(), limit + buffer.arrayOffset()); diff --git a/src/java.base/share/classes/java/util/zip/ZipException.java b/src/java.base/share/classes/java/util/zip/ZipException.java index f6dcc59cfe6..45048a4254b 100644 --- a/src/java.base/share/classes/java/util/zip/ZipException.java +++ b/src/java.base/share/classes/java/util/zip/ZipException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ /** * Signals that a Zip exception of some sort has occurred. * - * @author unascribed * @see java.io.IOException * @since 1.1 */ diff --git a/src/java.base/share/classes/jdk/internal/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/PreviewFeature.java index 5624ead42d9..4bf0838ec2a 100644 --- a/src/java.base/share/classes/jdk/internal/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/PreviewFeature.java @@ -54,7 +54,6 @@ public boolean essentialAPI() default false; public enum Feature { - PATTERN_MATCHING_IN_INSTANCEOF, // 8242284: // The TEXT_BLOCKS enum constant is not used in the JDK 15 codebase, but // exists to support the bootcycle build of JDK 15. The bootcycle build diff --git a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index 720be39e2bb..505024bebad 100644 --- a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -573,8 +573,12 @@ private static ZoneInfo getZoneInfo(String zoneId, // we can then pass in the dom = -1, dow > 0 into ZoneInfo // // hacking, assume the >=24 is the result of ZRB optimization for - // "last", it works for now. - if (dom < 0 || dom >= 24) { + // "last", it works for now. From tzdata2020d this hacking + // will not work for Asia/Gaza and Asia/Hebron which follow + // Palestine DST rules. + if (dom < 0 || dom >= 24 && + !(zoneId.equals("Asia/Gaza") || + zoneId.equals("Asia/Hebron"))) { params[1] = -1; params[2] = toCalendarDOW[dow]; } else { @@ -596,7 +600,9 @@ private static ZoneInfo getZoneInfo(String zoneId, params[7] = 0; } else { // hacking: see comment above - if (dom < 0 || dom >= 24) { + if (dom < 0 || dom >= 24 && + !(zoneId.equals("Asia/Gaza") || + zoneId.equals("Asia/Hebron"))) { params[6] = -1; params[7] = toCalendarDOW[dow]; } else { diff --git a/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java b/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java index c16a4c7f978..fa609761022 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java @@ -121,20 +121,9 @@ public enum ElementKind { RECORD_COMPONENT, /** - * {@preview Associated with pattern matching for {@code - * instanceof}, a preview feature of the Java language. - * - * This enum constant is associated with pattern - * matching for {@code instanceof}, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * - * A binding variable in a pattern . - * @since 14 + * A binding variable in a pattern. + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.PATTERN_MATCHING_IN_INSTANCEOF, - essentialAPI=false) BINDING_VARIABLE; /** diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java index 2b1b9b89f7a..c61b1258894 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifBorders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,11 +25,6 @@ package com.sun.java.swing.plaf.motif; -import sun.swing.SwingUtilities2; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.plaf.*; - import java.awt.Color; import java.awt.Component; import java.awt.Dimension; @@ -40,15 +35,21 @@ import java.awt.Point; import java.awt.Rectangle; +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JInternalFrame; +import javax.swing.JMenuBar; +import javax.swing.JPopupMenu; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; +import javax.swing.plaf.UIResource; + +import sun.swing.SwingUtilities2; + /** * Factory object that can vend Icons appropriate for the basic {@literal L & F}. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Amy Fowler */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java index eb2520cd2b1..08017a0b2c8 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,24 +25,27 @@ package com.sun.java.swing.plaf.motif; -import sun.awt.AppContext; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.Shape; + +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicButtonListener; +import javax.swing.plaf.basic.BasicButtonUI; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.plaf.basic.*; -import java.awt.*; -import java.awt.event.*; -import javax.swing.plaf.*; +import sun.awt.AppContext; /** * MotifButton implementation - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Rich Schiavi */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java index 11dc92d3a8d..fa06aa6bd02 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifCheckBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,15 @@ package com.sun.java.swing.plaf.motif; -import sun.awt.AppContext; - -import javax.swing.*; +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.*; - -import java.awt.*; +import sun.awt.AppContext; /** * MotifCheckBox implementation - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Rich Schiavi */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java index fcd12ac20d4..254b63181b3 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifComboBoxUI.java @@ -52,14 +52,7 @@ import javax.swing.plaf.basic.ComboPopup; /** - * ComboBox motif look and feel - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. + * ComboBox motif look and feel. * * @author Arnaud Weber */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java index c3e1f85993b..60552b8c780 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifDesktopPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,25 +25,26 @@ package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import java.awt.Rectangle; -import java.awt.Dimension; -import java.awt.Insets; import java.awt.Color; -import java.awt.Graphics; import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; import java.awt.Point; -import javax.swing.plaf.*; +import java.awt.Rectangle; import java.io.Serializable; +import javax.swing.DefaultDesktopManager; +import javax.swing.JComponent; +import javax.swing.JDesktopPane; +import javax.swing.JInternalFrame; +import javax.swing.JLayeredPane; +import javax.swing.SwingUtilities; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; + /** - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. + * Motif desktop pane. * * @author David Kloba */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java index c7943dff79f..3367b36f0fd 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifEditorPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,22 +22,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import javax.swing.text.*; -import javax.swing.plaf.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicEditorPaneUI; +import javax.swing.text.Caret; /** * Provides the look and feel for an pluggable content-type text editor. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Timothy Prinzing */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java index c7cf812dbf5..dac6514f0c4 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifIconFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,29 +25,21 @@ package com.sun.java.swing.plaf.motif; -import javax.swing.*; - -import javax.swing.plaf.UIResource; - import java.awt.Color; import java.awt.Component; -import java.awt.Dimension; import java.awt.Graphics; -import java.awt.Polygon; - import java.io.Serializable; +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.UIManager; +import javax.swing.plaf.UIResource; + /** * Icon factory for the CDE/Motif Look and Feel - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * - * 1.20 04/27/99 * @author Georges Saab */ @SuppressWarnings("serial") // Same-version serialization only diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java index 8d9e5122ef6..cba71847fa4 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifInternalFrameUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,27 +25,29 @@ package com.sun.java.swing.plaf.motif; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.event.*; - -import java.util.EventListener; - -import javax.swing.plaf.basic.*; -import javax.swing.border.*; -import javax.swing.plaf.*; - +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; + +import javax.swing.AbstractAction; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.JInternalFrame; +import javax.swing.KeyStroke; +import javax.swing.LookAndFeel; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.ActionMapUIResource; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicInternalFrameUI; /** * A Motif {@literal L&F} implementation of InternalFrame. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Tom Ball */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java index 1da0036e3fa..f19a3c23cb5 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLabelUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,15 @@ package com.sun.java.swing.plaf.motif; -import sun.awt.AppContext; - -import javax.swing.*; -import javax.swing.plaf.basic.BasicLabelUI; +import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicLabelUI; + +import sun.awt.AppContext; /** * A Motif {@literal L&F} implementation of LabelUI. * This merely sets up new default values in MotifLookAndFeel. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Amy Fowler */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java index 34f4bd700d2..d4993c11eb9 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifLookAndFeel.java @@ -27,39 +27,27 @@ import java.awt.Color; import java.awt.Font; -import java.awt.Insets; import java.awt.event.KeyEvent; -import java.awt.event.InputEvent; -import java.util.*; -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.border.*; -import javax.swing.text.JTextComponent; -import javax.swing.text.DefaultEditorKit; - -import javax.swing.plaf.basic.BasicLookAndFeel; +import javax.swing.JTextField; +import javax.swing.UIDefaults; +import javax.swing.border.Border; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.InsetsUIResource; import javax.swing.plaf.basic.BasicBorders; -import javax.swing.plaf.basic.BasicComboBoxRenderer; -import javax.swing.plaf.basic.BasicComboBoxEditor; +import javax.swing.plaf.basic.BasicLookAndFeel; +import javax.swing.text.DefaultEditorKit; import sun.swing.SwingAccessor; import sun.swing.SwingUtilities2; -import sun.awt.OSInfo; /** * Implements the Motif Look and Feel. * UI classes not implemented specifically for Motif will * default to those implemented in Basic. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * - * @author unattributed * @deprecated The Motif Look and Feel is deprecated with the intent to remove * it in some future release. It is recommended to use * {@link javax.swing.plaf.metal.MetalLookAndFeel} instead. diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuBarUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuBarUI.java index cdc05400fe2..4e9beaa8ab4 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuBarUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifMenuBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,35 +25,13 @@ package com.sun.java.swing.plaf.motif; -import java.awt.Component; -import java.awt.Container; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Color; -import java.awt.Insets; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.*; -import java.io.Serializable; - -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.border.*; -import javax.swing.plaf.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicMenuBarUI; -//REMIND -import javax.swing.plaf.basic.*; /** * A Windows {@literal L&F} implementation of MenuBarUI. This implementation * is a "combined" view/controller. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Georges Saab * @author Rich Schiavi diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java index ddba46c9cc9..7da390bad23 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifOptionPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,26 +25,21 @@ package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import javax.swing.plaf.basic.BasicOptionPaneUI; -import javax.swing.plaf.ComponentUI; import java.awt.Color; -import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Graphics; -import java.awt.Insets; -import java.awt.Rectangle; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicOptionPaneUI; /** * Provides the CDE/Motif look and feel for a JOptionPane. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Scott Violet */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java index 3b0159c8d7b..8e1369d7e96 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPasswordFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,22 +22,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import javax.swing.text.*; -import javax.swing.plaf.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicPasswordFieldUI; +import javax.swing.text.Caret; /** * Provides the Motif look and feel for a password field. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Timothy Prinzing */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java index a0b182b8019..0986f81f0ff 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifPopupMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,36 +25,27 @@ package com.sun.java.swing.plaf.motif; -import sun.swing.SwingUtilities2; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.border.*; -import java.awt.Color; -import java.awt.Component; -import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; -import java.awt.Frame; -import java.awt.Graphics; import java.awt.Insets; import java.awt.LayoutManager; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.*; -import javax.swing.plaf.*; +import java.awt.event.MouseEvent; + +import javax.swing.JComponent; +import javax.swing.JPopupMenu; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicPopupMenuUI; +import sun.swing.SwingUtilities2; /** * A Motif {@literal L&F} implementation of PopupMenuUI. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Georges Saab * @author Rich Schiavi diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifProgressBarUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifProgressBarUI.java index 66d99e007d4..2c53d741397 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifProgressBarUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifProgressBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,24 +25,12 @@ package com.sun.java.swing.plaf.motif; -import java.awt.*; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.plaf.*; -import java.io.Serializable; - +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicProgressBarUI; - /** * A Motif ProgressBarUI. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Michael C. Albers */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java index 3cc793fccae..1a9d7fa1e91 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,26 +25,24 @@ package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.plaf.*; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.io.Serializable; + +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.LookAndFeel; +import javax.swing.MenuSelectionManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.MouseInputListener; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI; -import java.awt.*; -import java.awt.event.*; -import java.io.Serializable; import sun.swing.SwingUtilities2; - /** * MotifRadioButtonMenuItem implementation - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Georges Saab * @author Rich Schiavi diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java index 328ca4844ed..58619280493 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifRadioButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,25 +25,21 @@ package com.sun.java.swing.plaf.motif; -import sun.awt.AppContext; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; -import javax.swing.*; -import javax.swing.border.*; +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicRadioButtonUI; -import javax.swing.plaf.*; - -import java.awt.*; +import sun.awt.AppContext; /** * RadioButtonUI implementation for MotifRadioButtonUI - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Rich Schiavi */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java index cb586512c82..5b812ca4c8c 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarButton.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,15 @@ package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.BasicArrowButton; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; -import java.awt.*; -import java.awt.event.*; +import javax.swing.UIManager; +import javax.swing.plaf.basic.BasicArrowButton; /** * Motif scroll bar button. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ @SuppressWarnings("serial") // Superclass is not serializable across versions public class MotifScrollBarButton extends BasicArrowButton diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java index 294a1c374ab..08a283f5e52 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.java.swing.plaf.motif; import java.awt.Dimension; @@ -38,16 +39,8 @@ import static sun.swing.SwingUtilities2.drawHLine; import static sun.swing.SwingUtilities2.drawVLine; - /** * Implementation of ScrollBarUI for the Motif Look and Feel - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Rich Schiavi * @author Hans Muller diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollPaneUI.java index af659095672..833cf732b0a 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifScrollPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,20 @@ package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.BasicScrollPaneUI; - import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicScrollPaneUI; + /** * A CDE/Motif {@code L&F} implementation of ScrollPaneUI. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Hans Muller */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSeparatorUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSeparatorUI.java index bc457b01b13..dac713eda7b 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSeparatorUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSeparatorUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,25 +25,13 @@ package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Insets; -import java.awt.Rectangle; -import javax.swing.plaf.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSeparatorUI; /** * A Motif {@literal L&F} implementation of SeparatorUI. * This implementation is a "combined" view/controller. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Georges Saab * @author Jeff Shapiro diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java index e22db5e05cd..c8820de17c4 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSliderUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,14 +38,7 @@ import static sun.swing.SwingUtilities2.drawVLine; /** - * Motif Slider - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. + * Motif Slider. * * @author Jeff Dinkins */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java index 6040eb31323..7dceae4930d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneDivider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,20 @@ package com.sun.java.swing.plaf.motif; -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.event.MouseEvent; + import javax.swing.JSplitPane; import javax.swing.UIManager; -import javax.swing.plaf.basic.BasicSplitPaneUI; import javax.swing.plaf.basic.BasicSplitPaneDivider; - +import javax.swing.plaf.basic.BasicSplitPaneUI; /** * Divider used for Motif split pane. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Jeff Dinkins */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java index 6ee670812c3..c61a1713c9b 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifSplitPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,21 +25,13 @@ package com.sun.java.swing.plaf.motif; -import javax.swing.plaf.basic.BasicSplitPaneUI; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSplitPaneDivider; -import javax.swing.plaf.*; -import javax.swing.*; -import java.awt.*; +import javax.swing.plaf.basic.BasicSplitPaneUI; /** * Motif rendition of a split pane. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Jeff Dinkins */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java index e7bae098a55..1c53fc4a179 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTabbedPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,17 @@ package com.sun.java.swing.plaf.motif; -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.plaf.*; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicTabbedPaneUI; -import java.io.Serializable; /** * A Motif {@literal L&F} implementation of TabbedPaneUI. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Amy Fowler * @author Philip Milne diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java index c6f4cc54b3a..baddbf3a75d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextAreaUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,24 +22,18 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import javax.swing.text.*; -import javax.swing.plaf.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicTextAreaUI; +import javax.swing.text.Caret; /** * Provides the look and feel for a plain text editor. In this * implementation the default UI is extended to act as a simple * view factory. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Timothy Prinzing */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java index 895183c1e6a..08437687ebc 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,22 +22,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.java.swing.plaf.motif; -import javax.swing.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicTextFieldUI; -import javax.swing.plaf.*; import javax.swing.text.Caret; /** * Provides the Motif look and feel for a text field. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Timothy Prinzing */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java index 3e1590a8831..e47ad4c60bf 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,22 +22,16 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import javax.swing.text.*; -import javax.swing.plaf.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicTextPaneUI; +import javax.swing.text.Caret; /** * Provides the look and feel for a styled text editor. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Timothy Prinzing */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java index a2a85e9cbff..b79ef19df8e 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTextUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,25 +22,29 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.java.swing.plaf.motif; -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; -import javax.swing.*; -import javax.swing.text.*; -import javax.swing.plaf.*; +import javax.swing.KeyStroke; +import javax.swing.plaf.TextUI; +import javax.swing.plaf.UIResource; +import javax.swing.text.BadLocationException; +import javax.swing.text.Caret; +import javax.swing.text.DefaultCaret; +import javax.swing.text.DefaultEditorKit; +import javax.swing.text.JTextComponent; /** * Provides the look and feel features that are common across * the Motif/CDE text LAF implementations. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Timothy Prinzing */ @@ -58,13 +62,6 @@ public static Caret createCaret() { /** * The motif caret is rendered as an I beam. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ @SuppressWarnings("serial") // Superclass is not serializable across versions public static class MotifCaret extends DefaultCaret implements UIResource { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java index b13c87e392b..eef60ade9c9 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifToggleButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,26 +25,24 @@ package com.sun.java.swing.plaf.motif; -import sun.awt.AppContext; - -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicToggleButtonUI; +import sun.awt.AppContext; /** - * BasicToggleButton implementation - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. + * BasicToggleButton implementation. * * @author Rich Schiavi */ diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java index fbddca81841..78ec251f05d 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeCellRenderer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,24 +25,18 @@ package com.sun.java.swing.plaf.motif; -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.tree.*; -import java.awt.*; -import java.awt.event.*; -import java.beans.*; -import java.io.*; -import java.util.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.Icon; +import javax.swing.UIManager; +import javax.swing.plaf.IconUIResource; +import javax.swing.tree.DefaultTreeCellRenderer; /** * Motif rendered to display a tree cell. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Jeff Dinkins */ @@ -62,13 +56,6 @@ public static Icon loadLeafIcon() { /** * Icon for a node with no children. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ @SuppressWarnings("serial") // Same-version serialization only public static class TreeLeafIcon implements Icon, Serializable { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java index 5977b807300..468ef4eb565 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/motif/MotifTreeUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,26 +25,20 @@ package com.sun.java.swing.plaf.motif; -import java.awt.*; -import java.awt.event.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; -import java.io.*; -import java.util.*; - -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.tree.*; -import javax.swing.plaf.basic.*; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTreeUI; +import javax.swing.tree.TreeCellRenderer; /** * Motif rendition of the tree component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Jeff Dinkins */ @@ -83,13 +77,6 @@ protected void paintHorizontalLine( Graphics g, JComponent c, int y, int left, i /** * The minus sign button icon. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ @SuppressWarnings("serial") // Same-version serialization only public static class MotifExpandedIcon implements Icon, Serializable { @@ -132,13 +119,6 @@ public void paintIcon(Component c, Graphics g, int x, int y) { /** * The plus sign button icon. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ @SuppressWarnings("serial") // Same-version serialization only public static class MotifCollapsedIcon extends MotifExpandedIcon { diff --git a/src/java.desktop/share/classes/java/awt/Robot.java b/src/java.desktop/share/classes/java/awt/Robot.java index 535fe58a676..a7af9903e4f 100644 --- a/src/java.desktop/share/classes/java/awt/Robot.java +++ b/src/java.desktop/share/classes/java/awt/Robot.java @@ -43,6 +43,9 @@ import sun.awt.image.SunWritableRaster; import sun.java2d.SunGraphicsEnvironment; +import static sun.java2d.SunGraphicsEnvironment.toDeviceSpace; +import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs; + /** * This class is used to generate native system input events * for the purposes of test automation, self-running demos, and @@ -385,13 +388,9 @@ private static void checkKeycodeArgument(int keycode) { */ public synchronized Color getPixelColor(int x, int y) { checkScreenCaptureAllowed(); - AffineTransform tx = GraphicsEnvironment. - getLocalGraphicsEnvironment().getDefaultScreenDevice(). - getDefaultConfiguration().getDefaultTransform(); - x = (int) (x * tx.getScaleX()); - y = (int) (y * tx.getScaleY()); - Color color = new Color(peer.getRGBPixel(x, y)); - return color; + Point point = peer.useAbsoluteCoordinates() ? toDeviceSpaceAbs(x, y) + : toDeviceSpace(x, y); + return new Color(peer.getRGBPixel(point.x, point.y)); } /** @@ -523,17 +522,16 @@ public synchronized BufferedImage createScreenCapture(Rectangle screenRect) { imageArray[0] = highResolutionImage; } else { - - int sX = (int) Math.floor(screenRect.x * uiScaleX); - int sY = (int) Math.floor(screenRect.y * uiScaleY); - int sWidth = (int) Math.ceil(screenRect.width * uiScaleX); - int sHeight = (int) Math.ceil(screenRect.height * uiScaleY); - int[] temppixels; - Rectangle scaledRect = new Rectangle(sX, sY, sWidth, sHeight); - temppixels = peer.getRGBPixels(scaledRect); - + Rectangle scaledRect; + if (peer.useAbsoluteCoordinates()) { + scaledRect = toDeviceSpaceAbs(gc, screenRect.x, + screenRect.y, screenRect.width, screenRect.height); + } else { + scaledRect = toDeviceSpace(gc, screenRect.x, + screenRect.y, screenRect.width, screenRect.height); + } // HighResolutionImage - pixels = temppixels; + pixels = peer.getRGBPixels(scaledRect); buffer = new DataBufferInt(pixels, pixels.length); raster = Raster.createPackedRaster(buffer, scaledRect.width, scaledRect.height, scaledRect.width, bandmasks, null); diff --git a/src/java.desktop/share/classes/java/awt/color/ColorSpace.java b/src/java.desktop/share/classes/java/awt/color/ColorSpace.java index ecb40c2844f..f88bde99dad 100644 --- a/src/java.desktop/share/classes/java/awt/color/ColorSpace.java +++ b/src/java.desktop/share/classes/java/awt/color/ColorSpace.java @@ -244,25 +244,25 @@ public abstract class ColorSpace implements Serializable { /** - * The sRGB color space defined at + * The built-in sRGB color space defined at * * http://www.w3.org/pub/WWW/Graphics/Color/sRGB.html. */ @Native public static final int CS_sRGB = 1000; /** - * A built-in linear RGB color space. This space is based on the same RGB + * The built-in linear RGB color space. This space is based on the same RGB * primaries as {@code CS_sRGB}, but has a linear tone reproduction curve. */ @Native public static final int CS_LINEAR_RGB = 1004; /** - * The CIEXYZ conversion color space defined above. + * The built-in CIEXYZ conversion color space defined above. */ @Native public static final int CS_CIEXYZ = 1001; /** - * The Photo YCC conversion color space. + * The built-in Photo YCC conversion color space. */ @Native public static final int CS_PYCC = 1002; diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java b/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java index 73b5f1ebb92..da571ab5db7 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java @@ -115,10 +115,10 @@ public class ICC_ColorSpace extends ColorSpace { private boolean needScaleInit = true; // {to,from}{RGB,CIEXYZ} methods create and cache these when needed - private transient ColorTransform this2srgb; - private transient ColorTransform srgb2this; - private transient ColorTransform this2xyz; - private transient ColorTransform xyz2this; + private transient volatile ColorTransform this2srgb; + private transient volatile ColorTransform srgb2this; + private transient volatile ColorTransform this2xyz; + private transient volatile ColorTransform xyz2this; /** * Constructs a new {@code ICC_ColorSpace} from an {@code ICC_Profile} @@ -193,20 +193,22 @@ public ICC_Profile getProfile() { * @throws ArrayIndexOutOfBoundsException if array length is not at least * the number of components in this {@code ColorSpace} */ - public float[] toRGB (float[] colorvalue) { - + public float[] toRGB(float[] colorvalue) { if (this2srgb == null) { - ColorTransform[] transformList = new ColorTransform [2]; - ICC_ColorSpace srgbCS = - (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB); - PCMM mdl = CMSManager.getModule(); - transformList[0] = mdl.createTransform( - thisProfile, ColorTransform.Any, ColorTransform.In); - transformList[1] = mdl.createTransform( - srgbCS.getProfile(), ColorTransform.Any, ColorTransform.Out); - this2srgb = mdl.createTransform(transformList); - if (needScaleInit) { - setComponentScaling(); + synchronized (this) { + if (this2srgb == null) { + ColorTransform[] transforms = new ColorTransform[2]; + var srgb = (ICC_ColorSpace) getInstance(CS_sRGB); + PCMM mdl = CMSManager.getModule(); + transforms[0] = mdl.createTransform(thisProfile, + ColorTransform.Any, ColorTransform.In); + transforms[1] = mdl.createTransform(srgb.getProfile(), + ColorTransform.Any, ColorTransform.Out); + if (needScaleInit) { + setComponentScaling(); + } + this2srgb = mdl.createTransform(transforms); + } } } @@ -243,20 +245,22 @@ public float[] toRGB (float[] colorvalue) { * this {@code ColorSpace} * @throws ArrayIndexOutOfBoundsException if array length is not at least 3 */ - public float[] fromRGB(float[] rgbvalue) { - + public float[] fromRGB(float[] rgbvalue) { if (srgb2this == null) { - ColorTransform[] transformList = new ColorTransform [2]; - ICC_ColorSpace srgbCS = - (ICC_ColorSpace) ColorSpace.getInstance (CS_sRGB); - PCMM mdl = CMSManager.getModule(); - transformList[0] = mdl.createTransform( - srgbCS.getProfile(), ColorTransform.Any, ColorTransform.In); - transformList[1] = mdl.createTransform( - thisProfile, ColorTransform.Any, ColorTransform.Out); - srgb2this = mdl.createTransform(transformList); - if (needScaleInit) { - setComponentScaling(); + synchronized (this) { + if (srgb2this == null) { + ColorTransform[] transforms = new ColorTransform[2]; + var srgb = (ICC_ColorSpace) getInstance(CS_sRGB); + PCMM mdl = CMSManager.getModule(); + transforms[0] = mdl.createTransform(srgb.getProfile(), + ColorTransform.Any, ColorTransform.In); + transforms[1] = mdl.createTransform(thisProfile, + ColorTransform.Any, ColorTransform.Out); + if (needScaleInit) { + setComponentScaling(); + } + srgb2this = mdl.createTransform(transforms); + } } } @@ -373,26 +377,28 @@ public float[] fromRGB(float[] rgbvalue) { * @throws ArrayIndexOutOfBoundsException if array length is not at least * the number of components in this {@code ColorSpace} */ - public float[] toCIEXYZ(float[] colorvalue) { - + public float[] toCIEXYZ(float[] colorvalue) { if (this2xyz == null) { - ColorTransform[] transformList = new ColorTransform [2]; - ICC_ColorSpace xyzCS = - (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ); - PCMM mdl = CMSManager.getModule(); - try { - transformList[0] = mdl.createTransform( - thisProfile, ICC_Profile.icRelativeColorimetric, - ColorTransform.In); - } catch (CMMException e) { - transformList[0] = mdl.createTransform( - thisProfile, ColorTransform.Any, ColorTransform.In); - } - transformList[1] = mdl.createTransform( - xyzCS.getProfile(), ColorTransform.Any, ColorTransform.Out); - this2xyz = mdl.createTransform (transformList); - if (needScaleInit) { - setComponentScaling(); + synchronized (this) { + if (this2xyz == null) { + ColorTransform[] transforms = new ColorTransform[2]; + var xyz = (ICC_ColorSpace) getInstance(CS_CIEXYZ); + PCMM mdl = CMSManager.getModule(); + try { + transforms[0] = mdl.createTransform(thisProfile, + ICC_Profile.icRelativeColorimetric, + ColorTransform.In); + } catch (CMMException e) { + transforms[0] = mdl.createTransform(thisProfile, + ColorTransform.Any, ColorTransform.In); + } + transforms[1] = mdl.createTransform(xyz.getProfile(), + ColorTransform.Any, ColorTransform.Out); + if (needScaleInit) { + setComponentScaling(); + } + this2xyz = mdl.createTransform(transforms); + } } } @@ -511,26 +517,28 @@ public float[] toCIEXYZ(float[] colorvalue) { * this {@code ColorSpace} * @throws ArrayIndexOutOfBoundsException if array length is not at least 3 */ - public float[] fromCIEXYZ(float[] colorvalue) { - + public float[] fromCIEXYZ(float[] colorvalue) { if (xyz2this == null) { - ColorTransform[] transformList = new ColorTransform [2]; - ICC_ColorSpace xyzCS = - (ICC_ColorSpace) ColorSpace.getInstance (CS_CIEXYZ); - PCMM mdl = CMSManager.getModule(); - transformList[0] = mdl.createTransform ( - xyzCS.getProfile(), ColorTransform.Any, ColorTransform.In); - try { - transformList[1] = mdl.createTransform( - thisProfile, ICC_Profile.icRelativeColorimetric, - ColorTransform.Out); - } catch (CMMException e) { - transformList[1] = CMSManager.getModule().createTransform( - thisProfile, ColorTransform.Any, ColorTransform.Out); - } - xyz2this = mdl.createTransform(transformList); - if (needScaleInit) { - setComponentScaling(); + synchronized (this) { + if (xyz2this == null) { + ColorTransform[] transforms = new ColorTransform[2]; + var xyz = (ICC_ColorSpace) getInstance(CS_CIEXYZ); + PCMM mdl = CMSManager.getModule(); + transforms[0] = mdl.createTransform(xyz.getProfile(), + ColorTransform.Any, ColorTransform.In); + try { + transforms[1] = mdl.createTransform(thisProfile, + ICC_Profile.icRelativeColorimetric, + ColorTransform.Out); + } catch (CMMException e) { + transforms[1] = mdl.createTransform(thisProfile, + ColorTransform.Any, ColorTransform.Out); + } + if (needScaleInit) { + setComponentScaling(); + } + xyz2this = mdl.createTransform(transforms); + } } } diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java index 1ccfa05818e..b4e38a25c7e 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_Profile.java @@ -831,8 +831,6 @@ else if ((getColorSpaceType (p) == ColorSpace.TYPE_RGB) && */ public static ICC_Profile getInstance (int cspace) { ICC_Profile thisProfile = null; - String fileName; - switch (cspace) { case ColorSpace.CS_sRGB: synchronized(ICC_Profile.class) { @@ -870,17 +868,11 @@ public static ICC_Profile getInstance (int cspace) { case ColorSpace.CS_PYCC: synchronized(ICC_Profile.class) { if (PYCCprofile == null) { - if (standardProfileExists("PYCC.pf")) - { - ProfileDeferralInfo pInfo = - new ProfileDeferralInfo("PYCC.pf", - ColorSpace.TYPE_3CLR, 3, - CLASS_DISPLAY); - PYCCprofile = getDeferredInstance(pInfo); - } else { - throw new IllegalArgumentException( - "Can't load standard profile: PYCC.pf"); - } + ProfileDeferralInfo pInfo = + new ProfileDeferralInfo("PYCC.pf", + ColorSpace.TYPE_3CLR, 3, + CLASS_DISPLAY); + PYCCprofile = getDeferredInstance(pInfo); } thisProfile = PYCCprofile; } @@ -1851,17 +1843,6 @@ private static boolean isChildOf(File f, String dirName) { } } - /** - * Checks whether built-in profile specified by fileName exists. - */ - private static boolean standardProfileExists(final String fileName) { - return AccessController.doPrivileged(new PrivilegedAction() { - public Boolean run() { - return PCMM.class.getResource("profiles/"+fileName) != null; - } - }); - } - /* * Serialization support. * diff --git a/src/java.desktop/share/classes/java/awt/peer/RobotPeer.java b/src/java.desktop/share/classes/java/awt/peer/RobotPeer.java index 4c77e193073..10a901817a2 100644 --- a/src/java.desktop/share/classes/java/awt/peer/RobotPeer.java +++ b/src/java.desktop/share/classes/java/awt/peer/RobotPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -117,4 +117,14 @@ public interface RobotPeer * @see Robot#createScreenCapture(Rectangle) */ int[] getRGBPixels(Rectangle bounds); + + /** + * Determines if absolute coordinates should be used by this peer. + * + * @return {@code true} if absolute coordinates should be used, + * {@code false} otherwise + */ + default boolean useAbsoluteCoordinates() { + return false; + } } diff --git a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java index 9dcb5d5ece8..db8b71e3b2c 100644 --- a/src/java.desktop/share/classes/javax/swing/SwingUtilities.java +++ b/src/java.desktop/share/classes/javax/swing/SwingUtilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,6 @@ /** * A collection of utility methods for Swing. * - * @author unknown * @since 1.2 */ public class SwingUtilities implements SwingConstants diff --git a/src/java.desktop/share/classes/javax/swing/UnsupportedLookAndFeelException.java b/src/java.desktop/share/classes/javax/swing/UnsupportedLookAndFeelException.java index a82c97d9940..02910664ea5 100644 --- a/src/java.desktop/share/classes/javax/swing/UnsupportedLookAndFeelException.java +++ b/src/java.desktop/share/classes/javax/swing/UnsupportedLookAndFeelException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,6 @@ * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. * - * @author unattributed * @since 1.2 */ @SuppressWarnings("serial") // Same-version serialization only diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java index 8c709c72070..d893f62bbd1 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -100,8 +100,6 @@ * of all JavaBeans * has been added to the java.beans package. * Please see {@link java.beans.XMLEncoder}. - * - * @author unattributed */ @SuppressWarnings("serial") // Same-version serialization only public abstract class BasicLookAndFeel extends LookAndFeel implements Serializable diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java index 243d465ac3e..a26f0511432 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicPopupMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1226,6 +1226,7 @@ public void stateChanged(ChangeEvent ev) { // menu hidden -- return focus to where it had been before // and uninstall menu keybindings removeItems(); + menuInputMap = null; } else { if (popup != lastPopup) { receivedKeyPressed = false; diff --git a/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java b/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java index 0f3f195fb19..c5ce7ebd315 100644 --- a/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java +++ b/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java @@ -27,6 +27,7 @@ import java.awt.AWTError; import java.awt.Color; +import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; @@ -349,53 +350,124 @@ public static GraphicsConfiguration getGraphicsConfigurationAtPoint( } /** - * Converts coordinates from the user's space to the device space using - * appropriate device transformation. + * Returns the bounds of the graphics configuration in device space. + * + * @param config the graphics configuration which bounds are requested + * @return the bounds of the area covered by this + * {@code GraphicsConfiguration} in device space (pixels) + */ + public static Rectangle getGCDeviceBounds(GraphicsConfiguration config) { + AffineTransform tx = config.getDefaultTransform(); + Rectangle bounds = config.getBounds(); + bounds.width *= tx.getScaleX(); + bounds.height *= tx.getScaleY(); + return bounds; + } + + /** + * Converts the size (w, h) from the device space to the user's space using + * passed graphics configuration. + * + * @param gc the graphics configuration to be used for transformation + * @param w the width in the device space + * @param h the height in the device space + * @return the size in the user's space + */ + public static Dimension toUserSpace(GraphicsConfiguration gc, + int w, int h) { + AffineTransform tx = gc.getDefaultTransform(); + return new Dimension( + Region.clipRound(w / tx.getScaleX()), + Region.clipRound(h / tx.getScaleY()) + ); + } + + /** + * Converts absolute coordinates from the user's space to the device space + * using appropriate device transformation. * - * @param x coordinate in the user space - * @param y coordinate in the user space - * @return the point which uses device space(pixels) + * @param x absolute coordinate in the user's space + * @param y absolute coordinate in the user's space + * @return the point which uses device space (pixels) */ - public static Point convertToDeviceSpace(double x, double y) { + public static Point toDeviceSpaceAbs(int x, int y) { GraphicsConfiguration gc = getLocalGraphicsEnvironment() - .getDefaultScreenDevice().getDefaultConfiguration(); + .getDefaultScreenDevice().getDefaultConfiguration(); gc = getGraphicsConfigurationAtPoint(gc, x, y); + return toDeviceSpaceAbs(gc, x, y, 0, 0).getLocation(); + } + /** + * Converts the rectangle from the user's space to the device space using + * appropriate device transformation. + * + * @param rect the rectangle in the user's space + * @return the rectangle which uses device space (pixels) + */ + public static Rectangle toDeviceSpaceAbs(Rectangle rect) { + GraphicsConfiguration gc = getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + gc = getGraphicsConfigurationAtPoint(gc, rect.x, rect.y); + return toDeviceSpaceAbs(gc, rect.x, rect.y, rect.width, rect.height); + } + + /** + * Converts absolute coordinates (x, y) and the size (w, h) from the user's + * space to the device space using passed graphics configuration. + * + * @param gc the graphics configuration to be used for transformation + * @param x absolute coordinate in the user's space + * @param y absolute coordinate in the user's space + * @param w the width in the user's space + * @param h the height in the user's space + * @return the rectangle which uses device space (pixels) + */ + public static Rectangle toDeviceSpaceAbs(GraphicsConfiguration gc, + int x, int y, int w, int h) { AffineTransform tx = gc.getDefaultTransform(); - x = Region.clipRound(x * tx.getScaleX()); - y = Region.clipRound(y * tx.getScaleY()); - return new Point((int) x, (int) y); + Rectangle screen = gc.getBounds(); + return new Rectangle( + screen.x + Region.clipRound((x - screen.x) * tx.getScaleX()), + screen.y + Region.clipRound((y - screen.y) * tx.getScaleY()), + Region.clipRound(w * tx.getScaleX()), + Region.clipRound(h * tx.getScaleY()) + ); } /** - * Converts bounds from the user's space to the device space using + * Converts coordinates from the user's space to the device space using * appropriate device transformation. * - * @param bounds the rectangle in the user space - * @return the rectangle which uses device space(pixels) + * @param x coordinate in the user's space + * @param y coordinate in the user's space + * @return the point which uses device space (pixels) */ - public static Rectangle convertToDeviceSpace(Rectangle bounds) { + public static Point toDeviceSpace(int x, int y) { GraphicsConfiguration gc = getLocalGraphicsEnvironment() .getDefaultScreenDevice().getDefaultConfiguration(); - gc = getGraphicsConfigurationAtPoint(gc, bounds.x, bounds.y); - return convertToDeviceSpace(gc, bounds); + gc = getGraphicsConfigurationAtPoint(gc, x, y); + return toDeviceSpace(gc, x, y, 0, 0).getLocation(); } /** - * Converts bounds from the user's space to the device space using - * appropriate device transformation of the passed graphics configuration. + * Converts coordinates (x, y) and the size (w, h) from the user's + * space to the device space using passed graphics configuration. * - * @param bounds the rectangle in the user space - * @return the rectangle which uses device space(pixels) + * @param gc the graphics configuration to be used for transformation + * @param x coordinate in the user's space + * @param y coordinate in the user's space + * @param w the width in the user's space + * @param h the height in the user's space + * @return the rectangle which uses device space (pixels) */ - public static Rectangle convertToDeviceSpace(GraphicsConfiguration gc, - Rectangle bounds) { + public static Rectangle toDeviceSpace(GraphicsConfiguration gc, + int x, int y, int w, int h) { AffineTransform tx = gc.getDefaultTransform(); return new Rectangle( - Region.clipRound(bounds.x * tx.getScaleX()), - Region.clipRound(bounds.y * tx.getScaleY()), - Region.clipRound(bounds.width * tx.getScaleX()), - Region.clipRound(bounds.height * tx.getScaleY()) + Region.clipRound(x * tx.getScaleX()), + Region.clipRound(y * tx.getScaleY()), + Region.clipRound(w * tx.getScaleX()), + Region.clipRound(h * tx.getScaleY()) ); } } diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/CMSManager.java b/src/java.desktop/share/classes/sun/java2d/cmm/CMSManager.java index fea14af51ed..4d9f09c5905 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/CMSManager.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/CMSManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,14 +25,11 @@ package sun.java2d.cmm; +import java.awt.color.CMMException; import java.awt.color.ColorSpace; import java.awt.color.ICC_Profile; -import java.awt.color.CMMException; -import java.awt.image.BufferedImage; -import java.awt.image.Raster; -import java.awt.image.WritableRaster; import java.security.AccessController; -import java.security.PrivilegedAction; + import sun.security.action.GetPropertyAction; public class CMSManager { @@ -103,11 +100,6 @@ public Profile loadProfile(byte[] data) { return p; } - public void freeProfile(Profile p) { - System.err.printf(cName + ".freeProfile(ID=%s)\n", p.toString()); - tcmm.freeProfile(p); - } - public int getProfileSize(Profile p) { System.err.print(cName + ".getProfileSize(ID=" + p + ")"); int size = tcmm.getProfileSize(p); diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/PCMM.java b/src/java.desktop/share/classes/sun/java2d/cmm/PCMM.java index d147f0a42dc..0526abafeca 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/PCMM.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/PCMM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ public interface PCMM { /* methods invoked from ICC_Profile */ public Profile loadProfile(byte[] data); - public void freeProfile(Profile p); public int getProfileSize(Profile p); public void getProfileData(Profile p, byte[] data); public void getTagData(Profile p, int tagSignature, byte[] data); diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java b/src/java.desktop/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java index 49b6808baa4..d19b6f6da68 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/ProfileDeferralMgr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,23 +59,6 @@ public static void registerDeferral(ProfileActivator pa) { } - /** - * Removes a ProfileActivator object from the vector of ProfileActivator - * objects whose activate method will be called if the CMM needs to be - * activated. - */ - public static void unregisterDeferral(ProfileActivator pa) { - - if (!deferring) { - return; - } - if (aVector == null) { - return; - } - aVector.removeElement(pa); - return; - } - /** * Removes a ProfileActivator object from the vector of ProfileActivator * objects whose activate method will be called if the CMM needs to be diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java index a9e6adbbed9..32232d02798 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,6 +27,7 @@ import java.awt.color.CMMException; import java.awt.color.ICC_Profile; + import sun.java2d.cmm.ColorTransform; import sun.java2d.cmm.PCMM; import sun.java2d.cmm.Profile; @@ -56,12 +57,6 @@ private LCMSProfile getLcmsProfile(Profile p) { throw new CMMException("Invalid profile: " + p); } - - @Override - public void freeProfile(Profile p) { - // we use disposer, so this method does nothing - } - @Override public int getProfileSize(final Profile p) { synchronized (p) { diff --git a/src/java.desktop/share/legal/harfbuzz.md b/src/java.desktop/share/legal/harfbuzz.md index 16698bc86ac..465bcf5be3c 100644 --- a/src/java.desktop/share/legal/harfbuzz.md +++ b/src/java.desktop/share/legal/harfbuzz.md @@ -1,16 +1,18 @@ -## Harfbuzz v2.3.1 +## Harfbuzz v2.7.2 ### Harfbuzz License -http://cgit.freedesktop.org/harfbuzz/tree/COPYING +https://github.com/harfbuzz/harfbuzz/blob/master/COPYING

     
    -HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
    +HarfBuzz is licensed under the so-called "Old MIT" license.  Details follow.
     For parts of HarfBuzz that are licensed under different licenses see individual
     files names COPYING in subdirectories where applicable.
     
    -Copyright © 2010,2011,2012  Google, Inc.
    +Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020  Google, Inc.
    +Copyright © 2018,2019,2020  Ebrahim Byagowi
    +Copyright © 2019,2020  Facebook, Inc. 
     Copyright © 2012  Mozilla Foundation
     Copyright © 2011  Codethink Limited
     Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-fdsc-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-fdsc-table.hh
    deleted file mode 100644
    index 4ee7353346d..00000000000
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-fdsc-table.hh
    +++ /dev/null
    @@ -1,126 +0,0 @@
    -/*
    - * Copyright © 2018  Ebrahim Byagowi
    - *
    - *  This is part of HarfBuzz, a text shaping library.
    - *
    - * Permission is hereby granted, without written agreement and without
    - * license or royalty fees, to use, copy, modify, and distribute this
    - * software and its documentation for any purpose, provided that the
    - * above copyright notice and the following two paragraphs appear in
    - * all copies of this software.
    - *
    - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    - * DAMAGE.
    - *
    - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    - * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    - */
    -
    -#ifndef HB_AAT_FDSC_TABLE_HH
    -#define HB_AAT_FDSC_TABLE_HH
    -
    -#include "hb-aat-layout-common.hh"
    -#include "hb-open-type.hh"
    -
    -/*
    - * fdsc -- Font descriptors
    - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fdsc.html
    - */
    -#define HB_AAT_TAG_fdsc HB_TAG('f','d','s','c')
    -
    -
    -namespace AAT {
    -
    -
    -struct FontDescriptor
    -{
    -  bool has_data () const { return tag; }
    -
    -  int cmp (hb_tag_t a) const { return tag.cmp (a); }
    -
    -  float get_value () const { return u.value.to_float (); }
    -
    -  enum non_alphabetic_value_t {
    -    Alphabetic          = 0,
    -    Dingbats            = 1,
    -    PiCharacters        = 2,
    -    Fleurons            = 3,
    -    DecorativeBorders   = 4,
    -    InternationalSymbols= 5,
    -    MathSymbols         = 6
    -  };
    -
    -  bool sanitize (hb_sanitize_context_t *c) const
    -  {
    -    TRACE_SANITIZE (this);
    -    return_trace (c->check_struct (this));
    -  }
    -
    -  protected:
    -  Tag           tag;            /* The 4-byte table tag name. */
    -  union {
    -  Fixed         value;          /* The value for the descriptor tag. */
    -  HBUINT32      nalfType;       /* If the tag is `nalf`, see non_alphabetic_value_t */
    -  } u;
    -  public:
    -  DEFINE_SIZE_STATIC (8);
    -};
    -
    -struct fdsc
    -{
    -  static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
    -
    -  enum {
    -    Weight       = HB_TAG ('w','g','h','t'),
    -                                /* Percent weight relative to regular weight.
    -                                 * (defaul value: 1.0) */
    -    Width        = HB_TAG ('w','d','t','h'),
    -                                /* Percent width relative to regular width.
    -                                 * (default value: 1.0) */
    -    Slant        = HB_TAG ('s','l','n','t'),
    -                                /* Angle of slant in degrees, where positive
    -                                 * is clockwise from straight up.
    -                                 * (default value: 0.0) */
    -    OpticalSize  = HB_TAG ('o','p','s','z'),
    -                                /* Point size the font was designed for.
    -                                 * (default value: 12.0) */
    -    NonAlphabetic= HB_TAG ('n','a','l','f')
    -                                /* These values are treated as integers,
    -                                 * not fixed32s. 0 means alphabetic, and greater
    -                                 * integers mean the font is non-alphabetic (e.g. symbols).
    -                                 * (default value: 0) */
    -  };
    -
    -  const FontDescriptor &get_descriptor (hb_tag_t style) const
    -  { return descriptors.lsearch (style); }
    -
    -  bool sanitize (hb_sanitize_context_t *c) const
    -  {
    -    TRACE_SANITIZE (this);
    -    return_trace (c->check_struct (this) &&
    -                  descriptors.sanitize (c));
    -  }
    -
    -  protected:
    -  Fixed         version;        /* Version number of the font descriptors
    -                                 * table (0x00010000 for the current version). */
    -  LArrayOf
    -                descriptors;    /* List of tagged-coordinate pairs style descriptors
    -                                 * that will be included to characterize this font.
    -                                 * Each descriptor consists of a  pair.
    -                                 * These pairs are located in the gxFontDescriptor
    -                                 * array that follows. */
    -  public:
    -  DEFINE_SIZE_ARRAY (8, descriptors);
    -};
    -
    -} /* namespace AAT */
    -
    -
    -#endif /* HB_AAT_FDSC_TABLE_HH */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-ankr-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-ankr-table.hh
    index f8495f384b9..90dd949a50a 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-ankr-table.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-ankr-table.hh
    @@ -66,7 +66,7 @@ struct ankr
       {
         const NNOffsetTo *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
         if (!offset)
    -      return Null(Anchor);
    +      return Null (Anchor);
         const GlyphAnchors &anchors = &(this+anchorData) + *offset;
         return anchors[i];
       }
    @@ -76,13 +76,14 @@ struct ankr
         TRACE_SANITIZE (this);
         return_trace (likely (c->check_struct (this) &&
                               version == 0 &&
    +                          c->check_range (this, anchorData) &&
                               lookupTable.sanitize (c, this, &(this+anchorData))));
       }
     
       protected:
       HBUINT16      version;        /* Version number (set to zero) */
       HBUINT16      flags;          /* Flags (currently unused; set to zero) */
    -  LOffsetTo > >
    +  LOffsetTo>>
                     lookupTable;    /* Offset to the table's lookup table */
       LNNOffsetTo
                     anchorData;     /* Offset to the glyph data table */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh
    index 746da3ae5bc..7dcf1c3bd9d 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh
    @@ -82,7 +82,7 @@ struct BaselineTableFormat2Part
       }
     
       protected:
    -  GlyphID       stdGlyph;       /* The specific glyph index number in this
    +  HBGlyphID     stdGlyph;       /* The specific glyph index number in this
                                      * font that is used to set the baseline values.
                                      * This is the standard glyph.
                                      * This glyph must contain a set of control points
    @@ -101,11 +101,11 @@ struct BaselineTableFormat3Part
       bool sanitize (hb_sanitize_context_t *c) const
       {
         TRACE_SANITIZE (this);
    -    return_trace (c->check_struct (this) && lookupTable.sanitize (c));
    +    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c)));
       }
     
       protected:
    -  GlyphID       stdGlyph;       /* ditto */
    +  HBGlyphID     stdGlyph;       /* ditto */
       HBUINT16      ctlPoints[32];  /* ditto */
       Lookup
                     lookupTable;    /* Lookup table that maps glyphs to their
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh
    index 7c8e3cec16f..e1dcd6f7102 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh
    @@ -93,8 +93,8 @@ struct LookupSegmentSingle
         return_trace (c->check_struct (this) && value.sanitize (c, base));
       }
     
    -  GlyphID       last;           /* Last GlyphID in this segment */
    -  GlyphID       first;          /* First GlyphID in this segment */
    +  HBGlyphID     last;           /* Last GlyphID in this segment */
    +  HBGlyphID     first;          /* First GlyphID in this segment */
       T             value;          /* The lookup value (only one) */
       public:
       DEFINE_SIZE_STATIC (4 + T::static_size);
    @@ -125,7 +125,7 @@ struct LookupFormat2
     
       protected:
       HBUINT16      format;         /* Format identifier--format = 2 */
    -  VarSizedBinSearchArrayOf >
    +  VarSizedBinSearchArrayOf>
                     segments;       /* The actual segments. These must already be sorted,
                                      * according to the first word in each one (the last
                                      * glyph in each segment). */
    @@ -153,18 +153,18 @@ struct LookupSegmentArray
                       first <= last &&
                       valuesZ.sanitize (c, base, last - first + 1));
       }
    -  template 
    -  bool sanitize (hb_sanitize_context_t *c, const void *base, T2 user_data) const
    +  template 
    +  bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
       {
         TRACE_SANITIZE (this);
         return_trace (c->check_struct (this) &&
                       first <= last &&
    -                  valuesZ.sanitize (c, base, last - first + 1, user_data));
    +                  valuesZ.sanitize (c, base, last - first + 1, hb_forward (ds)...));
       }
     
    -  GlyphID       last;           /* Last GlyphID in this segment */
    -  GlyphID       first;          /* First GlyphID in this segment */
    -  NNOffsetTo >
    +  HBGlyphID     last;           /* Last GlyphID in this segment */
    +  HBGlyphID     first;          /* First GlyphID in this segment */
    +  NNOffsetTo>
                     valuesZ;        /* A 16-bit offset from the start of
                                      * the table to the data. */
       public:
    @@ -196,7 +196,7 @@ struct LookupFormat4
     
       protected:
       HBUINT16      format;         /* Format identifier--format = 4 */
    -  VarSizedBinSearchArrayOf >
    +  VarSizedBinSearchArrayOf>
                     segments;       /* The actual segments. These must already be sorted,
                                      * according to the first word in each one (the last
                                      * glyph in each segment). */
    @@ -222,7 +222,7 @@ struct LookupSingle
         return_trace (c->check_struct (this) && value.sanitize (c, base));
       }
     
    -  GlyphID       glyph;          /* Last GlyphID */
    +  HBGlyphID     glyph;          /* Last GlyphID */
       T             value;          /* The lookup value (only one) */
       public:
       DEFINE_SIZE_STATIC (2 + T::static_size);
    @@ -253,7 +253,7 @@ struct LookupFormat6
     
       protected:
       HBUINT16      format;         /* Format identifier--format = 6 */
    -  VarSizedBinSearchArrayOf >
    +  VarSizedBinSearchArrayOf>
                     entries;        /* The actual entries, sorted by glyph index. */
       public:
       DEFINE_SIZE_ARRAY (8, entries);
    @@ -284,7 +284,7 @@ struct LookupFormat8
     
       protected:
       HBUINT16      format;         /* Format identifier--format = 8 */
    -  GlyphID       firstGlyph;     /* First glyph index included in the trimmed array. */
    +  HBGlyphID     firstGlyph;     /* First glyph index included in the trimmed array. */
       HBUINT16      glyphCount;     /* Total number of glyphs (equivalent to the last
                                      * glyph minus the value of firstGlyph plus 1). */
       UnsizedArrayOf
    @@ -303,7 +303,7 @@ struct LookupFormat10
       const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
       {
         if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
    -      return Null(T);
    +      return Null (T);
     
         const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
     
    @@ -326,7 +326,7 @@ struct LookupFormat10
       protected:
       HBUINT16      format;         /* Format identifier--format = 8 */
       HBUINT16      valueSize;      /* Byte size of each value. */
    -  GlyphID       firstGlyph;     /* First glyph index included in the trimmed array. */
    +  HBGlyphID     firstGlyph;     /* First glyph index included in the trimmed array. */
       HBUINT16      glyphCount;     /* Total number of glyphs (equivalent to the last
                                      * glyph minus the value of firstGlyph plus 1). */
       UnsizedArrayOf
    @@ -358,7 +358,7 @@ struct Lookup
           case 10: return u.format10.get_value_or_null (glyph_id);
           default:
           const T *v = get_value (glyph_id, num_glyphs);
    -      return v ? *v : Null(T);
    +      return v ? *v : Null (T);
         }
       }
     
    @@ -418,15 +418,11 @@ struct Lookup
     } /* Close namespace. */
     /* Ugly hand-coded null objects for template Lookup<> :(. */
     extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
    -template <>
    -/*static*/ inline const AAT::Lookup& Null > ()
    -{ return *reinterpret_cast *> (_hb_Null_AAT_Lookup); }
    -template <>
    -/*static*/ inline const AAT::Lookup& Null > ()
    -{ return *reinterpret_cast *> (_hb_Null_AAT_Lookup); }
    -template <>
    -/*static*/ inline const AAT::Lookup >& Null > > ()
    -{ return *reinterpret_cast > *> (_hb_Null_AAT_Lookup); }
    +template 
    +struct Null> {
    +  static AAT::Lookup const & get_null ()
    +  { return *reinterpret_cast *> (_hb_Null_AAT_Lookup); }
    +};
     namespace AAT {
     
     enum { DELETED_GLYPH = 0xFFFF };
    @@ -514,7 +510,7 @@ struct StateTable
       const Entry &get_entry (int state, unsigned int klass) const
       {
         if (unlikely (klass >= nClasses))
    -      klass = StateTable >::CLASS_OUT_OF_BOUNDS;
    +      klass = StateTable>::CLASS_OUT_OF_BOUNDS;
     
         const HBUSHORT *states = (this+stateArrayTable).arrayZ;
         const Entry *entries = (this+entryTable).arrayZ;
    @@ -580,7 +576,7 @@ struct StateTable
               if (unlikely (stop > states))
                 return_trace (false);
               for (const HBUSHORT *p = states; stop < p; p--)
    -            num_entries = MAX (num_entries, *(p - 1) + 1);
    +            num_entries = hb_max (num_entries, *(p - 1) + 1);
               state_neg = min_state;
             }
           }
    @@ -601,7 +597,7 @@ struct StateTable
               if (unlikely (stop < states))
                 return_trace (false);
               for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
    -            num_entries = MAX (num_entries, *p + 1);
    +            num_entries = hb_max (num_entries, *p + 1);
               state_pos = max_state + 1;
             }
           }
    @@ -615,8 +611,8 @@ struct StateTable
             for (const Entry *p = &entries[entry]; p < stop; p++)
             {
               int newState = new_state (p->newState);
    -          min_state = MIN (min_state, newState);
    -          max_state = MAX (max_state, newState);
    +          min_state = hb_min (min_state, newState);
    +          max_state = hb_max (max_state, newState);
             }
             entry = num_entries;
           }
    @@ -635,7 +631,7 @@ struct StateTable
                     classTable;     /* Offset to the class table. */
       NNOffsetTo, HBUINT>
                     stateArrayTable;/* Offset to the state array. */
    -  NNOffsetTo >, HBUINT>
    +  NNOffsetTo>, HBUINT>
                     entryTable;     /* Offset to the entry array. */
     
       public:
    @@ -662,7 +658,7 @@ struct ClassTable
         return_trace (c->check_struct (this) && classArray.sanitize (c));
       }
       protected:
    -  GlyphID               firstGlyph;     /* First glyph index included in the trimmed array. */
    +  HBGlyphID             firstGlyph;     /* First glyph index included in the trimmed array. */
       ArrayOf      classArray;     /* The class codes (indexed by glyph index minus
                                              * firstGlyph). */
       public:
    @@ -682,7 +678,7 @@ struct ObsoleteTypes
                                          const void *base,
                                          const T *array)
       {
    -    return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
    +    return (offset - ((const char *) array - (const char *) base)) / T::static_size;
       }
       template 
       static unsigned int byteOffsetToIndex (unsigned int offset,
    @@ -824,12 +820,11 @@ struct hb_aat_apply_context_t :
     
       /* Unused. For debug tracing only. */
       unsigned int lookup_index;
    -  unsigned int debug_depth;
     
       HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
                                           hb_font_t *font_,
                                           hb_buffer_t *buffer_,
    -                                      hb_blob_t *blob = const_cast (&Null(hb_blob_t)));
    +                                      hb_blob_t *blob = const_cast (&Null (hb_blob_t)));
     
       HB_INTERNAL ~hb_aat_apply_context_t ();
     
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh
    index 910a94f0bc3..06c48d2f64a 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh
    @@ -47,17 +47,16 @@ struct SettingName
       hb_aat_layout_feature_selector_t get_selector () const
       { return (hb_aat_layout_feature_selector_t) (unsigned) setting; }
     
    -  void get_info (hb_aat_layout_feature_selector_info_t *s,
    -                        hb_aat_layout_feature_selector_t default_selector) const
    +  hb_aat_layout_feature_selector_info_t get_info (hb_aat_layout_feature_selector_t default_selector) const
       {
    -    s->name_id = nameIndex;
    -
    -    s->enable = (hb_aat_layout_feature_selector_t) (unsigned int) setting;
    -    s->disable = default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID ?
    -                 (hb_aat_layout_feature_selector_t) (s->enable + 1) :
    -                 default_selector;
    -
    -    s->reserved = 0;
    +    return {
    +      nameIndex,
    +      (hb_aat_layout_feature_selector_t) (unsigned int) setting,
    +      default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID
    +        ? (hb_aat_layout_feature_selector_t) (setting + 1)
    +        : default_selector,
    +      0
    +    };
       }
     
       bool sanitize (hb_sanitize_context_t *c) const
    @@ -117,9 +116,10 @@ struct FeatureName
     
         if (selectors_count)
         {
    -      hb_array_t arr = settings_table.sub_array (start_offset, selectors_count);
    -      for (unsigned int i = 0; i < arr.length; i++)
    -        settings_table[start_offset + i].get_info (&selectors[i], default_selector);
    +      + settings_table.sub_array (start_offset, selectors_count)
    +      | hb_map ([=] (const SettingName& setting) { return setting.get_info (default_selector); })
    +      | hb_sink (hb_array (selectors, *selectors_count))
    +      ;
         }
         return settings_table.length;
       }
    @@ -129,6 +129,11 @@ struct FeatureName
     
       hb_ot_name_id_t get_feature_name_id () const { return nameIndex; }
     
    +  bool is_exclusive () const { return featureFlags & Exclusive; }
    +
    +  /* A FeatureName with no settings is meaningless */
    +  bool has_data () const { return nSettings; }
    +
       bool sanitize (hb_sanitize_context_t *c, const void *base) const
       {
         TRACE_SANITIZE (this);
    @@ -139,7 +144,7 @@ struct FeatureName
       protected:
       HBUINT16      feature;        /* Feature type. */
       HBUINT16      nSettings;      /* The number of records in the setting name array. */
    -  LOffsetTo, false>
    +  LNNOffsetTo>
                     settingTableZ;  /* Offset in bytes from the beginning of this table to
                                      * this feature's setting name array. The actual type of
                                      * record this offset refers to will depend on the
    @@ -162,21 +167,21 @@ struct feat
                                       unsigned int                 *count,
                                       hb_aat_layout_feature_type_t *features) const
       {
    -    unsigned int feature_count = featureNameCount;
    -    if (count && *count)
    +    if (count)
         {
    -      unsigned int len = MIN (feature_count - start_offset, *count);
    -      for (unsigned int i = 0; i < len; i++)
    -        features[i] = namesZ[i + start_offset].get_feature_type ();
    -      *count = len;
    +      + namesZ.as_array (featureNameCount).sub_array (start_offset, count)
    +      | hb_map (&FeatureName::get_feature_type)
    +      | hb_sink (hb_array (features, *count))
    +      ;
         }
         return featureNameCount;
       }
     
    +  bool exposes_feature (hb_aat_layout_feature_type_t feature_type) const
    +  { return get_feature (feature_type).has_data (); }
    +
       const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const
    -  {
    -    return namesZ.bsearch (featureNameCount, feature_type);
    -  }
    +  { return namesZ.bsearch (featureNameCount, feature_type); }
     
       hb_ot_name_id_t get_feature_name_id (hb_aat_layout_feature_type_t feature) const
       { return get_feature (feature).get_feature_name_id (); }
    @@ -209,7 +214,7 @@ struct feat
       SortedUnsizedArrayOf
                     namesZ;         /* The feature name array. */
       public:
    -  DEFINE_SIZE_STATIC (24);
    +  DEFINE_SIZE_ARRAY (12, namesZ);
     };
     
     } /* namespace AAT */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh
    index c3817ea0b9c..7ebd6a5ec5e 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh
    @@ -70,9 +70,9 @@ struct DecompositionAction
     
       ActionSubrecordHeader
                     header;
    -  Fixed         lowerLimit;     /* If the distance factor is less than this value,
    +  HBFixed       lowerLimit;     /* If the distance factor is less than this value,
                                      * then the ligature is decomposed. */
    -  Fixed         upperLimit;     /* If the distance factor is greater than this value,
    +  HBFixed       upperLimit;     /* If the distance factor is greater than this value,
                                      * then the ligature is decomposed. */
       HBUINT16      order;          /* Numerical order in which this ligature will
                                      * be decomposed; you may want infrequent ligatures
    @@ -100,7 +100,7 @@ struct UnconditionalAddGlyphAction
       protected:
       ActionSubrecordHeader
                     header;
    -  GlyphID       addGlyph;       /* Glyph that should be added if the distance factor
    +  HBGlyphID     addGlyph;       /* Glyph that should be added if the distance factor
                                      * is growing. */
     
       public:
    @@ -118,14 +118,14 @@ struct ConditionalAddGlyphAction
       protected:
       ActionSubrecordHeader
                     header;
    -  Fixed         substThreshold; /* Distance growth factor (in ems) at which
    +  HBFixed       substThreshold; /* Distance growth factor (in ems) at which
                                      * this glyph is replaced and the growth factor
                                      * recalculated. */
    -  GlyphID       addGlyph;       /* Glyph to be added as kashida. If this value is
    +  HBGlyphID     addGlyph;       /* Glyph to be added as kashida. If this value is
                                      * 0xFFFF, no extra glyph will be added. Note that
                                      * generally when a glyph is added, justification
                                      * will need to be redone. */
    -  GlyphID       substGlyph;     /* Glyph to be substituted for this glyph if the
    +  HBGlyphID     substGlyph;     /* Glyph to be substituted for this glyph if the
                                      * growth factor equals or exceeds the value of
                                      * substThreshold. */
       public:
    @@ -146,13 +146,13 @@ struct DuctileGlyphAction
       HBUINT32      variationAxis;  /* The 4-byte tag identifying the ductile axis.
                                      * This would normally be 0x64756374 ('duct'),
                                      * but you may use any axis the font contains. */
    -  Fixed         minimumLimit;   /* The lowest value for the ductility axis tha
    +  HBFixed       minimumLimit;   /* The lowest value for the ductility axis tha
                                      * still yields an acceptable appearance. Normally
                                      * this will be 1.0. */
    -  Fixed         noStretchValue; /* This is the default value that corresponds to
    +  HBFixed       noStretchValue; /* This is the default value that corresponds to
                                      * no change in appearance. Normally, this will
                                      * be 1.0. */
    -  Fixed         maximumLimit;   /* The highest value for the ductility axis that
    +  HBFixed       maximumLimit;   /* The highest value for the ductility axis that
                                      * still yields an acceptable appearance. */
       public:
       DEFINE_SIZE_STATIC (22);
    @@ -170,7 +170,7 @@ struct RepeatedAddGlyphAction
       ActionSubrecordHeader
                     header;
       HBUINT16      flags;          /* Currently unused; set to 0. */
    -  GlyphID       glyph;          /* Glyph that should be added if the distance factor
    +  HBGlyphID     glyph;          /* Glyph that should be added if the distance factor
                                      * is growing. */
       public:
       DEFINE_SIZE_STATIC (10);
    @@ -271,14 +271,14 @@ struct JustWidthDeltaEntry
       };
     
       protected:
    -  Fixed         beforeGrowLimit;/* The ratio by which the advance width of the
    +  HBFixed       beforeGrowLimit;/* The ratio by which the advance width of the
                                      * glyph is permitted to grow on the left or top side. */
    -  Fixed         beforeShrinkLimit;
    +  HBFixed       beforeShrinkLimit;
                                     /* The ratio by which the advance width of the
                                      * glyph is permitted to shrink on the left or top side. */
    -  Fixed         afterGrowLimit; /* The ratio by which the advance width of the glyph
    +  HBFixed       afterGrowLimit; /* The ratio by which the advance width of the glyph
                                      * is permitted to shrink on the left or top side. */
    -  Fixed         afterShrinkLimit;
    +  HBFixed       afterShrinkLimit;
                                     /* The ratio by which the advance width of the glyph
                                      * is at most permitted to shrink on the right or
                                      * bottom side. */
    @@ -371,7 +371,7 @@ struct JustificationHeader
                                      * of postcompensation subtable (set to zero if none).
                                      *
                                      * The postcompensation subtable, if present in the font. */
    -  Lookup >
    +  Lookup>
                     lookupTable;    /* Lookup table associating glyphs with width delta
                                      * clusters. See the description of Width Delta Clusters
                                      * table for details on how to interpret the lookup values. */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh
    index b5519480e23..76e1da06f3e 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh
    @@ -82,8 +82,8 @@ struct KernPair
       }
     
       protected:
    -  GlyphID       left;
    -  GlyphID       right;
    +  HBGlyphID     left;
    +  HBGlyphID     right;
       FWORD         value;
       public:
       DEFINE_SIZE_STATIC (6);
    @@ -229,9 +229,7 @@ struct KerxSubTableFormat1
     
         bool is_actionable (StateTableDriver *driver HB_UNUSED,
                             const Entry &entry)
    -    {
    -      return Format1EntryT::performAction (entry);
    -    }
    +    { return Format1EntryT::performAction (entry); }
         void transition (StateTableDriver *driver,
                          const Entry &entry)
         {
    @@ -251,7 +249,7 @@ struct KerxSubTableFormat1
     
           if (Format1EntryT::performAction (entry) && depth)
           {
    -        unsigned int tuple_count = MAX (1u, table->header.tuple_count ());
    +        unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
     
             unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
             kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
    @@ -281,35 +279,28 @@ struct KerxSubTableFormat1
     
               hb_glyph_position_t &o = buffer->pos[idx];
     
    -          /* Testing shows that CoreText only applies kern (cross-stream or not)
    -           * if none has been applied by previous subtables.  That is, it does
    -           * NOT seem to accumulate as otherwise implied by specs. */
    -
    -          /* The following flag is undocumented in the spec, but described
    -           * in the 'kern' table example. */
    -          if (v == -0x8000)
    -          {
    -            o.attach_type() = ATTACH_TYPE_NONE;
    -            o.attach_chain() = 0;
    -            o.x_offset = o.y_offset = 0;
    -          }
    -          else if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
    +          if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
               {
                 if (crossStream)
                 {
    -              if (buffer->pos[idx].attach_type() && !buffer->pos[idx].y_offset)
    +              /* The following flag is undocumented in the spec, but described
    +               * in the 'kern' table example. */
    +              if (v == -0x8000)
                   {
    -                o.y_offset = c->font->em_scale_y (v);
    +                o.attach_type() = ATTACH_TYPE_NONE;
    +                o.attach_chain() = 0;
    +                o.y_offset = 0;
    +              }
    +              else if (o.attach_type())
    +              {
    +                o.y_offset += c->font->em_scale_y (v);
                     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
                   }
                 }
                 else if (buffer->info[idx].mask & kern_mask)
                 {
    -              if (!buffer->pos[idx].x_offset)
    -              {
    -                buffer->pos[idx].x_advance += c->font->em_scale_x (v);
    -                buffer->pos[idx].x_offset += c->font->em_scale_x (v);
    -              }
    +              o.x_advance += c->font->em_scale_x (v);
    +              o.x_offset += c->font->em_scale_x (v);
                 }
               }
               else
    @@ -317,19 +308,22 @@ struct KerxSubTableFormat1
                 if (crossStream)
                 {
                   /* CoreText doesn't do crossStream kerning in vertical.  We do. */
    -              if (buffer->pos[idx].attach_type() && !buffer->pos[idx].x_offset)
    +              if (v == -0x8000)
                   {
    -                o.x_offset = c->font->em_scale_x (v);
    +                o.attach_type() = ATTACH_TYPE_NONE;
    +                o.attach_chain() = 0;
    +                o.x_offset = 0;
    +              }
    +              else if (o.attach_type())
    +              {
    +                o.x_offset += c->font->em_scale_x (v);
                     buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
                   }
                 }
                 else if (buffer->info[idx].mask & kern_mask)
                 {
    -              if (!buffer->pos[idx].y_offset)
    -              {
    -                buffer->pos[idx].y_advance += c->font->em_scale_y (v);
    -                buffer->pos[idx].y_offset += c->font->em_scale_y (v);
    -              }
    +              o.y_advance += c->font->em_scale_y (v);
    +              o.y_offset += c->font->em_scale_y (v);
                 }
               }
             }
    @@ -392,7 +386,7 @@ struct KerxSubTableFormat2
     
         const UnsizedArrayOf &arrayZ = this+array;
         unsigned int kern_idx = l + r;
    -    kern_idx = Types::offsetToIndex (kern_idx, this, &arrayZ);
    +    kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
         const FWORD *v = &arrayZ[kern_idx];
         if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
     
    @@ -488,7 +482,7 @@ struct KerxSubTableFormat4
         };
     
         driver_context_t (const KerxSubTableFormat4 *table,
    -                             hb_aat_apply_context_t *c_) :
    +                      hb_aat_apply_context_t *c_) :
             c (c_),
             action_type ((table->flags & ActionType) >> 30),
             ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
    @@ -497,9 +491,7 @@ struct KerxSubTableFormat4
     
         bool is_actionable (StateTableDriver *driver HB_UNUSED,
                             const Entry &entry)
    -    {
    -      return entry.data.ankrActionIndex != 0xFFFF;
    -    }
    +    { return entry.data.ankrActionIndex != 0xFFFF; }
         void transition (StateTableDriver *driver,
                          const Entry &entry)
         {
    @@ -512,11 +504,13 @@ struct KerxSubTableFormat4
             {
               case 0: /* Control Point Actions.*/
               {
    -            /* indexed into glyph outline. */
    -            const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
    +            /* Indexed into glyph outline. */
    +            /* Each action (record in ankrData) contains two 16-bit fields, so we must
    +               double the ankrActionIndex to get the correct offset here. */
    +            const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
                 if (!c->sanitizer.check_array (data, 2)) return;
    -            HB_UNUSED unsigned int markControlPoint = *data++;
    -            HB_UNUSED unsigned int currControlPoint = *data++;
    +            unsigned int markControlPoint = *data++;
    +            unsigned int currControlPoint = *data++;
                 hb_position_t markX = 0;
                 hb_position_t markY = 0;
                 hb_position_t currX = 0;
    @@ -538,8 +532,10 @@ struct KerxSubTableFormat4
     
               case 1: /* Anchor Point Actions. */
               {
    -           /* Indexed into 'ankr' table. */
    -            const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
    +            /* Indexed into 'ankr' table. */
    +            /* Each action (record in ankrData) contains two 16-bit fields, so we must
    +               double the ankrActionIndex to get the correct offset here. */
    +            const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
                 if (!c->sanitizer.check_array (data, 2)) return;
                 unsigned int markAnchorPoint = *data++;
                 unsigned int currAnchorPoint = *data++;
    @@ -557,7 +553,9 @@ struct KerxSubTableFormat4
     
               case 2: /* Control Point Coordinate Actions. */
               {
    -            const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex];
    +            /* Each action contains four 16-bit fields, so we multiply the ankrActionIndex
    +               by 4 to get the correct offset for the given action. */
    +            const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
                 if (!c->sanitizer.check_array (data, 4)) return;
                 int markX = *data++;
                 int markY = *data++;
    @@ -628,7 +626,7 @@ struct KerxSubTableFormat6
       bool is_long () const { return flags & ValuesAreLong; }
     
       int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
    -                          hb_aat_apply_context_t *c) const
    +                   hb_aat_apply_context_t *c) const
       {
         unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
         if (is_long ())
    @@ -712,18 +710,18 @@ struct KerxSubTableFormat6
       {
         struct Long
         {
    -      LNNOffsetTo >            rowIndexTable;
    -      LNNOffsetTo >            columnIndexTable;
    -      LNNOffsetTo >     array;
    +      LNNOffsetTo>             rowIndexTable;
    +      LNNOffsetTo>             columnIndexTable;
    +      LNNOffsetTo>      array;
         } l;
         struct Short
         {
    -      LNNOffsetTo >            rowIndexTable;
    -      LNNOffsetTo >            columnIndexTable;
    -      LNNOffsetTo >       array;
    +      LNNOffsetTo>             rowIndexTable;
    +      LNNOffsetTo>             columnIndexTable;
    +      LNNOffsetTo>        array;
         } s;
       } u;
    -  LNNOffsetTo >   vector;
    +  LNNOffsetTo>    vector;
       public:
       DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
     };
    @@ -733,8 +731,8 @@ struct KerxSubTableHeader
     {
       typedef ExtendedTypes Types;
     
    -  unsigned int tuple_count () const { return tupleCount; }
    -  bool is_horizontal () const       { return !(coverage & Vertical); }
    +  unsigned   tuple_count () const { return tupleCount; }
    +  bool     is_horizontal () const { return !(coverage & Vertical); }
     
       enum Coverage
       {
    @@ -771,17 +769,17 @@ struct KerxSubTable
       unsigned int get_size () const { return u.header.length; }
       unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
     
    -  template 
    -  typename context_t::return_t dispatch (context_t *c) const
    +  template 
    +  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
       {
         unsigned int subtable_type = get_type ();
         TRACE_DISPATCH (this, subtable_type);
         switch (subtable_type) {
    -    case 0:     return_trace (c->dispatch (u.format0));
    -    case 1:     return_trace (c->dispatch (u.format1));
    -    case 2:     return_trace (c->dispatch (u.format2));
    -    case 4:     return_trace (c->dispatch (u.format4));
    -    case 6:     return_trace (c->dispatch (u.format6));
    +    case 0:     return_trace (c->dispatch (u.format0, hb_forward (ds)...));
    +    case 1:     return_trace (c->dispatch (u.format1, hb_forward (ds)...));
    +    case 2:     return_trace (c->dispatch (u.format2, hb_forward (ds)...));
    +    case 4:     return_trace (c->dispatch (u.format4, hb_forward (ds)...));
    +    case 6:     return_trace (c->dispatch (u.format6, hb_forward (ds)...));
         default:    return_trace (c->default_return_value ());
         }
       }
    @@ -891,7 +889,7 @@ struct KerxTable
           reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
                     HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
     
    -      if (!c->buffer->message (c->font, "start %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index))
    +      if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index))
             goto skip;
     
           if (!seenCrossStream &&
    @@ -923,7 +921,7 @@ struct KerxTable
           if (reverse)
             c->buffer->reverse ();
     
    -      (void) c->buffer->message (c->font, "end %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index);
    +      (void) c->buffer->message (c->font, "end subtable %d", c->lookup_index);
     
         skip:
           st = &StructAfter (*st);
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-lcar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-lcar-table.hh
    deleted file mode 100644
    index 58f1ee02fce..00000000000
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-lcar-table.hh
    +++ /dev/null
    @@ -1,93 +0,0 @@
    -/*
    - * Copyright © 2018  Ebrahim Byagowi
    - *
    - *  This is part of HarfBuzz, a text shaping library.
    - *
    - * Permission is hereby granted, without written agreement and without
    - * license or royalty fees, to use, copy, modify, and distribute this
    - * software and its documentation for any purpose, provided that the
    - * above copyright notice and the following two paragraphs appear in
    - * all copies of this software.
    - *
    - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    - * DAMAGE.
    - *
    - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    - * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    - */
    -#ifndef HB_AAT_LAYOUT_LCAR_TABLE_HH
    -#define HB_AAT_LAYOUT_LCAR_TABLE_HH
    -
    -#include "hb-open-type.hh"
    -#include "hb-aat-layout-common.hh"
    -
    -/*
    - * lcar -- Ligature caret
    - * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6lcar.html
    - */
    -#define HB_AAT_TAG_lcar HB_TAG('l','c','a','r')
    -
    -
    -namespace AAT {
    -
    -typedef ArrayOf LigCaretClassEntry;
    -
    -struct lcar
    -{
    -  static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
    -
    -  unsigned int get_lig_carets (hb_font_t      *font,
    -                               hb_direction_t  direction,
    -                               hb_codepoint_t  glyph,
    -                               unsigned int    start_offset,
    -                               unsigned int   *caret_count /* IN/OUT */,
    -                               hb_position_t  *caret_array /* OUT */) const
    -  {
    -    const OffsetTo* entry_offset = lookup.get_value (glyph,
    -                                                                         font->face->get_num_glyphs ());
    -    const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry);
    -    if (caret_count)
    -    {
    -      hb_array_t arr = array.sub_array (start_offset, caret_count);
    -      unsigned int count = arr.length;
    -      for (unsigned int i = 0; i < count; ++i)
    -        switch (format)
    -        {
    -        case 0: caret_array[i] = font->em_scale_dir (arr[i], direction); break;
    -        case 1:
    -          hb_position_t x, y;
    -          font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y);
    -          caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
    -          break;
    -        }
    -    }
    -    return array.len;
    -  }
    -
    -  bool sanitize (hb_sanitize_context_t *c) const
    -  {
    -    TRACE_SANITIZE (this);
    -    return_trace (likely (c->check_struct (this) &&
    -                          version.major == 1 &&
    -                          lookup.sanitize (c, this)));
    -  }
    -
    -  protected:
    -  FixedVersion<>version;        /* Version number of the ligature caret table */
    -  HBUINT16      format;         /* Format of the ligature caret table. */
    -  Lookup >
    -                lookup;         /* data Lookup table associating glyphs */
    -
    -  public:
    -  DEFINE_SIZE_MIN (8);
    -};
    -
    -} /* namespace AAT */
    -
    -#endif /* HB_AAT_LAYOUT_LCAR_TABLE_HH */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh
    index f52d2ab301b..a0d137836b1 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh
    @@ -88,7 +88,7 @@ struct RearrangementSubtable
             start = buffer->idx;
     
           if (flags & MarkLast)
    -        end = MIN (buffer->idx + 1, buffer->len);
    +        end = hb_min (buffer->idx + 1, buffer->len);
     
           if ((flags & Verb) && start < end)
           {
    @@ -117,14 +117,14 @@ struct RearrangementSubtable
             };
     
             unsigned int m = map[flags & Verb];
    -        unsigned int l = MIN (2, m >> 4);
    -        unsigned int r = MIN (2, m & 0x0F);
    +        unsigned int l = hb_min (2u, m >> 4);
    +        unsigned int r = hb_min (2u, m & 0x0F);
             bool reverse_l = 3 == (m >> 4);
             bool reverse_r = 3 == (m & 0x0F);
     
             if (end - start >= l + r)
             {
    -          buffer->merge_clusters (start, MIN (buffer->idx + 1, buffer->len));
    +          buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
               buffer->merge_clusters (start, end);
     
               hb_glyph_info_t *info = buffer->info;
    @@ -240,46 +240,46 @@ struct ContextualSubtable
           if (buffer->idx == buffer->len && !mark_set)
             return;
     
    -      const GlyphID *replacement;
    +      const HBGlyphID *replacement;
     
           replacement = nullptr;
           if (Types::extended)
           {
             if (entry.data.markIndex != 0xFFFF)
             {
    -          const Lookup &lookup = subs[entry.data.markIndex];
    +          const Lookup &lookup = subs[entry.data.markIndex];
               replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
             }
           }
           else
           {
             unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
    -        const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs;
    +        const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs;
             replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
             if (!replacement->sanitize (&c->sanitizer) || !*replacement)
               replacement = nullptr;
           }
           if (replacement)
           {
    -        buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
    +        buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
             buffer->info[mark].codepoint = *replacement;
             ret = true;
           }
     
           replacement = nullptr;
    -      unsigned int idx = MIN (buffer->idx, buffer->len - 1);
    +      unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
           if (Types::extended)
           {
             if (entry.data.currentIndex != 0xFFFF)
             {
    -          const Lookup &lookup = subs[entry.data.currentIndex];
    +          const Lookup &lookup = subs[entry.data.currentIndex];
               replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
             }
           }
           else
           {
             unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
    -        const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs;
    +        const UnsizedArrayOf &subs_old = (const UnsizedArrayOf &) subs;
             replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
             if (!replacement->sanitize (&c->sanitizer) || !*replacement)
               replacement = nullptr;
    @@ -304,7 +304,7 @@ struct ContextualSubtable
         bool mark_set;
         unsigned int mark;
         const ContextualSubtable *table;
    -    const UnsizedOffsetListOf, HBUINT, false> &subs;
    +    const UnsizedOffsetListOf, HBUINT, false> &subs;
       };
     
       bool apply (hb_aat_apply_context_t *c) const
    @@ -337,9 +337,9 @@ struct ContextualSubtable
           const EntryData &data = entries[i].data;
     
           if (data.markIndex != 0xFFFF)
    -        num_lookups = MAX (num_lookups, 1 + data.markIndex);
    +        num_lookups = hb_max (num_lookups, 1 + data.markIndex);
           if (data.currentIndex != 0xFFFF)
    -        num_lookups = MAX (num_lookups, 1 + data.currentIndex);
    +        num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
         }
     
         return_trace (substitutionTables.sanitize (c, this, num_lookups));
    @@ -348,7 +348,7 @@ struct ContextualSubtable
       protected:
       StateTable
                     machine;
    -  NNOffsetTo, HBUINT, false>, HBUINT>
    +  NNOffsetTo, HBUINT, false>, HBUINT>
                     substitutionTables;
       public:
       DEFINE_SIZE_STATIC (20);
    @@ -520,7 +520,7 @@ struct LigatureSubtable
               if (action & (LigActionStore | LigActionLast))
               {
                 ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
    -            const GlyphID &ligatureData = ligature[ligature_idx];
    +            const HBGlyphID &ligatureData = ligature[ligature_idx];
                 if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
                 hb_codepoint_t lig = ligatureData;
     
    @@ -554,7 +554,7 @@ struct LigatureSubtable
         const LigatureSubtable *table;
         const UnsizedArrayOf &ligAction;
         const UnsizedArrayOf &component;
    -    const UnsizedArrayOf &ligature;
    +    const UnsizedArrayOf &ligature;
         unsigned int match_length;
         unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
       };
    @@ -586,7 +586,7 @@ struct LigatureSubtable
                     ligAction;      /* Offset to the ligature action table. */
       NNOffsetTo, HBUINT>
                     component;      /* Offset to the component table. */
    -  NNOffsetTo, HBUINT>
    +  NNOffsetTo, HBUINT>
                     ligature;       /* Offset to the actual ligature lists. */
       public:
       DEFINE_SIZE_STATIC (28);
    @@ -606,7 +606,7 @@ struct NoncontextualSubtable
         unsigned int count = c->buffer->len;
         for (unsigned int i = 0; i < count; i++)
         {
    -      const GlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
    +      const HBGlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
           if (replacement)
           {
             info[i].codepoint = *replacement;
    @@ -624,7 +624,7 @@ struct NoncontextualSubtable
       }
     
       protected:
    -  Lookup       substitute;
    +  Lookup     substitute;
       public:
       DEFINE_SIZE_MIN (2);
     };
    @@ -725,8 +725,9 @@ struct InsertionSubtable
           if (entry.data.markedInsertIndex != 0xFFFF)
           {
             unsigned int count = (flags & MarkedInsertCount);
    +        if (unlikely ((buffer->max_ops -= count) <= 0)) return;
             unsigned int start = entry.data.markedInsertIndex;
    -        const GlyphID *glyphs = &insertionAction[start];
    +        const HBGlyphID *glyphs = &insertionAction[start];
             if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
     
             bool before = flags & MarkedInsertBefore;
    @@ -744,7 +745,7 @@ struct InsertionSubtable
     
             buffer->move_to (end + count);
     
    -        buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
    +        buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
           }
     
           if (flags & SetMark)
    @@ -753,8 +754,9 @@ struct InsertionSubtable
           if (entry.data.currentInsertIndex != 0xFFFF)
           {
             unsigned int count = (flags & CurrentInsertCount) >> 5;
    +        if (unlikely ((buffer->max_ops -= count) <= 0)) return;
             unsigned int start = entry.data.currentInsertIndex;
    -        const GlyphID *glyphs = &insertionAction[start];
    +        const HBGlyphID *glyphs = &insertionAction[start];
             if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
     
             bool before = flags & CurrentInsertBefore;
    @@ -793,7 +795,7 @@ struct InsertionSubtable
         private:
         hb_aat_apply_context_t *c;
         unsigned int mark;
    -    const UnsizedArrayOf &insertionAction;
    +    const UnsizedArrayOf &insertionAction;
       };
     
       bool apply (hb_aat_apply_context_t *c) const
    @@ -819,7 +821,7 @@ struct InsertionSubtable
       protected:
       StateTable
                     machine;
    -  NNOffsetTo, HBUINT>
    +  NNOffsetTo, HBUINT>
                     insertionAction;        /* Byte offset from stateHeader to the start of
                                              * the insertion glyph table. */
       public:
    @@ -883,17 +885,17 @@ struct ChainSubtable
         Insertion           = 5
       };
     
    -  template 
    -  typename context_t::return_t dispatch (context_t *c) const
    +  template 
    +  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
       {
         unsigned int subtable_type = get_type ();
         TRACE_DISPATCH (this, subtable_type);
         switch (subtable_type) {
    -    case Rearrangement:         return_trace (c->dispatch (u.rearrangement));
    -    case Contextual:            return_trace (c->dispatch (u.contextual));
    -    case Ligature:              return_trace (c->dispatch (u.ligature));
    -    case Noncontextual:         return_trace (c->dispatch (u.noncontextual));
    -    case Insertion:             return_trace (c->dispatch (u.insertion));
    +    case Rearrangement:         return_trace (c->dispatch (u.rearrangement, hb_forward (ds)...));
    +    case Contextual:            return_trace (c->dispatch (u.contextual, hb_forward (ds)...));
    +    case Ligature:              return_trace (c->dispatch (u.ligature, hb_forward (ds)...));
    +    case Noncontextual:         return_trace (c->dispatch (u.noncontextual, hb_forward (ds)...));
    +    case Insertion:             return_trace (c->dispatch (u.insertion, hb_forward (ds)...));
         default:                    return_trace (c->default_return_value ());
         }
       }
    @@ -948,8 +950,10 @@ struct Chain
             hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
             hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
           retry:
    -        const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type);
    -        if (info && info->setting == setting)
    +        // Check whether this type/setting pair was requested in the map, and if so, apply its flags.
    +        // (The search here only looks at the type and setting fields of feature_info_t.)
    +        hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
    +        if (map->features.bsearch (info))
             {
               flags &= feature.disableFlags;
               flags |= feature.enableFlags;
    @@ -967,9 +971,9 @@ struct Chain
       }
     
       void apply (hb_aat_apply_context_t *c,
    -                     hb_mask_t flags) const
    +              hb_mask_t flags) const
       {
    -    const ChainSubtable *subtable = &StructAfter > (featureZ.as_array (featureCount));
    +    const ChainSubtable *subtable = &StructAfter> (featureZ.as_array (featureCount));
         unsigned int count = subtableCount;
         for (unsigned int i = 0; i < count; i++)
         {
    @@ -1015,7 +1019,7 @@ struct Chain
                     bool (subtable->get_coverage () & ChainSubtable::Backwards) !=
                     HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
     
    -      if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
    +      if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index))
             goto skip;
     
           if (reverse)
    @@ -1026,12 +1030,12 @@ struct Chain
           if (reverse)
             c->buffer->reverse ();
     
    -      (void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
    +      (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index);
     
           if (unlikely (!c->buffer->successful)) return;
     
         skip:
    -      subtable = &StructAfter > (*subtable);
    +      subtable = &StructAfter> (*subtable);
           c->set_lookup_index (c->lookup_index + 1);
         }
       }
    @@ -1049,13 +1053,13 @@ struct Chain
         if (!c->check_array (featureZ.arrayZ, featureCount))
           return_trace (false);
     
    -    const ChainSubtable *subtable = &StructAfter > (featureZ.as_array (featureCount));
    +    const ChainSubtable *subtable = &StructAfter> (featureZ.as_array (featureCount));
         unsigned int count = subtableCount;
         for (unsigned int i = 0; i < count; i++)
         {
           if (!subtable->sanitize (c))
             return_trace (false);
    -      subtable = &StructAfter > (*subtable);
    +      subtable = &StructAfter> (*subtable);
         }
     
         return_trace (true);
    @@ -1080,10 +1084,10 @@ struct Chain
      * The 'mort'/'morx' Table
      */
     
    -template 
    +template 
     struct mortmorx
     {
    -  static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
    +  static constexpr hb_tag_t tableTag = TAG;
     
       bool has_data () const { return version != 0; }
     
    @@ -1095,7 +1099,7 @@ struct mortmorx
         for (unsigned int i = 0; i < count; i++)
         {
           map->chain_flags.push (chain->compile_flags (mapper));
    -      chain = &StructAfter > (*chain);
    +      chain = &StructAfter> (*chain);
         }
       }
     
    @@ -1109,7 +1113,7 @@ struct mortmorx
         {
           chain->apply (c, c->plan->aat_map.chain_flags[i]);
           if (unlikely (!c->buffer->successful)) return;
    -      chain = &StructAfter > (*chain);
    +      chain = &StructAfter> (*chain);
         }
       }
     
    @@ -1125,7 +1129,7 @@ struct mortmorx
         {
           if (!chain->sanitize (c, version))
             return_trace (false);
    -      chain = &StructAfter > (*chain);
    +      chain = &StructAfter> (*chain);
         }
     
         return_trace (true);
    @@ -1143,14 +1147,8 @@ struct mortmorx
       DEFINE_SIZE_MIN (8);
     };
     
    -struct morx : mortmorx
    -{
    -  static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
    -};
    -struct mort : mortmorx
    -{
    -  static constexpr hb_tag_t tableTag = HB_AAT_TAG_mort;
    -};
    +struct morx : mortmorx {};
    +struct mort : mortmorx {};
     
     
     } /* namespace AAT */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh
    new file mode 100644
    index 00000000000..bfd476c77e0
    --- /dev/null
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh
    @@ -0,0 +1,173 @@
    +/*
    + * Copyright © 2019  Ebrahim Byagowi
    + *
    + *  This is part of HarfBuzz, a text shaping library.
    + *
    + * Permission is hereby granted, without written agreement and without
    + * license or royalty fees, to use, copy, modify, and distribute this
    + * software and its documentation for any purpose, provided that the
    + * above copyright notice and the following two paragraphs appear in
    + * all copies of this software.
    + *
    + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    + * DAMAGE.
    + *
    + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    + * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    + */
    +
    +#ifndef HB_AAT_LAYOUT_OPBD_TABLE_HH
    +#define HB_AAT_LAYOUT_OPBD_TABLE_HH
    +
    +#include "hb-aat-layout-common.hh"
    +#include "hb-open-type.hh"
    +
    +/*
    + * opbd -- Optical Bounds
    + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6opbd.html
    + */
    +#define HB_AAT_TAG_opbd HB_TAG('o','p','b','d')
    +
    +
    +namespace AAT {
    +
    +struct OpticalBounds
    +{
    +  bool sanitize (hb_sanitize_context_t *c) const
    +  {
    +    TRACE_SANITIZE (this);
    +    return_trace (likely (c->check_struct (this)));
    +  }
    +
    +  FWORD         leftSide;
    +  FWORD         topSide;
    +  FWORD         rightSide;
    +  FWORD         bottomSide;
    +  public:
    +  DEFINE_SIZE_STATIC (8);
    +};
    +
    +struct opbdFormat0
    +{
    +  bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
    +                   hb_glyph_extents_t *extents, const void *base) const
    +  {
    +    const OffsetTo *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
    +    if (!bounds_offset) return false;
    +    const OpticalBounds &bounds = base+*bounds_offset;
    +
    +    if (extents)
    +      *extents = {
    +        font->em_scale_x (bounds.leftSide),
    +        font->em_scale_y (bounds.topSide),
    +        font->em_scale_x (bounds.rightSide),
    +        font->em_scale_y (bounds.bottomSide)
    +      };
    +    return true;
    +  }
    +
    +  bool sanitize (hb_sanitize_context_t *c, const void *base) const
    +  {
    +    TRACE_SANITIZE (this);
    +    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
    +  }
    +
    +  protected:
    +  Lookup>
    +                lookupTable;    /* Lookup table associating glyphs with the four
    +                                 * int16 values for the left-side, top-side,
    +                                 * right-side, and bottom-side optical bounds. */
    +  public:
    +  DEFINE_SIZE_MIN (2);
    +};
    +
    +struct opbdFormat1
    +{
    +  bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
    +                   hb_glyph_extents_t *extents, const void *base) const
    +  {
    +    const OffsetTo *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
    +    if (!bounds_offset) return false;
    +    const OpticalBounds &bounds = base+*bounds_offset;
    +
    +    hb_position_t left = 0, top = 0, right = 0, bottom = 0, ignore;
    +    if (font->get_glyph_contour_point (glyph_id, bounds.leftSide, &left, &ignore) ||
    +        font->get_glyph_contour_point (glyph_id, bounds.topSide, &ignore, &top) ||
    +        font->get_glyph_contour_point (glyph_id, bounds.rightSide, &right, &ignore) ||
    +        font->get_glyph_contour_point (glyph_id, bounds.bottomSide, &ignore, &bottom))
    +    {
    +      if (extents)
    +        *extents = {left, top, right, bottom};
    +      return true;
    +    }
    +    return false;
    +  }
    +
    +  bool sanitize (hb_sanitize_context_t *c, const void *base) const
    +  {
    +    TRACE_SANITIZE (this);
    +    return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
    +  }
    +
    +  protected:
    +  Lookup>
    +                lookupTable;    /* Lookup table associating glyphs with the four
    +                                 * int16 values for the left-side, top-side,
    +                                 * right-side, and bottom-side optical bounds. */
    +  public:
    +  DEFINE_SIZE_MIN (2);
    +};
    +
    +struct opbd
    +{
    +  static constexpr hb_tag_t tableTag = HB_AAT_TAG_opbd;
    +
    +  bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
    +                   hb_glyph_extents_t *extents) const
    +  {
    +    switch (format)
    +    {
    +    case 0: return u.format0.get_bounds (font, glyph_id, extents, this);
    +    case 1: return u.format1.get_bounds (font, glyph_id, extents, this);
    +    default:return false;
    +    }
    +  }
    +
    +  bool sanitize (hb_sanitize_context_t *c) const
    +  {
    +    TRACE_SANITIZE (this);
    +    if (unlikely (!c->check_struct (this) || version.major != 1))
    +      return_trace (false);
    +
    +    switch (format)
    +    {
    +    case 0: return_trace (u.format0.sanitize (c, this));
    +    case 1: return_trace (u.format1.sanitize (c, this));
    +    default:return_trace (true);
    +    }
    +  }
    +
    +  protected:
    +  FixedVersion<>version;        /* Version number of the optical bounds
    +                                 * table (0x00010000 for the current version). */
    +  HBUINT16      format;         /* Format of the optical bounds table.
    +                                 * Format 0 indicates distance and Format 1 indicates
    +                                 * control point. */
    +  union {
    +  opbdFormat0   format0;
    +  opbdFormat1   format1;
    +  } u;
    +  public:
    +  DEFINE_SIZE_MIN (8);
    +};
    +
    +} /* namespace AAT */
    +
    +
    +#endif /* HB_AAT_LAYOUT_OPBD_TABLE_HH */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh
    index 469cae5a677..1643e142229 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh
    @@ -62,11 +62,11 @@ struct TrackTableEntry
       }
     
       protected:
    -  Fixed         track;          /* Track value for this record. */
    +  HBFixed       track;          /* Track value for this record. */
       NameID        trackNameID;    /* The 'name' table index for this track.
                                      * (a short word or phrase like "loose"
                                      * or "very tight") */
    -  NNOffsetTo >
    +  NNOffsetTo>
                     valuesZ;        /* Offset from start of tracking table to
                                      * per-size tracking values for this track. */
     
    @@ -82,7 +82,7 @@ struct TrackData
                             const void *base) const
       {
         unsigned int sizes = nSizes;
    -    hb_array_t size_table ((base+sizeTable).arrayZ, sizes);
    +    hb_array_t size_table ((base+sizeTable).arrayZ, sizes);
     
         float s0 = size_table[idx].to_float ();
         float s1 = size_table[idx + 1].to_float ();
    @@ -93,13 +93,6 @@ struct TrackData
     
       int get_tracking (const void *base, float ptem) const
       {
    -    /* CoreText points are CSS pixels (96 per inch),
    -     * NOT typographic points (72 per inch).
    -     *
    -     * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
    -     */
    -    float csspx = ptem * 96.f / 72.f;
    -
         /*
          * Choose track.
          */
    @@ -127,14 +120,14 @@ struct TrackData
         if (!sizes) return 0.;
         if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
     
    -    hb_array_t size_table ((base+sizeTable).arrayZ, sizes);
    +    hb_array_t size_table ((base+sizeTable).arrayZ, sizes);
         unsigned int size_index;
         for (size_index = 0; size_index < sizes - 1; size_index++)
    -      if (size_table[size_index].to_float () >= csspx)
    +      if (size_table[size_index].to_float () >= ptem)
             break;
     
    -    return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
    -                                  *trackTableEntry, base));
    +    return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
    +                                   *trackTableEntry, base));
       }
     
       bool sanitize (hb_sanitize_context_t *c, const void *base) const
    @@ -148,7 +141,7 @@ struct TrackData
       protected:
       HBUINT16      nTracks;        /* Number of separate tracks included in this table. */
       HBUINT16      nSizes;         /* Number of point sizes included in this table. */
    -  LOffsetTo, false>
    +  LNNOffsetTo>
                     sizeTable;      /* Offset from start of the tracking table to
                                      * Array[nSizes] of size values.. */
       UnsizedArrayOf
    @@ -217,7 +210,7 @@ struct trak
     
       protected:
       FixedVersion<>version;        /* Version of the tracking table
    -                                         * (0x00010000u for version 1.0). */
    +                                 * (0x00010000u for version 1.0). */
       HBUINT16      format;         /* Format of the tracking table (set to 0). */
       OffsetTo
                     horizData;      /* Offset from start of tracking table to TrackData
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc
    index a49729dd761..38a5c57519d 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc
    @@ -25,11 +25,9 @@
      * Google Author(s): Behdad Esfahbod
      */
     
    -#include "hb-open-type.hh"
    +#include "hb.hh"
     
    -#include "hb-ot-face.hh"
     #include "hb-aat-layout.hh"
    -#include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise.
     #include "hb-aat-layout-ankr-table.hh"
     #include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
     #include "hb-aat-layout-feat-table.hh"
    @@ -40,6 +38,41 @@
     #include "hb-aat-ltag-table.hh"
     
     
    +/*
    + * hb_aat_apply_context_t
    + */
    +
    +/* Note: This context is used for kerning, even without AAT, hence the condition. */
    +#if !defined(HB_NO_AAT) || !defined(HB_NO_OT_KERN)
    +
    +AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
    +                                                     hb_font_t *font_,
    +                                                     hb_buffer_t *buffer_,
    +                                                     hb_blob_t *blob) :
    +                                                       plan (plan_),
    +                                                       font (font_),
    +                                                       face (font->face),
    +                                                       buffer (buffer_),
    +                                                       sanitizer (),
    +                                                       ankr_table (&Null (AAT::ankr)),
    +                                                       lookup_index (0)
    +{
    +  sanitizer.init (blob);
    +  sanitizer.set_num_glyphs (face->get_num_glyphs ());
    +  sanitizer.start_processing ();
    +  sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
    +}
    +
    +AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
    +{ sanitizer.end_processing (); }
    +
    +void
    +AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
    +{ ankr_table = ankr_table_; }
    +
    +#endif
    +
    +
     /**
      * SECTION:hb-aat-layout
      * @title: hb-aat-layout
    @@ -50,6 +83,8 @@
      **/
     
     
    +#if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
    +
     /* Table data courtesy of Apple.  Converted from mnemonics to integers
      * when moving to this file. */
     static const hb_aat_feature_mapping_t feature_mappings[] =
    @@ -135,44 +170,12 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
     const hb_aat_feature_mapping_t *
     hb_aat_layout_find_feature_mapping (hb_tag_t tag)
     {
    -  return (const hb_aat_feature_mapping_t *) bsearch (&tag,
    -                                                     feature_mappings,
    -                                                     ARRAY_LENGTH (feature_mappings),
    -                                                     sizeof (feature_mappings[0]),
    -                                                     hb_aat_feature_mapping_t::cmp);
    -}
    -
    -
    -/*
    - * hb_aat_apply_context_t
    - */
    -
    -AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
    -                                                     hb_font_t *font_,
    -                                                     hb_buffer_t *buffer_,
    -                                                     hb_blob_t *blob) :
    -                                                       plan (plan_),
    -                                                       font (font_),
    -                                                       face (font->face),
    -                                                       buffer (buffer_),
    -                                                       sanitizer (),
    -                                                       ankr_table (&Null(AAT::ankr)),
    -                                                       lookup_index (0),
    -                                                       debug_depth (0)
    -{
    -  sanitizer.init (blob);
    -  sanitizer.set_num_glyphs (face->get_num_glyphs ());
    -  sanitizer.start_processing ();
    -  sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
    +  return hb_sorted_array (feature_mappings).bsearch (tag);
     }
    +#endif
     
    -AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
    -{ sanitizer.end_processing (); }
    -
    -void
    -AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
    -{ ankr_table = ankr_table_; }
     
    +#ifndef HB_NO_AAT
     
     /*
      * mort/morx/kerx/trak
    @@ -311,14 +314,6 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
       trak.apply (&c);
     }
     
    -
    -hb_language_t
    -_hb_aat_language_get (hb_face_t *face,
    -                      unsigned int i)
    -{
    -  return face->table.ltag->get_language (i);
    -}
    -
     /**
      * hb_aat_layout_get_feature_types:
      * @face: a face object
    @@ -382,3 +377,6 @@ hb_aat_layout_feature_type_get_selector_infos (hb_face_t
     {
       return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
     }
    +
    +
    +#endif
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.h b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.h
    index 42540f264e3..977599e6cc4 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.h
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.h
    @@ -85,7 +85,7 @@ typedef enum
       HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE                  = 39,
       HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE             = 103,
     
    -  _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
    +  _HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
     } hb_aat_layout_feature_type_t;
     
     /**
    @@ -424,7 +424,7 @@ typedef enum
       HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN              = 2,
       HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN           = 3,
     
    -  _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
    +  _HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
     } hb_aat_layout_feature_selector_t;
     
     HB_EXTERN unsigned int
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh
    index 80b6a1d0973..1a95507ccee 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh
    @@ -30,7 +30,7 @@
     #include "hb.hh"
     
     #include "hb-ot-shape.hh"
    -
    +#include "hb-aat-ltag-table.hh"
     
     struct hb_aat_feature_mapping_t
     {
    @@ -39,14 +39,8 @@ struct hb_aat_feature_mapping_t
       hb_aat_layout_feature_selector_t selectorToEnable;
       hb_aat_layout_feature_selector_t selectorToDisable;
     
    -  static int cmp (const void *key_, const void *entry_)
    -  {
    -    hb_tag_t key = * (unsigned int *) key_;
    -    const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_;
    -    return key < entry->otFeatureTag ? -1 :
    -           key > entry->otFeatureTag ? 1 :
    -           0;
    -  }
    +  int cmp (hb_tag_t key) const
    +  { return key < otFeatureTag ? -1 : key > otFeatureTag ? 1 : 0; }
     };
     
     HB_INTERNAL const hb_aat_feature_mapping_t *
    @@ -77,9 +71,5 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
                          hb_font_t *font,
                          hb_buffer_t *buffer);
     
    -HB_INTERNAL hb_language_t
    -_hb_aat_language_get (hb_face_t *face,
    -                      unsigned int i);
    -
     
     #endif /* HB_AAT_LAYOUT_HH */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-ltag-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-ltag-table.hh
    index 23649f827ff..f42ca23e0d8 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-ltag-table.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-ltag-table.hh
    @@ -50,7 +50,7 @@ struct FTStringRange
       }
     
       protected:
    -  NNOffsetTo >
    +  NNOffsetTo>
                     tag;            /* Offset from the start of the table to
                                      * the beginning of the string */
       HBUINT16      length;         /* String length (in bytes) */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc
    index c3d078dbd65..ad3eff7935f 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc
    @@ -26,28 +26,55 @@
      * Google Author(s): Behdad Esfahbod
      */
     
    +#include "hb.hh"
    +
    +#ifndef HB_NO_AAT_SHAPE
    +
     #include "hb-aat-map.hh"
     
     #include "hb-aat-layout.hh"
    +#include "hb-aat-layout-feat-table.hh"
     
     
    -void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
    -                                        unsigned int value)
    +void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
     {
    +  if (!face->table.feat->has_data ()) return;
    +
       if (tag == HB_TAG ('a','a','l','t'))
       {
    +    if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
    +      return;
         feature_info_t *info = features.push();
         info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
         info->setting = (hb_aat_layout_feature_selector_t) value;
    +    info->seq = features.length;
    +    info->is_exclusive = true;
         return;
       }
     
       const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
       if (!mapping) return;
     
    +  const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType);
    +  if (!feature->has_data ())
    +  {
    +    /* Special case: Chain::compile_flags will fall back to the deprecated version of
    +     * small-caps if necessary, so we need to check for that possibility.
    +     * https://github.com/harfbuzz/harfbuzz/issues/2307 */
    +    if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
    +        mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
    +    {
    +      feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
    +      if (!feature->has_data ()) return;
    +    }
    +    else return;
    +  }
    +
       feature_info_t *info = features.push();
       info->type = mapping->aatFeatureType;
       info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
    +  info->seq = features.length;
    +  info->is_exclusive = feature->is_exclusive ();
     }
     
     void
    @@ -59,10 +86,17 @@ hb_aat_map_builder_t::compile (hb_aat_map_t  &m)
         features.qsort ();
         unsigned int j = 0;
         for (unsigned int i = 1; i < features.length; i++)
    -      if (features[i].type != features[j].type)
    +      if (features[i].type != features[j].type ||
    +          /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
    +           * respectively, so we mask out the low-order bit when checking for "duplicates"
    +           * (selectors referring to the same feature setting) here. */
    +          (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1))))
             features[++j] = features[i];
         features.shrink (j + 1);
       }
     
       hb_aat_layout_compile_map (this, &m);
     }
    +
    +
    +#endif
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh
    index 594d48e7cd5..ce30daa6084 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh
    @@ -64,19 +64,24 @@ struct hb_aat_map_builder_t
       {
         hb_aat_layout_feature_type_t  type;
         hb_aat_layout_feature_selector_t  setting;
    +    bool is_exclusive;
         unsigned  seq; /* For stable sorting only. */
     
    -    static int cmp (const void *pa, const void *pb)
    +    HB_INTERNAL static int cmp (const void *pa, const void *pb)
         {
           const feature_info_t *a = (const feature_info_t *) pa;
           const feature_info_t *b = (const feature_info_t *) pb;
    -      return (a->type != b->type) ? (a->type < b->type ? -1 : 1) :
    -             (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
    +      if (a->type != b->type) return (a->type < b->type ? -1 : 1);
    +      if (!a->is_exclusive &&
    +          (a->setting & ~1) != (b->setting & ~1)) return (a->setting < b->setting ? -1 : 1);
    +            return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
         }
     
    -    int cmp (hb_aat_layout_feature_type_t ty) const
    +    /* compares type & setting only, not is_exclusive flag or seq number */
    +    int cmp (const feature_info_t& f) const
         {
    -      return (type != ty) ? (type < ty ? -1 : 1) : 0;
    +      return (f.type != type) ? (f.type < type ? -1 : 1) :
    +             (f.setting != setting) ? (f.setting < setting ? -1 : 1) : 0;
         }
       };
     
    @@ -84,7 +89,7 @@ struct hb_aat_map_builder_t
       hb_face_t *face;
     
       public:
    -  hb_vector_t features;
    +  hb_sorted_vector_t features;
     };
     
     
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
    new file mode 100644
    index 00000000000..e21cb5429c9
    --- /dev/null
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh
    @@ -0,0 +1,1127 @@
    +/*
    + * Copyright © 2017  Google, Inc.
    + * Copyright © 2019  Facebook, Inc.
    + *
    + *  This is part of HarfBuzz, a text shaping library.
    + *
    + * Permission is hereby granted, without written agreement and without
    + * license or royalty fees, to use, copy, modify, and distribute this
    + * software and its documentation for any purpose, provided that the
    + * above copyright notice and the following two paragraphs appear in
    + * all copies of this software.
    + *
    + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    + * DAMAGE.
    + *
    + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    + * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    + *
    + * Google Author(s): Behdad Esfahbod
    + * Facebook Author(s): Behdad Esfahbod
    + */
    +
    +#ifndef HB_ALGS_HH
    +#define HB_ALGS_HH
    +
    +#include "hb.hh"
    +#include "hb-meta.hh"
    +#include "hb-null.hh"
    +#include "hb-number.hh"
    +
    +
    +/* Encodes three unsigned integers in one 64-bit number.  If the inputs have more than 21 bits,
    + * values will be truncated / overlap, and might not decode exactly. */
    +#define HB_CODEPOINT_ENCODE3(x,y,z) (((uint64_t) (x) << 42) | ((uint64_t) (y) << 21) | (uint64_t) (z))
    +#define HB_CODEPOINT_DECODE3_1(v) ((hb_codepoint_t) ((v) >> 42))
    +#define HB_CODEPOINT_DECODE3_2(v) ((hb_codepoint_t) ((v) >> 21) & 0x1FFFFFu)
    +#define HB_CODEPOINT_DECODE3_3(v) ((hb_codepoint_t) (v) & 0x1FFFFFu)
    +
    +/* Custom encoding used by hb-ucd. */
    +#define HB_CODEPOINT_ENCODE3_11_7_14(x,y,z) (((uint32_t) ((x) & 0x07FFu) << 21) | (((uint32_t) (y) & 0x007Fu) << 14) | (uint32_t) ((z) & 0x3FFFu))
    +#define HB_CODEPOINT_DECODE3_11_7_14_1(v) ((hb_codepoint_t) ((v) >> 21))
    +#define HB_CODEPOINT_DECODE3_11_7_14_2(v) ((hb_codepoint_t) (((v) >> 14) & 0x007Fu) | 0x0300)
    +#define HB_CODEPOINT_DECODE3_11_7_14_3(v) ((hb_codepoint_t) (v) & 0x3FFFu)
    +
    +struct
    +{
    +  /* Note.  This is dangerous in that if it's passed an rvalue, it returns rvalue-reference. */
    +  template  constexpr auto
    +  operator () (T&& v) const HB_AUTO_RETURN ( hb_forward (v) )
    +}
    +HB_FUNCOBJ (hb_identity);
    +struct
    +{
    +  /* Like identity(), but only retains lvalue-references.  Rvalues are returned as rvalues. */
    +  template  constexpr T&
    +  operator () (T& v) const { return v; }
    +
    +  template  constexpr hb_remove_reference
    +  operator () (T&& v) const { return v; }
    +}
    +HB_FUNCOBJ (hb_lidentity);
    +struct
    +{
    +  /* Like identity(), but always returns rvalue. */
    +  template  constexpr hb_remove_reference
    +  operator () (T&& v) const { return v; }
    +}
    +HB_FUNCOBJ (hb_ridentity);
    +
    +struct
    +{
    +  template  constexpr bool
    +  operator () (T&& v) const { return bool (hb_forward (v)); }
    +}
    +HB_FUNCOBJ (hb_bool);
    +
    +struct
    +{
    +  private:
    +
    +  template  constexpr auto
    +  impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ())
    +
    +  template  constexpr auto
    +  impl (const T& v, hb_priority<0>) const HB_AUTO_RETURN
    +  (
    +    /* Knuth's multiplicative method: */
    +    (uint32_t) v * 2654435761u
    +  )
    +
    +  public:
    +
    +  template  constexpr auto
    +  operator () (const T& v) const HB_RETURN (uint32_t, impl (v, hb_prioritize))
    +}
    +HB_FUNCOBJ (hb_hash);
    +
    +
    +struct
    +{
    +  private:
    +
    +  /* Pointer-to-member-function. */
    +  template  auto
    +  impl (Appl&& a, hb_priority<2>, T &&v, Ts&&... ds) const HB_AUTO_RETURN
    +  ((hb_deref (hb_forward (v)).*hb_forward (a)) (hb_forward (ds)...))
    +
    +  /* Pointer-to-member. */
    +  template  auto
    +  impl (Appl&& a, hb_priority<1>, T &&v) const HB_AUTO_RETURN
    +  ((hb_deref (hb_forward (v))).*hb_forward (a))
    +
    +  /* Operator(). */
    +  template  auto
    +  impl (Appl&& a, hb_priority<0>, Ts&&... ds) const HB_AUTO_RETURN
    +  (hb_deref (hb_forward (a)) (hb_forward (ds)...))
    +
    +  public:
    +
    +  template  auto
    +  operator () (Appl&& a, Ts&&... ds) const HB_AUTO_RETURN
    +  (
    +    impl (hb_forward (a),
    +          hb_prioritize,
    +          hb_forward (ds)...)
    +  )
    +}
    +HB_FUNCOBJ (hb_invoke);
    +
    +template 
    +struct hb_partial_t
    +{
    +  hb_partial_t (Appl a, V v) : a (a), v (v) {}
    +
    +  static_assert (Pos > 0, "");
    +
    +  template  auto
    +  operator () (Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
    +                                                   hb_declval (V),
    +                                                   hb_declval (Ts)...))
    +  {
    +    return hb_invoke (hb_forward (a),
    +                      hb_forward (v),
    +                      hb_forward (ds)...);
    +  }
    +  template  auto
    +  operator () (T0&& d0, Ts&& ...ds) -> decltype (hb_invoke (hb_declval (Appl),
    +                                                            hb_declval (T0),
    +                                                            hb_declval (V),
    +                                                            hb_declval (Ts)...))
    +  {
    +    return hb_invoke (hb_forward (a),
    +                      hb_forward (d0),
    +                      hb_forward (v),
    +                      hb_forward (ds)...);
    +  }
    +
    +  private:
    +  hb_reference_wrapper a;
    +  V v;
    +};
    +template 
    +auto hb_partial (Appl&& a, V&& v) HB_AUTO_RETURN
    +(( hb_partial_t (a, v) ))
    +
    +/* The following, HB_PARTIALIZE, macro uses a particular corner-case
    + * of C++11 that is not particularly well-supported by all compilers.
    + * What's happening is that it's using "this" in a trailing return-type
    + * via decltype().  Broken compilers deduce the type of "this" pointer
    + * in that context differently from what it resolves to in the body
    + * of the function.
    + *
    + * One probable cause of this is that at the time of trailing return
    + * type declaration, "this" points to an incomplete type, whereas in
    + * the function body the type is complete.  That doesn't justify the
    + * error in any way, but is probably what's happening.
    + *
    + * In the case of MSVC, we get around this by using C++14 "decltype(auto)"
    + * which deduces the type from the actual return statement.  For gcc 4.8
    + * we use "+this" instead of "this" which produces an rvalue that seems
    + * to be deduced as the same type with this particular compiler, and seem
    + * to be fine as default code path as well.
    + */
    +#ifdef _MSC_VER
    +/* https://github.com/harfbuzz/harfbuzz/issues/1730 */ \
    +#define HB_PARTIALIZE(Pos) \
    +  template  \
    +  decltype(auto) operator () (_T&& _v) const \
    +  { return hb_partial (this, hb_forward<_T> (_v)); } \
    +  static_assert (true, "")
    +#else
    +/* https://github.com/harfbuzz/harfbuzz/issues/1724 */
    +#define HB_PARTIALIZE(Pos) \
    +  template  \
    +  auto operator () (_T&& _v) const HB_AUTO_RETURN \
    +  (hb_partial (+this, hb_forward<_T> (_v))) \
    +  static_assert (true, "")
    +#endif
    +
    +
    +struct
    +{
    +  private:
    +
    +  template  auto
    +  impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
    +  (hb_deref (hb_forward (p)).has (hb_forward (v)))
    +
    +  template  auto
    +  impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
    +  (
    +    hb_invoke (hb_forward (p),
    +               hb_forward (v))
    +  )
    +
    +  public:
    +
    +  template  auto
    +  operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
    +    impl (hb_forward (p),
    +          hb_forward (v),
    +          hb_prioritize)
    +  )
    +}
    +HB_FUNCOBJ (hb_has);
    +
    +struct
    +{
    +  private:
    +
    +  template  auto
    +  impl (Pred&& p, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
    +  (
    +    hb_has (hb_forward (p),
    +            hb_forward (v))
    +  )
    +
    +  template  auto
    +  impl (Pred&& p, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
    +  (
    +    hb_forward (p) == hb_forward (v)
    +  )
    +
    +  public:
    +
    +  template  auto
    +  operator () (Pred&& p, Val &&v) const HB_RETURN (bool,
    +    impl (hb_forward (p),
    +          hb_forward (v),
    +          hb_prioritize)
    +  )
    +}
    +HB_FUNCOBJ (hb_match);
    +
    +struct
    +{
    +  private:
    +
    +  template  auto
    +  impl (Proj&& f, Val &&v, hb_priority<2>) const HB_AUTO_RETURN
    +  (hb_deref (hb_forward (f)).get (hb_forward (v)))
    +
    +  template  auto
    +  impl (Proj&& f, Val &&v, hb_priority<1>) const HB_AUTO_RETURN
    +  (
    +    hb_invoke (hb_forward (f),
    +               hb_forward (v))
    +  )
    +
    +  template  auto
    +  impl (Proj&& f, Val &&v, hb_priority<0>) const HB_AUTO_RETURN
    +  (
    +    hb_forward (f)[hb_forward (v)]
    +  )
    +
    +  public:
    +
    +  template  auto
    +  operator () (Proj&& f, Val &&v) const HB_AUTO_RETURN
    +  (
    +    impl (hb_forward (f),
    +          hb_forward (v),
    +          hb_prioritize)
    +  )
    +}
    +HB_FUNCOBJ (hb_get);
    +
    +
    +template 
    +struct hb_pair_t
    +{
    +  typedef T1 first_t;
    +  typedef T2 second_t;
    +  typedef hb_pair_t pair_t;
    +
    +  hb_pair_t (T1 a, T2 b) : first (a), second (b) {}
    +
    +  template 
    +  operator hb_pair_t () { return hb_pair_t (first, second); }
    +
    +  hb_pair_t reverse () const
    +  { return hb_pair_t (second, first); }
    +
    +  bool operator == (const pair_t& o) const { return first == o.first && second == o.second; }
    +  bool operator != (const pair_t& o) const { return !(*this == o); }
    +  bool operator < (const pair_t& o) const { return first < o.first || (first == o.first && second < o.second); }
    +  bool operator >= (const pair_t& o) const { return !(*this < o); }
    +  bool operator > (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); }
    +  bool operator <= (const pair_t& o) const { return !(*this > o); }
    +
    +  T1 first;
    +  T2 second;
    +};
    +#define hb_pair_t(T1,T2) hb_pair_t
    +template  static inline hb_pair_t
    +hb_pair (T1&& a, T2&& b) { return hb_pair_t (a, b); }
    +
    +struct
    +{
    +  template  constexpr typename Pair::first_t
    +  operator () (const Pair& pair) const { return pair.first; }
    +}
    +HB_FUNCOBJ (hb_first);
    +
    +struct
    +{
    +  template  constexpr typename Pair::second_t
    +  operator () (const Pair& pair) const { return pair.second; }
    +}
    +HB_FUNCOBJ (hb_second);
    +
    +/* Note.  In min/max impl, we can use hb_type_identity for second argument.
    + * However, that would silently convert between different-signedness integers.
    + * Instead we accept two different types, such that compiler can err if
    + * comparing integers of different signedness. */
    +struct
    +{
    +  template  constexpr auto
    +  operator () (T&& a, T2&& b) const HB_AUTO_RETURN
    +  (hb_forward (a) <= hb_forward (b) ? hb_forward (a) : hb_forward (b))
    +}
    +HB_FUNCOBJ (hb_min);
    +struct
    +{
    +  template  constexpr auto
    +  operator () (T&& a, T2&& b) const HB_AUTO_RETURN
    +  (hb_forward (a) >= hb_forward (b) ? hb_forward (a) : hb_forward (b))
    +}
    +HB_FUNCOBJ (hb_max);
    +struct
    +{
    +  template  constexpr auto
    +  operator () (T&& x, T2&& min, T3&& max) const HB_AUTO_RETURN
    +  (hb_min (hb_max (hb_forward (x), hb_forward (min)), hb_forward (max)))
    +}
    +HB_FUNCOBJ (hb_clamp);
    +
    +
    +/*
    + * Bithacks.
    + */
    +
    +/* Return the number of 1 bits in v. */
    +template 
    +static inline HB_CONST_FUNC unsigned int
    +hb_popcount (T v)
    +{
    +#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
    +  if (sizeof (T) <= sizeof (unsigned int))
    +    return __builtin_popcount (v);
    +
    +  if (sizeof (T) <= sizeof (unsigned long))
    +    return __builtin_popcountl (v);
    +
    +  if (sizeof (T) <= sizeof (unsigned long long))
    +    return __builtin_popcountll (v);
    +#endif
    +
    +  if (sizeof (T) <= 4)
    +  {
    +    /* "HACKMEM 169" */
    +    uint32_t y;
    +    y = (v >> 1) &033333333333;
    +    y = v - y - ((y >>1) & 033333333333);
    +    return (((y + (y >> 3)) & 030707070707) % 077);
    +  }
    +
    +  if (sizeof (T) == 8)
    +  {
    +    unsigned int shift = 32;
    +    return hb_popcount ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
    +  }
    +
    +  if (sizeof (T) == 16)
    +  {
    +    unsigned int shift = 64;
    +    return hb_popcount ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
    +  }
    +
    +  assert (0);
    +  return 0; /* Shut up stupid compiler. */
    +}
    +
    +/* Returns the number of bits needed to store number */
    +template 
    +static inline HB_CONST_FUNC unsigned int
    +hb_bit_storage (T v)
    +{
    +  if (unlikely (!v)) return 0;
    +
    +#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
    +  if (sizeof (T) <= sizeof (unsigned int))
    +    return sizeof (unsigned int) * 8 - __builtin_clz (v);
    +
    +  if (sizeof (T) <= sizeof (unsigned long))
    +    return sizeof (unsigned long) * 8 - __builtin_clzl (v);
    +
    +  if (sizeof (T) <= sizeof (unsigned long long))
    +    return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
    +#endif
    +
    +#if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
    +  if (sizeof (T) <= sizeof (unsigned int))
    +  {
    +    unsigned long where;
    +    _BitScanReverse (&where, v);
    +    return 1 + where;
    +  }
    +# if defined(_WIN64)
    +  if (sizeof (T) <= 8)
    +  {
    +    unsigned long where;
    +    _BitScanReverse64 (&where, v);
    +    return 1 + where;
    +  }
    +# endif
    +#endif
    +
    +  if (sizeof (T) <= 4)
    +  {
    +    /* "bithacks" */
    +    const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
    +    const unsigned int S[] = {1, 2, 4, 8, 16};
    +    unsigned int r = 0;
    +    for (int i = 4; i >= 0; i--)
    +      if (v & b[i])
    +      {
    +        v >>= S[i];
    +        r |= S[i];
    +      }
    +    return r + 1;
    +  }
    +  if (sizeof (T) <= 8)
    +  {
    +    /* "bithacks" */
    +    const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
    +    const unsigned int S[] = {1, 2, 4, 8, 16, 32};
    +    unsigned int r = 0;
    +    for (int i = 5; i >= 0; i--)
    +      if (v & b[i])
    +      {
    +        v >>= S[i];
    +        r |= S[i];
    +      }
    +    return r + 1;
    +  }
    +  if (sizeof (T) == 16)
    +  {
    +    unsigned int shift = 64;
    +    return (v >> shift) ? hb_bit_storage ((uint64_t) (v >> shift)) + shift :
    +                          hb_bit_storage ((uint64_t) v);
    +  }
    +
    +  assert (0);
    +  return 0; /* Shut up stupid compiler. */
    +}
    +
    +/* Returns the number of zero bits in the least significant side of v */
    +template 
    +static inline HB_CONST_FUNC unsigned int
    +hb_ctz (T v)
    +{
    +  if (unlikely (!v)) return 8 * sizeof (T);
    +
    +#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
    +  if (sizeof (T) <= sizeof (unsigned int))
    +    return __builtin_ctz (v);
    +
    +  if (sizeof (T) <= sizeof (unsigned long))
    +    return __builtin_ctzl (v);
    +
    +  if (sizeof (T) <= sizeof (unsigned long long))
    +    return __builtin_ctzll (v);
    +#endif
    +
    +#if (defined(_MSC_VER) && _MSC_VER >= 1500) || (defined(__MINGW32__) && (__GNUC__ < 4))
    +  if (sizeof (T) <= sizeof (unsigned int))
    +  {
    +    unsigned long where;
    +    _BitScanForward (&where, v);
    +    return where;
    +  }
    +# if defined(_WIN64)
    +  if (sizeof (T) <= 8)
    +  {
    +    unsigned long where;
    +    _BitScanForward64 (&where, v);
    +    return where;
    +  }
    +# endif
    +#endif
    +
    +  if (sizeof (T) <= 4)
    +  {
    +    /* "bithacks" */
    +    unsigned int c = 32;
    +    v &= - (int32_t) v;
    +    if (v) c--;
    +    if (v & 0x0000FFFF) c -= 16;
    +    if (v & 0x00FF00FF) c -= 8;
    +    if (v & 0x0F0F0F0F) c -= 4;
    +    if (v & 0x33333333) c -= 2;
    +    if (v & 0x55555555) c -= 1;
    +    return c;
    +  }
    +  if (sizeof (T) <= 8)
    +  {
    +    /* "bithacks" */
    +    unsigned int c = 64;
    +    v &= - (int64_t) (v);
    +    if (v) c--;
    +    if (v & 0x00000000FFFFFFFFULL) c -= 32;
    +    if (v & 0x0000FFFF0000FFFFULL) c -= 16;
    +    if (v & 0x00FF00FF00FF00FFULL) c -= 8;
    +    if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
    +    if (v & 0x3333333333333333ULL) c -= 2;
    +    if (v & 0x5555555555555555ULL) c -= 1;
    +    return c;
    +  }
    +  if (sizeof (T) == 16)
    +  {
    +    unsigned int shift = 64;
    +    return (uint64_t) v ? hb_bit_storage ((uint64_t) v) :
    +                          hb_bit_storage ((uint64_t) (v >> shift)) + shift;
    +  }
    +
    +  assert (0);
    +  return 0; /* Shut up stupid compiler. */
    +}
    +
    +
    +/*
    + * Tiny stuff.
    + */
    +
    +/* ASCII tag/character handling */
    +static inline bool ISALPHA (unsigned char c)
    +{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
    +static inline bool ISALNUM (unsigned char c)
    +{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
    +static inline bool ISSPACE (unsigned char c)
    +{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
    +static inline unsigned char TOUPPER (unsigned char c)
    +{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
    +static inline unsigned char TOLOWER (unsigned char c)
    +{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
    +static inline bool ISHEX (unsigned char c)
    +{ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); }
    +static inline unsigned char TOHEX (uint8_t c)
    +{ return (c & 0xF) <= 9 ? (c & 0xF) + '0' : (c & 0xF) + 'a' - 10; }
    +static inline uint8_t FROMHEX (unsigned char c)
    +{ return (c >= '0' && c <= '9') ? c - '0' : TOLOWER (c) - 'a' + 10; }
    +
    +static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
    +{ return (a + (b - 1)) / b; }
    +
    +
    +#undef  ARRAY_LENGTH
    +template 
    +static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
    +/* A const version, but does not detect erratically being called on pointers. */
    +#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
    +
    +
    +static inline int
    +hb_memcmp (const void *a, const void *b, unsigned int len)
    +{
    +  /* It's illegal to pass NULL to memcmp(), even if len is zero.
    +   * So, wrap it.
    +   * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
    +  if (unlikely (!len)) return 0;
    +  return memcmp (a, b, len);
    +}
    +
    +static inline void *
    +hb_memset (void *s, int c, unsigned int n)
    +{
    +  /* It's illegal to pass NULL to memset(), even if n is zero. */
    +  if (unlikely (!n)) return 0;
    +  return memset (s, c, n);
    +}
    +
    +static inline unsigned int
    +hb_ceil_to_4 (unsigned int v)
    +{
    +  return ((v - 1) | 3) + 1;
    +}
    +
    +template  static inline bool
    +hb_in_range (T u, T lo, T hi)
    +{
    +  static_assert (!hb_is_signed::value, "");
    +
    +  /* The casts below are important as if T is smaller than int,
    +   * the subtract results will become a signed int! */
    +  return (T)(u - lo) <= (T)(hi - lo);
    +}
    +template  static inline bool
    +hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
    +{
    +  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
    +}
    +template  static inline bool
    +hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
    +{
    +  return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
    +}
    +
    +
    +/*
    + * Overflow checking.
    + */
    +
    +/* Consider __builtin_mul_overflow use here also */
    +static inline bool
    +hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
    +{
    +  return (size > 0) && (count >= ((unsigned int) -1) / size);
    +}
    +
    +
    +/*
    + * Sort and search.
    + */
    +
    +template 
    +static int
    +_hb_cmp_method (const void *pkey, const void *pval, Ts... ds)
    +{
    +  const K& key = * (const K*) pkey;
    +  const V& val = * (const V*) pval;
    +
    +  return val.cmp (key, ds...);
    +}
    +
    +template 
    +static inline bool
    +hb_bsearch_impl (unsigned *pos, /* Out */
    +                 const K& key,
    +                 V* base, size_t nmemb, size_t stride,
    +                 int (*compar)(const void *_key, const void *_item, Ts... _ds),
    +                 Ts... ds)
    +{
    +  /* This is our *only* bsearch implementation. */
    +
    +  int min = 0, max = (int) nmemb - 1;
    +  while (min <= max)
    +  {
    +    int mid = ((unsigned int) min + (unsigned int) max) / 2;
    +#pragma GCC diagnostic push
    +#pragma GCC diagnostic ignored "-Wcast-align"
    +    V* p = (V*) (((const char *) base) + (mid * stride));
    +#pragma GCC diagnostic pop
    +    int c = compar ((const void *) hb_addressof (key), (const void *) p, ds...);
    +    if (c < 0)
    +      max = mid - 1;
    +    else if (c > 0)
    +      min = mid + 1;
    +    else
    +    {
    +      *pos = mid;
    +      return true;
    +    }
    +  }
    +  *pos = min;
    +  return false;
    +}
    +
    +template 
    +static inline V*
    +hb_bsearch (const K& key, V* base,
    +            size_t nmemb, size_t stride = sizeof (V),
    +            int (*compar)(const void *_key, const void *_item) = _hb_cmp_method)
    +{
    +  unsigned pos;
    +#pragma GCC diagnostic push
    +#pragma GCC diagnostic ignored "-Wcast-align"
    +  return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar) ?
    +         (V*) (((const char *) base) + (pos * stride)) : nullptr;
    +#pragma GCC diagnostic pop
    +}
    +template 
    +static inline V*
    +hb_bsearch (const K& key, V* base,
    +            size_t nmemb, size_t stride,
    +            int (*compar)(const void *_key, const void *_item, Ts... _ds),
    +            Ts... ds)
    +{
    +  unsigned pos;
    +#pragma GCC diagnostic push
    +#pragma GCC diagnostic ignored "-Wcast-align"
    +  return hb_bsearch_impl (&pos, key, base, nmemb, stride, compar, ds...) ?
    +         (V*) (((const char *) base) + (pos * stride)) : nullptr;
    +#pragma GCC diagnostic pop
    +}
    +
    +
    +/* From https://github.com/noporpoise/sort_r
    +   Feb 5, 2019 (c8c65c1e)
    +   Modified to support optional argument using templates */
    +
    +/* Isaac Turner 29 April 2014 Public Domain */
    +
    +/*
    +hb_qsort function to be exported.
    +Parameters:
    +  base is the array to be sorted
    +  nel is the number of elements in the array
    +  width is the size in bytes of each element of the array
    +  compar is the comparison function
    +  arg (optional) is a pointer to be passed to the comparison function
    +
    +void hb_qsort(void *base, size_t nel, size_t width,
    +              int (*compar)(const void *_a, const void *_b, [void *_arg]),
    +              [void *arg]);
    +*/
    +
    +#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp))
    +
    +/* swap a and b */
    +/* a and b must not be equal! */
    +static inline void sort_r_swap(char *__restrict a, char *__restrict b,
    +                               size_t w)
    +{
    +  char tmp, *end = a+w;
    +  for(; a < end; a++, b++) { SORT_R_SWAP(*a, *b, tmp); }
    +}
    +
    +/* swap a, b iff a>b */
    +/* a and b must not be equal! */
    +/* __restrict is same as restrict but better support on old machines */
    +template 
    +static inline int sort_r_cmpswap(char *__restrict a,
    +                                 char *__restrict b, size_t w,
    +                                 int (*compar)(const void *_a,
    +                                               const void *_b,
    +                                               Ts... _ds),
    +                                 Ts... ds)
    +{
    +  if(compar(a, b, ds...) > 0) {
    +    sort_r_swap(a, b, w);
    +    return 1;
    +  }
    +  return 0;
    +}
    +
    +/*
    +Swap consecutive blocks of bytes of size na and nb starting at memory addr ptr,
    +with the smallest swap so that the blocks are in the opposite order. Blocks may
    +be internally re-ordered e.g.
    +  12345ab  ->   ab34512
    +  123abc   ->   abc123
    +  12abcde  ->   deabc12
    +*/
    +static inline void sort_r_swap_blocks(char *ptr, size_t na, size_t nb)
    +{
    +  if(na > 0 && nb > 0) {
    +    if(na > nb) { sort_r_swap(ptr, ptr+na, nb); }
    +    else { sort_r_swap(ptr, ptr+nb, na); }
    +  }
    +}
    +
    +/* Implement recursive quicksort ourselves */
    +/* Note: quicksort is not stable, equivalent values may be swapped */
    +template 
    +static inline void sort_r_simple(void *base, size_t nel, size_t w,
    +                                 int (*compar)(const void *_a,
    +                                               const void *_b,
    +                                               Ts... _ds),
    +                                 Ts... ds)
    +{
    +  char *b = (char *)base, *end = b + nel*w;
    +
    +  /* for(size_t i=0; i b && sort_r_cmpswap(pj-w,pj,w,compar,ds...); pj -= w) {}
    +    }
    +  }
    +  else
    +  {
    +    /* nel > 9; Quicksort */
    +
    +    int cmp;
    +    char *pl, *ple, *pr, *pre, *pivot;
    +    char *last = b+w*(nel-1), *tmp;
    +
    +    /*
    +    Use median of second, middle and second-last items as pivot.
    +    First and last may have been swapped with pivot and therefore be extreme
    +    */
    +    char *l[3];
    +    l[0] = b + w;
    +    l[1] = b+w*(nel/2);
    +    l[2] = last - w;
    +
    +    /* printf("pivots: %i, %i, %i\n", *(int*)l[0], *(int*)l[1], *(int*)l[2]); */
    +
    +    if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
    +    if(compar(l[1],l[2],ds...) > 0) {
    +      SORT_R_SWAP(l[1], l[2], tmp);
    +      if(compar(l[0],l[1],ds...) > 0) { SORT_R_SWAP(l[0], l[1], tmp); }
    +    }
    +
    +    /* swap mid value (l[1]), and last element to put pivot as last element */
    +    if(l[1] != last) { sort_r_swap(l[1], last, w); }
    +
    +    /*
    +    pl is the next item on the left to be compared to the pivot
    +    pr is the last item on the right that was compared to the pivot
    +    ple is the left position to put the next item that equals the pivot
    +    ple is the last right position where we put an item that equals the pivot
    +                                           v- end (beyond the array)
    +      EEEEEELLLLLLLLuuuuuuuuGGGGGGGEEEEEEEE.
    +      ^- b  ^- ple  ^- pl   ^- pr  ^- pre ^- last (where the pivot is)
    +    Pivot comparison key:
    +      E = equal, L = less than, u = unknown, G = greater than, E = equal
    +    */
    +    pivot = last;
    +    ple = pl = b;
    +    pre = pr = last;
    +
    +    /*
    +    Strategy:
    +    Loop into the list from the left and right at the same time to find:
    +    - an item on the left that is greater than the pivot
    +    - an item on the right that is less than the pivot
    +    Once found, they are swapped and the loop continues.
    +    Meanwhile items that are equal to the pivot are moved to the edges of the
    +    array.
    +    */
    +    while(pl < pr) {
    +      /* Move left hand items which are equal to the pivot to the far left.
    +         break when we find an item that is greater than the pivot */
    +      for(; pl < pr; pl += w) {
    +        cmp = compar(pl, pivot, ds...);
    +        if(cmp > 0) { break; }
    +        else if(cmp == 0) {
    +          if(ple < pl) { sort_r_swap(ple, pl, w); }
    +          ple += w;
    +        }
    +      }
    +      /* break if last batch of left hand items were equal to pivot */
    +      if(pl >= pr) { break; }
    +      /* Move right hand items which are equal to the pivot to the far right.
    +         break when we find an item that is less than the pivot */
    +      for(; pl < pr; ) {
    +        pr -= w; /* Move right pointer onto an unprocessed item */
    +        cmp = compar(pr, pivot, ds...);
    +        if(cmp == 0) {
    +          pre -= w;
    +          if(pr < pre) { sort_r_swap(pr, pre, w); }
    +        }
    +        else if(cmp < 0) {
    +          if(pl < pr) { sort_r_swap(pl, pr, w); }
    +          pl += w;
    +          break;
    +        }
    +      }
    +    }
    +
    +    pl = pr; /* pr may have gone below pl */
    +
    +    /*
    +    Now we need to go from: EEELLLGGGGEEEE
    +                        to: LLLEEEEEEEGGGG
    +    Pivot comparison key:
    +      E = equal, L = less than, u = unknown, G = greater than, E = equal
    +    */
    +    sort_r_swap_blocks(b, ple-b, pl-ple);
    +    sort_r_swap_blocks(pr, pre-pr, end-pre);
    +
    +    /*for(size_t i=0; i static inline void
    +hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2)
    +{
    +  for (unsigned int i = 1; i < len; i++)
    +  {
    +    unsigned int j = i;
    +    while (j && compar (&array[j - 1], &array[i]) > 0)
    +      j--;
    +    if (i == j)
    +      continue;
    +    /* Move item i to occupy place for item j, shift what's in between. */
    +    {
    +      T t = array[i];
    +      memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
    +      array[j] = t;
    +    }
    +    if (array2)
    +    {
    +      T3 t = array2[i];
    +      memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T3));
    +      array2[j] = t;
    +    }
    +  }
    +}
    +
    +template  static inline void
    +hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
    +{
    +  hb_stable_sort (array, len, compar, (int *) nullptr);
    +}
    +
    +static inline hb_bool_t
    +hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
    +{
    +  unsigned int v;
    +  const char *p = s;
    +  const char *end = p + len;
    +  if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */, base)))
    +    return false;
    +
    +  *out = v;
    +  return true;
    +}
    +
    +
    +/* Operators. */
    +
    +struct hb_bitwise_and
    +{ HB_PARTIALIZE(2);
    +  static constexpr bool passthru_left = false;
    +  static constexpr bool passthru_right = false;
    +  template  constexpr auto
    +  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
    +}
    +HB_FUNCOBJ (hb_bitwise_and);
    +struct hb_bitwise_or
    +{ HB_PARTIALIZE(2);
    +  static constexpr bool passthru_left = true;
    +  static constexpr bool passthru_right = true;
    +  template  constexpr auto
    +  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
    +}
    +HB_FUNCOBJ (hb_bitwise_or);
    +struct hb_bitwise_xor
    +{ HB_PARTIALIZE(2);
    +  static constexpr bool passthru_left = true;
    +  static constexpr bool passthru_right = true;
    +  template  constexpr auto
    +  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
    +}
    +HB_FUNCOBJ (hb_bitwise_xor);
    +struct hb_bitwise_sub
    +{ HB_PARTIALIZE(2);
    +  static constexpr bool passthru_left = true;
    +  static constexpr bool passthru_right = false;
    +  template  constexpr auto
    +  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
    +}
    +HB_FUNCOBJ (hb_bitwise_sub);
    +struct
    +{
    +  template  constexpr auto
    +  operator () (const T &a) const HB_AUTO_RETURN (~a)
    +}
    +HB_FUNCOBJ (hb_bitwise_neg);
    +
    +struct
    +{ HB_PARTIALIZE(2);
    +  template  constexpr auto
    +  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a + b)
    +}
    +HB_FUNCOBJ (hb_add);
    +struct
    +{ HB_PARTIALIZE(2);
    +  template  constexpr auto
    +  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a - b)
    +}
    +HB_FUNCOBJ (hb_sub);
    +struct
    +{ HB_PARTIALIZE(2);
    +  template  constexpr auto
    +  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)
    +}
    +HB_FUNCOBJ (hb_mul);
    +struct
    +{ HB_PARTIALIZE(2);
    +  template  constexpr auto
    +  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a / b)
    +}
    +HB_FUNCOBJ (hb_div);
    +struct
    +{ HB_PARTIALIZE(2);
    +  template  constexpr auto
    +  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a % b)
    +}
    +HB_FUNCOBJ (hb_mod);
    +struct
    +{
    +  template  constexpr auto
    +  operator () (const T &a) const HB_AUTO_RETURN (+a)
    +}
    +HB_FUNCOBJ (hb_pos);
    +struct
    +{
    +  template  constexpr auto
    +  operator () (const T &a) const HB_AUTO_RETURN (-a)
    +}
    +HB_FUNCOBJ (hb_neg);
    +struct
    +{
    +  template  constexpr auto
    +  operator () (T &a) const HB_AUTO_RETURN (++a)
    +}
    +HB_FUNCOBJ (hb_inc);
    +struct
    +{
    +  template  constexpr auto
    +  operator () (T &a) const HB_AUTO_RETURN (--a)
    +}
    +HB_FUNCOBJ (hb_dec);
    +
    +
    +/* Compiler-assisted vectorization. */
    +
    +/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
    + * basically a fixed-size bitset. */
    +template 
    +struct hb_vector_size_t
    +{
    +  elt_t& operator [] (unsigned int i) { return v[i]; }
    +  const elt_t& operator [] (unsigned int i) const { return v[i]; }
    +
    +  void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
    +
    +  template 
    +  hb_vector_size_t process (const Op& op) const
    +  {
    +    hb_vector_size_t r;
    +    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
    +      r.v[i] = op (v[i]);
    +    return r;
    +  }
    +  template 
    +  hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const
    +  {
    +    hb_vector_size_t r;
    +    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
    +      r.v[i] = op (v[i], o.v[i]);
    +    return r;
    +  }
    +  hb_vector_size_t operator | (const hb_vector_size_t &o) const
    +  { return process (hb_bitwise_or, o); }
    +  hb_vector_size_t operator & (const hb_vector_size_t &o) const
    +  { return process (hb_bitwise_and, o); }
    +  hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
    +  { return process (hb_bitwise_xor, o); }
    +  hb_vector_size_t operator ~ () const
    +  { return process (hb_bitwise_neg); }
    +
    +  private:
    +  static_assert (0 == byte_size % sizeof (elt_t), "");
    +  elt_t v[byte_size / sizeof (elt_t)];
    +};
    +
    +
    +#endif /* HB_ALGS_HH */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-array.hh
    index 4034d92903a..c6766e61edd 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-array.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-array.hh
    @@ -28,7 +28,7 @@
     #define HB_ARRAY_HH
     
     #include "hb.hh"
    -#include "hb-dsalgs.hh"
    +#include "hb-algs.hh"
     #include "hb-iter.hh"
     #include "hb-null.hh"
     
    @@ -37,22 +37,31 @@ template 
     struct hb_sorted_array_t;
     
     template 
    -struct hb_array_t :
    -        hb_iter_t, Type>,
    -        hb_iter_mixin_t, Type>
    +struct hb_array_t : hb_iter_with_fallback_t, Type&>
     {
       /*
        * Constructors.
        */
    -  hb_array_t () : arrayZ (nullptr), length (0) {}
    -  hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
    -  template  hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {}
    +  hb_array_t () : arrayZ (nullptr), length (0), backwards_length (0) {}
    +  hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_), backwards_length (0) {}
    +  template 
    +  hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_), backwards_length (0) {}
     
    +  template 
    +  hb_array_t (const hb_array_t &o) :
    +    hb_iter_with_fallback_t (),
    +    arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {}
    +  template 
    +  hb_array_t& operator = (const hb_array_t &o)
    +  { arrayZ = o.arrayZ; length = o.length; backwards_length = o.backwards_length; return *this; }
     
       /*
        * Iterator implementation.
        */
    -  typedef Type __item_type__;
    +  typedef Type& __item_t__;
    +  static constexpr bool is_random_access_iterator = true;
       Type& __item_at__ (unsigned i) const
       {
         if (unlikely (i >= length)) return CrapOrNull (Type);
    @@ -63,16 +72,25 @@ struct hb_array_t :
         if (unlikely (n > length))
           n = length;
         length -= n;
    +    backwards_length += n;
         arrayZ += n;
       }
       void __rewind__ (unsigned n)
       {
    -    if (unlikely (n > length))
    -      n = length;
    -    length -= n;
    +    if (unlikely (n > backwards_length))
    +      n = backwards_length;
    +    length += n;
    +    backwards_length -= n;
    +    arrayZ -= n;
       }
       unsigned __len__ () const { return length; }
    -  bool __random_access__ () const { return true; }
    +  /* Ouch. The operator== compares the contents of the array.  For range-based for loops,
    +   * it's best if we can just compare arrayZ, though comparing contents is still fast,
    +   * but also would require that Type has operator==.  As such, we optimize this operator
    +   * for range-based for loop and just compare arrayZ.  No need to compare length, as we
    +   * assume we're only compared to .end(). */
    +  bool operator != (const hb_array_t& o) const
    +  { return arrayZ != o.arrayZ; }
     
       /* Extra operators.
        */
    @@ -80,70 +98,105 @@ struct hb_array_t :
       operator hb_array_t () { return hb_array_t (arrayZ, length); }
       template  operator T * () const { return arrayZ; }
     
    +  HB_INTERNAL bool operator == (const hb_array_t &o) const;
    +
    +  uint32_t hash () const {
    +    uint32_t current = 0;
    +    for (unsigned int i = 0; i < this->length; i++) {
    +      current = current * 31 + hb_hash (this->arrayZ[i]);
    +    }
    +    return current;
    +  }
    +
       /*
        * Compare, Sort, and Search.
        */
     
       /* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
    -  int cmp (const hb_array_t &a) const
    +  int cmp (const hb_array_t &a) const
       {
         if (length != a.length)
           return (int) a.length - (int) length;
         return hb_memcmp (a.arrayZ, arrayZ, get_size ());
       }
    -  static int cmp (const void *pa, const void *pb)
    +  HB_INTERNAL static int cmp (const void *pa, const void *pb)
       {
    -    hb_array_t *a = (hb_array_t *) pa;
    -    hb_array_t *b = (hb_array_t *) pb;
    +    hb_array_t *a = (hb_array_t *) pa;
    +    hb_array_t *b = (hb_array_t *) pb;
         return b->cmp (*a);
       }
     
       template 
       Type *lsearch (const T &x, Type *not_found = nullptr)
       {
    -    unsigned int count = length;
    -    for (unsigned int i = 0; i < count; i++)
    -      if (!this->arrayZ[i].cmp (x))
    -        return &this->arrayZ[i];
    -    return not_found;
    +    unsigned i;
    +    return lfind (x, &i) ? &this->arrayZ[i] : not_found;
       }
       template 
       const Type *lsearch (const T &x, const Type *not_found = nullptr) const
       {
    -    unsigned int count = length;
    -    for (unsigned int i = 0; i < count; i++)
    +    unsigned i;
    +    return lfind (x, &i) ? &this->arrayZ[i] : not_found;
    +  }
    +  template 
    +  bool lfind (const T &x, unsigned *pos = nullptr) const
    +  {
    +    for (unsigned i = 0; i < length; ++i)
           if (!this->arrayZ[i].cmp (x))
    -        return &this->arrayZ[i];
    -    return not_found;
    +      {
    +        if (pos)
    +          *pos = i;
    +        return true;
    +      }
    +
    +    return false;
       }
     
       hb_sorted_array_t qsort (int (*cmp_)(const void*, const void*))
       {
         if (likely (length))
    -      ::qsort (arrayZ, length, this->item_size, cmp_);
    +      hb_qsort (arrayZ, length, this->get_item_size (), cmp_);
         return hb_sorted_array_t (*this);
       }
       hb_sorted_array_t qsort ()
       {
         if (likely (length))
    -      ::qsort (arrayZ, length, this->item_size, Type::cmp);
    +      hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
         return hb_sorted_array_t (*this);
       }
       void qsort (unsigned int start, unsigned int end)
       {
    -    end = MIN (end, length);
    +    end = hb_min (end, length);
         assert (start <= end);
         if (likely (start < end))
    -      ::qsort (arrayZ + start, end - start, this->item_size, Type::cmp);
    +      hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
       }
     
       /*
        * Other methods.
        */
     
    -  unsigned int get_size () const { return length * this->item_size; }
    +  unsigned int get_size () const { return length * this->get_item_size (); }
     
    -  hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
    +  /*
    +   * Reverse the order of items in this array in the range [start, end).
    +   */
    +  void reverse (unsigned start = 0, unsigned end = -1)
    +  {
    +    start = hb_min (start, length);
    +    end = hb_min (end, length);
    +
    +    if (end < start + 2)
    +      return;
    +
    +    for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) {
    +      Type temp = arrayZ[rhs];
    +      arrayZ[rhs] = arrayZ[lhs];
    +      arrayZ[lhs] = temp;
    +    }
    +  }
    +
    +  hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
       {
         if (!start_offset && !seg_count)
           return *this;
    @@ -154,16 +207,45 @@ struct hb_array_t :
         else
           count -= start_offset;
         if (seg_count)
    -      count = *seg_count = MIN (count, *seg_count);
    -    return hb_array_t (arrayZ + start_offset, count);
    +      count = *seg_count = hb_min (count, *seg_count);
    +    return hb_array_t (arrayZ + start_offset, count);
       }
    -  hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
    +  hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
       { return sub_array (start_offset, &seg_count); }
     
    +  hb_array_t truncate (unsigned length) const { return sub_array (0, length); }
    +
    +  template 
    +  const T *as () const
    +  { return length < hb_null_size (T) ? &Null (T) : reinterpret_cast (arrayZ); }
    +
    +  template 
    +  bool check_range (const T *p, unsigned int size = T::static_size) const
    +  {
    +    return arrayZ <= ((const char *) p)
    +        && ((const char *) p) <= arrayZ + length
    +        && (unsigned int) (arrayZ + length - (const char *) p) >= size;
    +  }
    +
       /* Only call if you allocated the underlying array using malloc() or similar. */
       void free ()
       { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
     
    +  template 
    +  hb_array_t copy (hb_serialize_context_t *c) const
    +  {
    +    TRACE_SERIALIZE (this);
    +    auto* out = c->start_embed (arrayZ);
    +    if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
    +    for (unsigned i = 0; i < length; i++)
    +      out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
    +    return_trace (hb_array_t (out, length));
    +  }
    +
       template 
       bool sanitize (hb_sanitize_context_t *c) const
       { return c->check_array (arrayZ, length); }
    @@ -175,6 +257,7 @@ struct hb_array_t :
       public:
       Type *arrayZ;
       unsigned int length;
    +  unsigned int backwards_length;
     };
     template  inline hb_array_t
     hb_array (T *array, unsigned int length)
    @@ -183,7 +266,6 @@ template  inline hb_array_t
     hb_array (T (&array_)[length_])
     { return hb_array_t (array_); }
     
    -
     enum hb_bfind_not_found_t
     {
       HB_BFIND_NOT_FOUND_DONT_STORE,
    @@ -193,20 +275,40 @@ enum hb_bfind_not_found_t
     
     template 
     struct hb_sorted_array_t :
    -        hb_sorted_iter_t, Type>,
    -        hb_array_t,
    -        hb_iter_mixin_t, Type>
    +        hb_iter_t, Type&>,
    +        hb_array_t
     {
    +  typedef hb_iter_t iter_base_t;
    +  HB_ITER_USING (iter_base_t);
    +  static constexpr bool is_random_access_iterator = true;
    +  static constexpr bool is_sorted_iterator = true;
    +
       hb_sorted_array_t () : hb_array_t () {}
    -  hb_sorted_array_t (const hb_array_t &o) : hb_array_t (o) {}
       hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t (array_, length_) {}
    -  template  hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t (array_) {}
    +  template 
    +  hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t (array_) {}
    +
    +  template 
    +  hb_sorted_array_t (const hb_array_t &o) :
    +    hb_iter_t (),
    +    hb_array_t (o) {}
    +  template 
    +  hb_sorted_array_t& operator = (const hb_array_t &o)
    +  { hb_array_t (*this) = o; return *this; }
    +
    +  /* Iterator implementation. */
    +  bool operator != (const hb_sorted_array_t& o) const
    +  { return this->arrayZ != o.arrayZ || this->length != o.length; }
     
    -  hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
    -  { return hb_sorted_array_t (((const hb_array_t *) (this))->sub_array (start_offset, seg_count)); }
    -  hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
    +  hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
    +  { return hb_sorted_array_t (((const hb_array_t *) (this))->sub_array (start_offset, seg_count)); }
    +  hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
       { return sub_array (start_offset, &seg_count); }
     
    +  hb_sorted_array_t truncate (unsigned length) const { return sub_array (0, length); }
    +
       template 
       Type *bsearch (const T &x, Type *not_found = nullptr)
       {
    @@ -221,26 +323,18 @@ struct hb_sorted_array_t :
       }
       template 
       bool bfind (const T &x, unsigned int *i = nullptr,
    -                     hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
    -                     unsigned int to_store = (unsigned int) -1) const
    +              hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
    +              unsigned int to_store = (unsigned int) -1) const
       {
    -    int min = 0, max = (int) this->length - 1;
    -    const Type *array = this->arrayZ;
    -    while (min <= max)
    +    unsigned pos;
    +
    +    if (bsearch_impl (x, &pos))
         {
    -      int mid = ((unsigned int) min + (unsigned int) max) / 2;
    -      int c = array[mid].cmp (x);
    -      if (c < 0)
    -        max = mid - 1;
    -      else if (c > 0)
    -        min = mid + 1;
    -      else
    -      {
    -        if (i)
    -          *i = mid;
    -        return true;
    -      }
    +      if (i)
    +        *i = pos;
    +      return true;
         }
    +
         if (i)
         {
           switch (not_found)
    @@ -253,14 +347,22 @@ struct hb_sorted_array_t :
               break;
     
             case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
    -          if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
    -            max++;
    -          *i = max;
    +          *i = pos;
               break;
           }
         }
         return false;
       }
    +  template 
    +  bool bsearch_impl (const T &x, unsigned *pos) const
    +  {
    +    return hb_bsearch_impl (pos,
    +                            x,
    +                            this->arrayZ,
    +                            this->length,
    +                            sizeof (Type),
    +                            _hb_cmp_method);
    +  }
     };
     template  inline hb_sorted_array_t
     hb_sorted_array (T *array, unsigned int length)
    @@ -269,9 +371,38 @@ template  inline hb_sorted_array_t
     hb_sorted_array (T (&array_)[length_])
     { return hb_sorted_array_t (array_); }
     
    +template 
    +bool hb_array_t::operator == (const hb_array_t &o) const
    +{
    +  if (o.length != this->length) return false;
    +  for (unsigned int i = 0; i < this->length; i++) {
    +    if (this->arrayZ[i] != o.arrayZ[i]) return false;
    +  }
    +  return true;
    +}
    +
    +/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */
    +
    +template <>
    +inline uint32_t hb_array_t::hash () const {
    +  uint32_t current = 0;
    +  for (unsigned int i = 0; i < this->length; i++)
    +    current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
    +  return current;
    +}
    +
    +template <>
    +inline uint32_t hb_array_t::hash () const {
    +  uint32_t current = 0;
    +  for (unsigned int i = 0; i < this->length; i++)
    +    current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
    +  return current;
    +}
    +
     
     typedef hb_array_t hb_bytes_t;
     typedef hb_array_t hb_ubytes_t;
     
     
    +
     #endif /* HB_ARRAY_HH */
    diff --git a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
    index d1ff7a722ef..a6877f8e674 100644
    --- a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
    +++ b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh
    @@ -33,6 +33,7 @@
     #define HB_ATOMIC_HH
     
     #include "hb.hh"
    +#include "hb-meta.hh"
     
     
     /*
    @@ -85,11 +86,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
     #define hb_atomic_int_impl_add(AI, V)           (reinterpret_cast *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
     #define hb_atomic_int_impl_set_relaxed(AI, V)   (reinterpret_cast *> (AI)->store ((V), std::memory_order_relaxed))
     #define hb_atomic_int_impl_set(AI, V)           (reinterpret_cast *> (AI)->store ((V), std::memory_order_release))
    -#define hb_atomic_int_impl_get_relaxed(AI)      (reinterpret_cast *> (AI)->load (std::memory_order_relaxed))
    -#define hb_atomic_int_impl_get(AI)              (reinterpret_cast *> (AI)->load (std::memory_order_acquire))
    +#define hb_atomic_int_impl_get_relaxed(AI)      (reinterpret_cast const *> (AI)->load (std::memory_order_relaxed))
    +#define hb_atomic_int_impl_get(AI)              (reinterpret_cast const *> (AI)->load (std::memory_order_acquire))
     
     #define hb_atomic_ptr_impl_set_relaxed(P, V)    (reinterpret_cast *> (P)->store ((V), std::memory_order_relaxed))
    -#define hb_atomic_ptr_impl_get_relaxed(P)       (reinterpret_cast *> (P)->load (std::memory_order_relaxed))
    +#define hb_atomic_ptr_impl_get_relaxed(P)       (reinterpret_cast const *> (P)->load (std::memory_order_relaxed))
     #define hb_atomic_ptr_impl_get(P)               (reinterpret_cast *> (P)->load (std::memory_order_acquire))
     static inline bool
     _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
    @@ -106,7 +107,7 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
     
     static inline void _hb_memory_barrier ()
     {
    -#if !defined(MemoryBarrier)
    +#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
       /* MinGW has a convoluted history of supporting MemoryBarrier. */
       LONG dummy = 0;
       InterlockedExchange (&dummy, 1);
    @@ -211,25 +212,19 @@ static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
     static_assert ((sizeof (long) == sizeof (void *)), "");
     
     
    -#elif !defined(HB_NO_MT)
    -
    -#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
    -
    -#define _hb_memory_barrier()
    +#elif defined(HB_NO_MT)
     
     #define hb_atomic_int_impl_add(AI, V)           ((*(AI) += (V)) - (V))
     
    -#define hb_atomic_ptr_impl_cmpexch(P,O,N)       (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
    -
    -
    -#else /* HB_NO_MT */
    +#define _hb_memory_barrier()                    do {} while (0)
     
    -#define hb_atomic_int_impl_add(AI, V)           ((*(AI) += (V)) - (V))
    +#define hb_atomic_ptr_impl_cmpexch(P,O,N)       (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
     
    -#define _hb_memory_barrier()
     
    -#define hb_atomic_ptr_impl_cmpexch(P,O,N)       (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
    +#else
     
    +#error "Could not find any system to define atomic_int macros."
    +#error "Check hb-atomic.hh for possible resolutions."
     
     #endif
     
    @@ -282,7 +277,7 @@ struct hb_atomic_int_t
     template 
     struct hb_atomic_ptr_t
     {
    -  typedef typename hb_remove_pointer (P) T;
    +  typedef hb_remove_pointer

    T; void init (T* v_ = nullptr) { set_relaxed (v_); } void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh new file mode 100644 index 00000000000..ff47c6f2476 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-bimap.hh @@ -0,0 +1,166 @@ +/* + * Copyright © 2019 Adobe Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_BIMAP_HH +#define HB_BIMAP_HH + +#include "hb.hh" +#include "hb-map.hh" + +/* Bi-directional map */ +struct hb_bimap_t +{ + hb_bimap_t () { init (); } + ~hb_bimap_t () { fini (); } + + void init () + { + forw_map.init (); + back_map.init (); + } + + void fini () + { + forw_map.fini (); + back_map.fini (); + } + + void reset () + { + forw_map.reset (); + back_map.reset (); + } + + bool in_error () const { return forw_map.in_error () || back_map.in_error (); } + + void set (hb_codepoint_t lhs, hb_codepoint_t rhs) + { + if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return; + if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; } + forw_map.set (lhs, rhs); + back_map.set (rhs, lhs); + } + + hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); } + hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); } + + hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); } + bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); } + + void del (hb_codepoint_t lhs) + { + back_map.del (get (lhs)); + forw_map.del (lhs); + } + + void clear () + { + forw_map.clear (); + back_map.clear (); + } + + bool is_empty () const { return get_population () == 0; } + + unsigned int get_population () const { return forw_map.get_population (); } + + protected: + hb_map_t forw_map; + hb_map_t back_map; +}; + +/* Inremental bimap: only lhs is given, rhs is incrementally assigned */ +struct hb_inc_bimap_t : hb_bimap_t +{ + hb_inc_bimap_t () { init (); } + + void init () + { + hb_bimap_t::init (); + next_value = 0; + } + + /* Add a mapping from lhs to rhs with a unique value if lhs is unknown. + * Return the rhs value as the result. + */ + hb_codepoint_t add (hb_codepoint_t lhs) + { + hb_codepoint_t rhs = forw_map[lhs]; + if (rhs == HB_MAP_VALUE_INVALID) + { + rhs = next_value++; + set (lhs, rhs); + } + return rhs; + } + + hb_codepoint_t skip () + { return next_value++; } + + hb_codepoint_t get_next_value () const + { return next_value; } + + void add_set (const hb_set_t *set) + { + hb_codepoint_t i = HB_SET_VALUE_INVALID; + while (hb_set_next (set, &i)) add (i); + } + + /* Create an identity map. */ + bool identity (unsigned int size) + { + clear (); + for (hb_codepoint_t i = 0; i < size; i++) set (i, i); + return !in_error (); + } + + protected: + static int cmp_id (const void* a, const void* b) + { return (int)*(const hb_codepoint_t *)a - (int)*(const hb_codepoint_t *)b; } + + public: + /* Optional: after finished adding all mappings in a random order, + * reassign rhs to lhs so that they are in the same order. */ + void sort () + { + hb_codepoint_t count = get_population (); + hb_vector_t work; + work.resize (count); + + for (hb_codepoint_t rhs = 0; rhs < count; rhs++) + work[rhs] = back_map[rhs]; + + work.qsort (cmp_id); + + clear (); + for (hb_codepoint_t rhs = 0; rhs < count; rhs++) + set (work[rhs], rhs); + } + + protected: + unsigned int next_value; +}; + +#endif /* HB_BIMAP_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc index ffeecc2a168..fc18b61c913 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc @@ -25,18 +25,6 @@ * Red Hat Author(s): Behdad Esfahbod */ - -/* https://github.com/harfbuzz/harfbuzz/issues/1308 - * http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html - * https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html - */ -#ifndef _POSIX_C_SOURCE -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-macros" -#define _POSIX_C_SOURCE 200809L -#pragma GCC diagnostic pop -#endif - #include "hb.hh" #include "hb-blob.hh" @@ -48,7 +36,6 @@ #endif /* HAVE_SYS_MMAN_H */ #include -#include #include @@ -155,7 +142,7 @@ hb_blob_create_sub_blob (hb_blob_t *parent, hb_blob_make_immutable (parent); blob = hb_blob_create (parent->data + offset, - MIN (length, parent->length - offset), + hb_min (length, parent->length - offset), HB_MEMORY_MODE_READONLY, hb_blob_reference (parent), _hb_blob_destroy); @@ -202,7 +189,7 @@ hb_blob_copy_writable_or_fail (hb_blob_t *blob) hb_blob_t * hb_blob_get_empty () { - return const_cast (&Null(hb_blob_t)); + return const_cast (&Null (hb_blob_t)); } /** @@ -487,7 +474,11 @@ hb_blob_t::try_make_writable () * Mmap */ +#ifndef HB_NO_OPEN #ifdef HAVE_MMAP +# if !defined(HB_NO_RESOURCE_FORK) && defined(__APPLE__) +# include +# endif # include # include # include @@ -532,6 +523,39 @@ _hb_mapped_file_destroy (void *file_) } #endif +#ifdef _PATH_RSRCFORKSPEC +static int +_open_resource_fork (const char *file_name, hb_mapped_file_t *file) +{ + size_t name_len = strlen (file_name); + size_t len = name_len + sizeof (_PATH_RSRCFORKSPEC); + + char *rsrc_name = (char *) malloc (len); + if (unlikely (!rsrc_name)) return -1; + + strncpy (rsrc_name, file_name, name_len); + strncpy (rsrc_name + name_len, _PATH_RSRCFORKSPEC, + sizeof (_PATH_RSRCFORKSPEC) - 1); + + int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0); + free (rsrc_name); + + if (fd != -1) + { + struct stat st; + if (fstat (fd, &st) != -1) + file->length = (unsigned long) st.st_size; + else + { + close (fd); + fd = -1; + } + } + + return fd; +} +#endif + /** * hb_blob_create_from_file: * @file_name: font filename. @@ -556,6 +580,19 @@ hb_blob_create_from_file (const char *file_name) if (unlikely (fstat (fd, &st) == -1)) goto fail; file->length = (unsigned long) st.st_size; + +#ifdef _PATH_RSRCFORKSPEC + if (unlikely (file->length == 0)) + { + int rfd = _open_resource_fork (file_name, file); + if (rfd != -1) + { + close (fd); + fd = rfd; + } + } +#endif + file->contents = (char *) mmap (nullptr, file->length, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0); @@ -579,9 +616,9 @@ hb_blob_create_from_file (const char *file_name) HANDLE fd; unsigned int size = strlen (file_name) + 1; wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size); - if (unlikely (wchar_file_name == nullptr)) goto fail_without_close; + if (unlikely (!wchar_file_name)) goto fail_without_close; mbstowcs (wchar_file_name, file_name, size); -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) { CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); @@ -602,7 +639,7 @@ hb_blob_create_from_file (const char *file_name) if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) { LARGE_INTEGER length; GetFileSizeEx (fd, &length); @@ -613,14 +650,14 @@ hb_blob_create_from_file (const char *file_name) file->length = (unsigned long) GetFileSize (fd, nullptr); file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr); #endif - if (unlikely (file->mapping == nullptr)) goto fail; + if (unlikely (!file->mapping)) goto fail; -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); #else file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); #endif - if (unlikely (file->contents == nullptr)) goto fail; + if (unlikely (!file->contents)) goto fail; CloseHandle (fd); return hb_blob_create (file->contents, file->length, @@ -638,10 +675,10 @@ hb_blob_create_from_file (const char *file_name) It's used as a fallback for systems without mmap or to read from pipes */ unsigned long len = 0, allocated = BUFSIZ * 16; char *data = (char *) malloc (allocated); - if (unlikely (data == nullptr)) return hb_blob_get_empty (); + if (unlikely (!data)) return hb_blob_get_empty (); FILE *fp = fopen (file_name, "rb"); - if (unlikely (fp == nullptr)) goto fread_fail_without_close; + if (unlikely (!fp)) goto fread_fail_without_close; while (!feof (fp)) { @@ -652,7 +689,7 @@ hb_blob_create_from_file (const char *file_name) can cover files like that but lets limit our fallback reader */ if (unlikely (allocated > (2 << 28))) goto fread_fail; char *new_data = (char *) realloc (data, allocated); - if (unlikely (new_data == nullptr)) goto fread_fail; + if (unlikely (!new_data)) goto fread_fail; data = new_data; } @@ -666,6 +703,7 @@ hb_blob_create_from_file (const char *file_name) len += addition; } + fclose (fp); return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data, (hb_destroy_func_t) free); @@ -676,3 +714,4 @@ hb_blob_create_from_file (const char *file_name) free (data); return hb_blob_get_empty (); } +#endif /* !HB_NO_OPEN */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.h b/src/java.desktop/share/native/libharfbuzz/hb-blob.h index a714fb2057b..ddbcd1a999c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-blob.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.h @@ -71,6 +71,9 @@ hb_blob_create (const char *data, void *user_data, hb_destroy_func_t destroy); +HB_EXTERN hb_blob_t * +hb_blob_create_from_file (const char *file_name); + /* Always creates with MEMORY_MODE_READONLY. * Even if the parent blob is writable, we don't * want the user of the sub-blob to be able to @@ -123,9 +126,6 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length); HB_EXTERN char * hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length); -HB_EXTERN hb_blob_t * -hb_blob_create_from_file (const char *file_name); - HB_END_DECLS #endif /* HB_BLOB_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.hh b/src/java.desktop/share/native/libharfbuzz/hb-blob.hh index 4ea13f81370..d85bd823b00 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-blob.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.hh @@ -54,13 +54,9 @@ struct hb_blob_t HB_INTERNAL bool try_make_writable_inplace (); HB_INTERNAL bool try_make_writable_inplace_unix (); + hb_bytes_t as_bytes () const { return hb_bytes_t (data, length); } template - const Type* as () const - { - return length < hb_null_size (Type) ? &Null(Type) : reinterpret_cast (data); - } - hb_bytes_t as_bytes () const - { return hb_bytes_t (data, length); } + const Type* as () const { return as_bytes ().as (); } public: hb_object_header_t header; @@ -81,7 +77,7 @@ struct hb_blob_t template struct hb_blob_ptr_t { - typedef typename hb_remove_pointer (P) T; + typedef hb_remove_pointer

    T; hb_blob_ptr_t (hb_blob_t *b_ = nullptr) : b (b_) {} hb_blob_t * operator = (hb_blob_t *b_) { return b = b_; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc index 14a9a568c7e..52dbb84bb3f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_BUFFER_SERIALIZE + #include "hb-buffer.hh" @@ -85,7 +89,7 @@ hb_buffer_serialize_format_from_string (const char *str, int len) const char * hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format) { - switch (format) + switch ((unsigned) format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0]; case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1]; @@ -138,34 +142,34 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, *p++ = '"'; } else - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster)); } if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) { - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d", x+pos[i].x_offset, y+pos[i].y_offset)); if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d", pos[i].x_advance, pos[i].y_advance)); } if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS) { if (info[i].mask & HB_GLYPH_FLAG_DEFINED) - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED)); } if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) { hb_glyph_extents_t extents; hb_font_get_glyph_extents(font, info[i].codepoint, &extents); - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d", + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d", extents.x_bearing, extents.y_bearing)); - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d", + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d", extents.width, extents.height)); } @@ -224,37 +228,37 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, p += strlen (p); } else - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint)); if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) { - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster)); } if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS)) { if (x+pos[i].x_offset || y+pos[i].y_offset) - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset)); if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES)) { *p++ = '+'; - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance)); if (pos[i].y_advance) - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance)); } } if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS) { if (info[i].mask & HB_GLYPH_FLAG_DEFINED) - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED)); } if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS) { hb_glyph_extents_t extents; hb_font_get_glyph_extents(font, info[i].codepoint, &extents); - p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height)); + p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height)); } unsigned int l = p - b; @@ -344,8 +348,8 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, if (buf_size) *buf = '\0'; - assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || - buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + assert ((!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)) || + (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)); if (!buffer->have_positions) flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS; @@ -375,43 +379,24 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, } } - -static hb_bool_t -parse_uint (const char *pp, const char *end, uint32_t *pv) +static bool +parse_int (const char *pp, const char *end, int32_t *pv) { - char buf[32]; - unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); - strncpy (buf, pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - uint32_t v; - - errno = 0; - v = strtol (p, &pend, 10); - if (errno || p == pend || pend - p != end - pp) + int v; + const char *p = pp; + if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */))) return false; *pv = v; return true; } -static hb_bool_t -parse_int (const char *pp, const char *end, int32_t *pv) +static bool +parse_uint (const char *pp, const char *end, uint32_t *pv) { - char buf[32]; - unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp)); - strncpy (buf, pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - int32_t v; - - errno = 0; - v = strtol (p, &pend, 10); - if (errno || p == pend || pend - p != end - pp) + unsigned int v; + const char *p = pp; + if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */))) return false; *pv = v; @@ -449,8 +434,8 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, end_ptr = &end; *end_ptr = buf; - assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) || - buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS); + assert ((!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)) || + (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS)); if (buf_len == -1) buf_len = strlen (buf); @@ -484,3 +469,6 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, } } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc index f9a46d12b3c..2da3c486e22 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc @@ -324,7 +324,7 @@ hb_buffer_t::clear_positions () out_len = 0; out_info = info; - memset (pos, 0, sizeof (pos[0]) * len); + hb_memset (pos, 0, sizeof (pos[0]) * len); } void @@ -438,13 +438,6 @@ hb_buffer_t::set_masks (hb_mask_t value, if (!mask) return; - if (cluster_start == 0 && cluster_end == (unsigned int)-1) { - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - info[i].mask = (info[i].mask & not_mask) | value; - return; - } - unsigned int count = len; for (unsigned int i = 0; i < count; i++) if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end) @@ -455,27 +448,13 @@ void hb_buffer_t::reverse_range (unsigned int start, unsigned int end) { - unsigned int i, j; - if (end - start < 2) return; - for (i = start, j = end - 1; i < j; i++, j--) { - hb_glyph_info_t t; - - t = info[i]; - info[i] = info[j]; - info[j] = t; - } + hb_array_t (info, len).reverse (start, end); if (have_positions) { - for (i = start, j = end - 1; i < j; i++, j--) { - hb_glyph_position_t t; - - t = pos[i]; - pos[i] = pos[j]; - pos[j] = t; - } + hb_array_t (pos, len).reverse (start, end); } } @@ -524,7 +503,7 @@ hb_buffer_t::merge_clusters_impl (unsigned int start, unsigned int cluster = info[start].cluster; for (unsigned int i = start + 1; i < end; i++) - cluster = MIN (cluster, info[i].cluster); + cluster = hb_min (cluster, info[i].cluster); /* Extend end */ while (end < len && info[end - 1].cluster == info[end].cluster) @@ -555,7 +534,7 @@ hb_buffer_t::merge_out_clusters (unsigned int start, unsigned int cluster = out_info[start].cluster; for (unsigned int i = start + 1; i < end; i++) - cluster = MIN (cluster, out_info[i].cluster); + cluster = hb_min (cluster, out_info[i].cluster); /* Extend start */ while (start && out_info[start - 1].cluster == out_info[start].cluster) @@ -612,7 +591,7 @@ hb_buffer_t::delete_glyph () void hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end) { - unsigned int cluster = (unsigned int) -1; + unsigned int cluster = UINT_MAX; cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster); _unsafe_to_break_set_mask (info, start, end, cluster); } @@ -628,7 +607,7 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en assert (start <= out_len); assert (idx <= end); - unsigned int cluster = (unsigned int) -1; + unsigned int cluster = UINT_MAX; cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster); cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster); _unsafe_to_break_set_mask (out_info, start, out_len, cluster); @@ -638,8 +617,8 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en void hb_buffer_t::guess_segment_properties () { - assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || - (!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); + assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) || + (!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID))); /* If script is set to INVALID, guess from buffer contents */ if (props.script == HB_SCRIPT_INVALID) { @@ -736,7 +715,7 @@ hb_buffer_create () hb_buffer_t * hb_buffer_get_empty () { - return const_cast (&Null(hb_buffer_t)); + return const_cast (&Null (hb_buffer_t)); } /** @@ -776,8 +755,10 @@ hb_buffer_destroy (hb_buffer_t *buffer) free (buffer->info); free (buffer->pos); +#ifndef HB_NO_BUFFER_MESSAGE if (buffer->message_destroy) buffer->message_destroy (buffer->message_data); +#endif free (buffer); } @@ -956,7 +937,7 @@ hb_buffer_get_direction (hb_buffer_t *buffer) * * You can pass one of the predefined #hb_script_t values, or use * hb_script_from_string() or hb_script_from_iso15924_tag() to get the - * corresponding script from an ISO 15924 script tag. + * corresponding script from an ISO 15924 script tag. * * Since: 0.9.2 **/ @@ -999,7 +980,7 @@ hb_buffer_get_script (hb_buffer_t *buffer) * are orthogonal to the scripts, and though they are related, they are * different concepts and should not be confused with each other. * - * Use hb_language_from_string() to convert from BCP 47 language tags to + * Use hb_language_from_string() to convert from BCP 47 language tags to * #hb_language_t. * * Since: 0.9.2 @@ -1115,8 +1096,8 @@ hb_buffer_get_flags (hb_buffer_t *buffer) * Since: 0.9.42 **/ void -hb_buffer_set_cluster_level (hb_buffer_t *buffer, - hb_buffer_cluster_level_t cluster_level) +hb_buffer_set_cluster_level (hb_buffer_t *buffer, + hb_buffer_cluster_level_t cluster_level) { if (unlikely (hb_object_is_immutable (buffer))) return; @@ -1532,8 +1513,8 @@ hb_buffer_add_utf (hb_buffer_t *buffer, typedef typename utf_t::codepoint_t T; const hb_codepoint_t replacement = buffer->replacement; - assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE || - (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); + assert ((buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) || + (!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID))); if (unlikely (hb_object_is_immutable (buffer))) return; @@ -1736,7 +1717,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer, * @buffer: an #hb_buffer_t. * @source: source #hb_buffer_t. * @start: start index into source buffer to copy. Use 0 to copy from start of buffer. - * @end: end index into source buffer to copy. Use (unsigned int) -1 to copy to end of buffer. + * @end: end index into source buffer to copy. Use @HB_FEATURE_GLOBAL_END to copy to end of buffer. * * Append (part of) contents of another buffer to this buffer. * @@ -1853,23 +1834,13 @@ void hb_buffer_normalize_glyphs (hb_buffer_t *buffer) { assert (buffer->have_positions); - assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS || - (!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)); + assert ((buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS) || + (!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID))); bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); - unsigned int count = buffer->len; - if (unlikely (!count)) return; - hb_glyph_info_t *info = buffer->info; - - unsigned int start = 0; - unsigned int end; - for (end = start + 1; end < count; end++) - if (info[start].cluster != info[end].cluster) { - normalize_glyphs_cluster (buffer, start, end, backward); - start = end; - } - normalize_glyphs_cluster (buffer, start, end, backward); + foreach_cluster (buffer, start, end) + normalize_glyphs_cluster (buffer, start, end, backward); } void @@ -1993,6 +1964,7 @@ hb_buffer_diff (hb_buffer_t *buffer, * Debugging. */ +#ifndef HB_NO_BUFFER_MESSAGE /** * hb_buffer_set_message_func: * @buffer: an #hb_buffer_t. @@ -2022,11 +1994,11 @@ hb_buffer_set_message_func (hb_buffer_t *buffer, buffer->message_destroy = nullptr; } } - bool hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap) { char buf[100]; - vsnprintf (buf, sizeof (buf), fmt, ap); + vsnprintf (buf, sizeof (buf), fmt, ap); return (bool) this->message_func (this, font, buf, this->message_data); } +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h index f5a724cfb43..1a7ca4069e5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h @@ -284,6 +284,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer); * space glyph and zeroing the advance width.) * @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes * precedence over this flag. Since: 1.8.0 + * @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE: + * flag indicating that a dotted circle should + * not be inserted in the rendering of incorrect + * character sequences (such at <0905 093E>). Since: 2.4 * * Since: 0.9.20 */ @@ -292,7 +296,8 @@ typedef enum { /*< flags >*/ HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */ HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */ HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u, - HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u + HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u, + HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u } hb_buffer_flags_t; HB_EXTERN void diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh index 6416a5328d9..c4ef466b7a7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh @@ -124,9 +124,11 @@ struct hb_buffer_t unsigned int context_len[2]; /* Debugging API */ +#ifndef HB_NO_BUFFER_MESSAGE hb_buffer_message_func_t message_func; void *message_data; hb_destroy_func_t message_destroy; +#endif /* Internal debugging. */ /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */ @@ -226,10 +228,10 @@ struct hb_buffer_t /* Makes a copy of the glyph at idx to output and replace glyph_index */ hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index) { - if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t); + if (unlikely (!make_room_for (0, 1))) return Crap (hb_glyph_info_t); if (unlikely (idx == len && !out_len)) - return Crap(hb_glyph_info_t); + return Crap (hb_glyph_info_t); out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1]; out_info[out_len].codepoint = glyph_index; @@ -316,7 +318,7 @@ struct hb_buffer_t HB_INTERNAL void delete_glyph (); void unsafe_to_break (unsigned int start, - unsigned int end) + unsigned int end) { if (end - start < 2) return; @@ -347,9 +349,19 @@ struct hb_buffer_t HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *)); - bool messaging () { return unlikely (message_func); } + bool messaging () + { +#ifdef HB_NO_BUFFER_MESSAGE + return false; +#else + return unlikely (message_func); +#endif + } bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4) { +#ifdef HB_NO_BUFFER_MESSAGE + return true; +#else if (!messaging ()) return true; va_list ap; @@ -357,6 +369,7 @@ struct hb_buffer_t bool ret = message_impl (font, fmt, ap); va_end (ap); return ret; +#endif } HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0); @@ -373,13 +386,13 @@ struct hb_buffer_t inf.cluster = cluster; } - int + unsigned int _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos, unsigned int start, unsigned int end, unsigned int cluster) const { for (unsigned int i = start; i < end; i++) - cluster = MIN (cluster, infos[i].cluster); + cluster = hb_min (cluster, infos[i].cluster); return cluster; } void @@ -395,8 +408,7 @@ struct hb_buffer_t } } - void unsafe_to_break_all () - { unsafe_to_break_impl (0, len); } + void unsafe_to_break_all () { unsafe_to_break_impl (0, len); } void safe_to_break_all () { for (unsigned int i = 0; i < len; i++) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh index a013e96dc43..3fcd5575122 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh @@ -220,32 +220,22 @@ struct number_t void init () { set_real (0.0); } void fini () {} - void set_int (int v) { value = (double) v; } - int to_int () const { return (int) value; } + void set_int (int v) { value = v; } + int to_int () const { return value; } void set_fixed (int32_t v) { value = v / 65536.0; } - int32_t to_fixed () const { return (int32_t) (value * 65536.0); } + int32_t to_fixed () const { return value * 65536.0; } - void set_real (double v) { value = v; } + void set_real (double v) { value = v; } double to_real () const { return value; } - int ceil () const { return (int) ::ceil (value); } - int floor () const { return (int) ::floor (value); } - bool in_int_range () const { return ((double) (int16_t) to_int () == value); } - bool operator > (const number_t &n) const - { return value > n.to_real (); } - - bool operator < (const number_t &n) const - { return n > *this; } - - bool operator >= (const number_t &n) const - { return !(*this < n); } - - bool operator <= (const number_t &n) const - { return !(*this > n); } + bool operator > (const number_t &n) const { return value > n.to_real (); } + bool operator < (const number_t &n) const { return n > *this; } + bool operator >= (const number_t &n) const { return !(*this < n); } + bool operator <= (const number_t &n) const { return !(*this > n); } const number_t &operator += (const number_t &n) { @@ -255,37 +245,34 @@ struct number_t } protected: - double value; + double value; }; /* byte string */ struct UnsizedByteStr : UnsizedArrayOf { // encode 2-byte int (Dict/CharString) or 4-byte int (Dict) - template - static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, int value) + template + static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value) { TRACE_SERIALIZE (this); - if (unlikely ((value < minVal || value > maxVal))) - return_trace (false); - HBUINT8 *p = c->allocate_size (1); - if (unlikely (p == nullptr)) return_trace (false); - p->set (intOp); - - INTTYPE *ip = c->allocate_size (INTTYPE::static_size); - if (unlikely (ip == nullptr)) return_trace (false); - ip->set ((unsigned int)value); + if (unlikely (!p)) return_trace (false); + *p = intOp; - return_trace (true); + T *ip = c->allocate_size (T::static_size); + if (unlikely (!ip)) return_trace (false); + return_trace (c->check_assign (*ip, value)); } - static bool serialize_int4 (hb_serialize_context_t *c, int value) - { return serialize_int (c, OpCode_longintdict, value); } + template + static bool serialize_int4 (hb_serialize_context_t *c, V value) + { return serialize_int (c, OpCode_longintdict, value); } - static bool serialize_int2 (hb_serialize_context_t *c, int value) - { return serialize_int (c, OpCode_shortint, value); } + template + static bool serialize_int2 (hb_serialize_context_t *c, V value) + { return serialize_int (c, OpCode_shortint, value); } /* Defining null_size allows a Null object may be created. Should be safe because: * A descendent struct Dict uses a Null pointer to indicate a missing table, @@ -320,8 +307,7 @@ struct byte_str_t : hb_ubytes_t /* A byte string associated with the current offset and an error condition */ struct byte_str_ref_t { - byte_str_ref_t () - { init (); } + byte_str_ref_t () { init (); } void init () { @@ -343,13 +329,12 @@ struct byte_str_ref_t } const unsigned char& operator [] (int i) { - if (unlikely ((unsigned int)(offset + i) >= str.length)) + if (unlikely ((unsigned int) (offset + i) >= str.length)) { set_error (); - return Null(unsigned char); + return Null (unsigned char); } - else - return str[offset + i]; + return str[offset + i]; } /* Conversion to byte_str_t */ @@ -359,9 +344,7 @@ struct byte_str_ref_t { return str.sub_str (offset_, len_); } bool avail (unsigned int count=1) const - { - return (!in_error () && str.check_limit (offset, count)); - } + { return (!in_error () && str.check_limit (offset, count)); } void inc (unsigned int count=1) { if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length))) @@ -389,7 +372,7 @@ typedef hb_vector_t byte_str_array_t; /* stack */ template -struct stack_t +struct cff_stack_t { void init () { @@ -400,11 +383,7 @@ struct stack_t for (unsigned int i = 0; i < elements.length; i++) elements[i].init (); } - - void fini () - { - elements.fini_deep (); - } + void fini () { elements.fini_deep (); } ELEM& operator [] (unsigned int i) { @@ -419,7 +398,6 @@ struct stack_t else set_error (); } - ELEM &push () { if (likely (count < elements.length)) @@ -427,7 +405,7 @@ struct stack_t else { set_error (); - return Crap(ELEM); + return Crap (ELEM); } } @@ -438,10 +416,9 @@ struct stack_t else { set_error (); - return Crap(ELEM); + return Crap (ELEM); } } - void pop (unsigned int n) { if (likely (count >= n)) @@ -452,13 +429,12 @@ struct stack_t const ELEM& peek () { - if (likely (count > 0)) - return elements[count-1]; - else + if (unlikely (count < 0)) { set_error (); - return Null(ELEM); + return Null (ELEM); } + return elements[count - 1]; } void unpop () @@ -475,7 +451,7 @@ struct stack_t void set_error () { error = true; } unsigned int get_count () const { return count; } - bool is_empty () const { return count == 0; } + bool is_empty () const { return !count; } static constexpr unsigned kSizeLimit = LIMIT; @@ -487,7 +463,7 @@ struct stack_t /* argument stack */ template -struct arg_stack_t : stack_t +struct arg_stack_t : cff_stack_t { void push_int (int v) { @@ -519,7 +495,7 @@ struct arg_stack_t : stack_t i = 0; S::set_error (); } - return (unsigned)i; + return (unsigned) i; } void push_longint_from_substr (byte_str_ref_t& str_ref) @@ -538,12 +514,10 @@ struct arg_stack_t : stack_t } hb_array_t get_subarray (unsigned int start) const - { - return S::elements.sub_array (start); - } + { return S::elements.sub_array (start); } private: - typedef stack_t S; + typedef cff_stack_t S; }; /* an operator prefixed by its operands in a byte string */ @@ -565,7 +539,7 @@ struct op_serializer_t TRACE_SERIALIZE (this); HBUINT8 *d = c->allocate_size (opstr.str.length); - if (unlikely (d == nullptr)) return_trace (false); + if (unlikely (!d)) return_trace (false); memcpy (d, &opstr.str[0], opstr.str.length); return_trace (true); } @@ -605,7 +579,7 @@ struct parsed_values_t } unsigned get_count () const { return values.length; } - const VAL &get_value (unsigned int i) const { return values[i]; } + const VAL &get_value (unsigned int i) const { return values[i]; } const VAL &operator [] (unsigned int i) const { return get_value (i); } unsigned int opStart; @@ -644,30 +618,19 @@ struct interp_env_t return op; } - const ARG& eval_arg (unsigned int i) - { - return argStack[i]; - } + const ARG& eval_arg (unsigned int i) { return argStack[i]; } - ARG& pop_arg () - { - return argStack.pop (); - } + ARG& pop_arg () { return argStack.pop (); } + void pop_n_args (unsigned int n) { argStack.pop (n); } - void pop_n_args (unsigned int n) - { - argStack.pop (n); - } - - void clear_args () - { - pop_n_args (argStack.get_count ()); - } + void clear_args () { pop_n_args (argStack.get_count ()); } - byte_str_ref_t str_ref; - arg_stack_t argStack; + byte_str_ref_t + str_ref; + arg_stack_t + argStack; protected: - bool error; + bool error; }; typedef interp_env_t<> num_interp_env_t; @@ -691,7 +654,7 @@ struct opset_t case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1: case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3: - env.argStack.push_int ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108)); + env.argStack.push_int ((-(int16_t)(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108)); env.str_ref.inc (); break; @@ -711,8 +674,8 @@ struct opset_t }; template -struct interpreter_t { - +struct interpreter_t +{ ~interpreter_t() { fini (); } void fini () { env.fini (); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh index d6d7f857ecb..1b0d795c7cb 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh @@ -57,14 +57,14 @@ struct call_context_t /* call stack */ const unsigned int kMaxCallLimit = 10; -struct call_stack_t : stack_t {}; +struct call_stack_t : cff_stack_t {}; template struct biased_subrs_t { - void init (const SUBRS &subrs_) + void init (const SUBRS *subrs_) { - subrs = &subrs_; + subrs = subrs_; unsigned int nSubrs = get_count (); if (nSubrs < 1240) bias = 107; @@ -76,13 +76,13 @@ struct biased_subrs_t void fini () {} - unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; } - unsigned int get_bias () const { return bias; } + unsigned int get_count () const { return subrs ? subrs->count : 0; } + unsigned int get_bias () const { return bias; } byte_str_t operator [] (unsigned int index) const { - if (unlikely ((subrs == nullptr) || index >= subrs->count)) - return Null(byte_str_t); + if (unlikely (!subrs || index >= subrs->count)) + return Null (byte_str_t); else return (*subrs)[index]; } @@ -118,7 +118,7 @@ struct point_t template struct cs_interp_env_t : interp_env_t { - void init (const byte_str_t &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_) + void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_) { interp_env_t::init (str); @@ -147,8 +147,9 @@ struct cs_interp_env_t : interp_env_t return callStack.in_error () || SUPER::in_error (); } - bool popSubrNum (const biased_subrs_t& biasedSubrs, unsigned int &subr_num) + bool pop_subr_num (const biased_subrs_t& biasedSubrs, unsigned int &subr_num) { + subr_num = 0; int n = SUPER::argStack.pop_int (); n += biasedSubrs.get_bias (); if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ()))) @@ -158,11 +159,11 @@ struct cs_interp_env_t : interp_env_t return true; } - void callSubr (const biased_subrs_t& biasedSubrs, cs_type_t type) + void call_subr (const biased_subrs_t& biasedSubrs, cs_type_t type) { - unsigned int subr_num; + unsigned int subr_num = 0; - if (unlikely (!popSubrNum (biasedSubrs, subr_num) + if (unlikely (!pop_subr_num (biasedSubrs, subr_num) || callStack.get_count () >= kMaxCallLimit)) { SUPER::set_error (); @@ -175,7 +176,7 @@ struct cs_interp_env_t : interp_env_t SUPER::str_ref = context.str_ref; } - void returnFromSubr () + void return_from_subr () { if (unlikely (SUPER::str_ref.in_error ())) SUPER::set_error (); @@ -246,7 +247,7 @@ struct path_procs_null_t static void flex1 (ENV &env, PARAM& param) {} }; -template > +template > struct cs_opset_t : opset_t { static void process_op (op_code_t op, ENV &env, PARAM& param) @@ -254,7 +255,7 @@ struct cs_opset_t : opset_t switch (op) { case OpCode_return: - env.returnFromSubr (); + env.return_from_subr (); break; case OpCode_endchar: OPSET::check_width (op, env, param); @@ -267,11 +268,11 @@ struct cs_opset_t : opset_t break; case OpCode_callsubr: - env.callSubr (env.localSubrs, CSType_LocalSubr); + env.call_subr (env.localSubrs, CSType_LocalSubr); break; case OpCode_callgsubr: - env.callSubr (env.globalSubrs, CSType_GlobalSubr); + env.call_subr (env.globalSubrs, CSType_GlobalSubr); break; case OpCode_hstem: @@ -550,8 +551,13 @@ struct path_procs_t static void rcurveline (ENV &env, PARAM& param) { + unsigned int arg_count = env.argStack.get_count (); + if (unlikely (arg_count < 8)) + return; + unsigned int i = 0; - for (; i + 6 <= env.argStack.get_count (); i += 6) + unsigned int curve_limit = arg_count - 2; + for (; i + 6 <= curve_limit; i += 6) { point_t pt1 = env.get_pt (); pt1.move (env.eval_arg (i), env.eval_arg (i+1)); @@ -561,34 +567,34 @@ struct path_procs_t pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); PATH::curve (env, param, pt1, pt2, pt3); } - for (; i + 2 <= env.argStack.get_count (); i += 2) - { - point_t pt1 = env.get_pt (); - pt1.move (env.eval_arg (i), env.eval_arg (i+1)); - PATH::line (env, param, pt1); - } + + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + PATH::line (env, param, pt1); } static void rlinecurve (ENV &env, PARAM& param) { + unsigned int arg_count = env.argStack.get_count (); + if (unlikely (arg_count < 8)) + return; + unsigned int i = 0; - unsigned int line_limit = (env.argStack.get_count () % 6); + unsigned int line_limit = arg_count - 6; for (; i + 2 <= line_limit; i += 2) { point_t pt1 = env.get_pt (); pt1.move (env.eval_arg (i), env.eval_arg (i+1)); PATH::line (env, param, pt1); } - for (; i + 6 <= env.argStack.get_count (); i += 6) - { - point_t pt1 = env.get_pt (); - pt1.move (env.eval_arg (i), env.eval_arg (i+1)); - point_t pt2 = pt1; - pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); - point_t pt3 = pt2; - pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); - PATH::curve (env, param, pt1, pt2, pt3); - } + + point_t pt1 = env.get_pt (); + pt1.move (env.eval_arg (i), env.eval_arg (i+1)); + point_t pt2 = pt1; + pt2.move (env.eval_arg (i+2), env.eval_arg (i+3)); + point_t pt3 = pt2; + pt3.move (env.eval_arg (i+4), env.eval_arg (i+5)); + PATH::curve (env, param, pt1, pt2, pt3); } static void vvcurveto (ENV &env, PARAM& param) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh index 256c96c0462..a0a9429bf9b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh @@ -27,8 +27,6 @@ #define HB_CFF_INTERP_DICT_COMMON_HH #include "hb-cff-interp-common.hh" -#include -#include namespace CFF { @@ -58,19 +56,6 @@ struct top_dict_values_t : dict_values_t } void fini () { dict_values_t::fini (); } - unsigned int calculate_serialized_op_size (const OPSTR& opstr) const - { - switch (opstr.op) - { - case OpCode_CharStrings: - case OpCode_FDArray: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); - - default: - return opstr.str.length; - } - } - unsigned int charStringsOffset; unsigned int FDArrayOffset; }; @@ -94,130 +79,52 @@ struct dict_opset_t : opset_t } } + /* Turns CFF's BCD format into strtod understandable string */ static double parse_bcd (byte_str_ref_t& str_ref) { - bool neg = false; - double int_part = 0; - uint64_t frac_part = 0; - uint32_t frac_count = 0; - bool exp_neg = false; - uint32_t exp_part = 0; - bool exp_overflow = false; - enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART; + if (unlikely (str_ref.in_error ())) return .0; + enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END }; - const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */ - const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */ - double value = 0.0; + char buf[32]; unsigned char byte = 0; - for (uint32_t i = 0;; i++) + for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count) { - char d; - if ((i & 1) == 0) + unsigned nibble; + if (!(i & 1)) { - if (!str_ref.avail ()) - { - str_ref.set_error (); - return 0.0; - } + if (unlikely (!str_ref.avail ())) break; + byte = str_ref[0]; str_ref.inc (); - d = byte >> 4; + nibble = byte >> 4; } else - d = byte & 0x0F; + nibble = byte & 0x0F; - switch (d) + if (unlikely (nibble == RESERVED)) break; + else if (nibble == END) { - case RESERVED: - str_ref.set_error (); - return value; - - case END: - value = (double)(neg? -int_part: int_part); - if (frac_count > 0) - { - double frac = (frac_part / pow (10.0, (double)frac_count)); - if (neg) frac = -frac; - value += frac; - } - if (unlikely (exp_overflow)) - { - if (value == 0.0) - return value; - if (exp_neg) - return neg? -DBL_MIN: DBL_MIN; - else - return neg? -DBL_MAX: DBL_MAX; - } - if (exp_part != 0) - { - if (exp_neg) - value /= pow (10.0, (double)exp_part); - else - value *= pow (10.0, (double)exp_part); - } - return value; - - case NEG: - if (i != 0) - { - str_ref.set_error (); - return 0.0; - } - neg = true; - break; - - case DECIMAL: - if (part != INT_PART) - { - str_ref.set_error (); - return value; - } - part = FRAC_PART; + const char *p = buf; + double pv; + if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */))) break; - - case EXP_NEG: - exp_neg = true; - HB_FALLTHROUGH; - - case EXP_POS: - if (part == EXP_PART) - { - str_ref.set_error (); - return value; - } - part = EXP_PART; - break; - - default: - switch (part) { - default: - case INT_PART: - int_part = (int_part * 10) + d; - break; - - case FRAC_PART: - if (likely (frac_part <= MAX_FRACT / 10)) - { - frac_part = (frac_part * 10) + (unsigned)d; - frac_count++; - } - break; - - case EXP_PART: - if (likely (exp_part * 10 + d <= MAX_EXP)) - { - exp_part = (exp_part * 10) + d; - } - else - exp_overflow = true; - break; - } + return pv; + } + else + { + buf[count] = "0123456789.EE?-?"[nibble]; + if (nibble == EXP_NEG) + { + ++count; + if (unlikely (count == ARRAY_LENGTH (buf))) break; + buf[count] = '-'; + } } } - return value; + str_ref.set_error (); + return .0; } static bool is_hint_op (op_code_t op) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh index a8208a3d196..96718f4a698 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh @@ -40,7 +40,7 @@ struct cff1_cs_interp_env_t : cs_interp_env_t template void init (const byte_str_t &str, ACC &acc, unsigned int fd) { - SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); + SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); processed_width = false; has_width = false; arg_start = 0; @@ -81,7 +81,7 @@ struct cff1_cs_interp_env_t : cs_interp_env_t typedef cs_interp_env_t SUPER; }; -template > +template > struct cff1_cs_opset_t : cs_opset_t { /* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh index 6971c2eec55..f1de1e32981 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh @@ -52,7 +52,7 @@ struct blend_arg_t : number_t void set_real (double v) { reset_blends (); number_t::set_real (v); } void set_blends (unsigned int numValues_, unsigned int valueIndex_, - unsigned int numBlends, hb_array_t blends_) + unsigned int numBlends, hb_array_t blends_) { numValues = numValues_; valueIndex = valueIndex_; @@ -80,9 +80,9 @@ struct cff2_cs_interp_env_t : cs_interp_env_t { template void init (const byte_str_t &str, ACC &acc, unsigned int fd, - const int *coords_=nullptr, unsigned int num_coords_=0) + const int *coords_=nullptr, unsigned int num_coords_=0) { - SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs); + SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs); coords = coords_; num_coords = num_coords_; @@ -90,7 +90,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t seen_blend = false; seen_vsindex_ = false; scalars.init (); - do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore)); + do_blend = num_coords && coords && varStore->size; set_ivs (acc.privateDicts[fd].ivs); } @@ -133,10 +133,11 @@ struct cff2_cs_interp_env_t : cs_interp_env_t region_count = varStore->varStore.get_region_index_count (get_ivs ()); if (do_blend) { - scalars.resize (region_count); - varStore->varStore.get_scalars (get_ivs (), - (int *)coords, num_coords, - &scalars[0], region_count); + if (unlikely (!scalars.resize (region_count))) + set_error (); + else + varStore->varStore.get_scalars (get_ivs (), coords, num_coords, + &scalars[0], region_count); } seen_blend = true; } @@ -193,7 +194,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t typedef cs_interp_env_t SUPER; }; -template > +template > struct cff2_cs_opset_t : cs_opset_t { static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-common.cc index 890697cee1b..4dd2479a0e6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-common.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-common.cc @@ -27,14 +27,13 @@ */ #include "hb.hh" - #include "hb-machinery.hh" #include -#ifdef HAVE_XLOCALE_H -#include -#endif +#ifdef HB_NO_SETLOCALE +#define setlocale(Category, Locale) "C" +#endif /** * SECTION:hb-common @@ -67,10 +66,9 @@ _hb_options_init () p = c + strlen (c); #define OPTION(name, symbol) \ - if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true; + if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast(p - c)) do { u.opts.symbol = true; } while (0) OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible); - OPTION ("aat", aat); #undef OPTION @@ -334,14 +332,14 @@ lang_find_or_insert (const char *key) /** * hb_language_from_string: * @str: (array length=len) (element-type uint8_t): a string representing - * a BCP 47 language tag + * a BCP 47 language tag * @len: length of the @str, or -1 if it is %NULL-terminated. * - * Converts @str representing a BCP 47 language tag to the corresponding + * Converts @str representing a BCP 47 language tag to the corresponding * #hb_language_t. * * Return value: (transfer none): - * The #hb_language_t corresponding to the BCP 47 language tag. + * The #hb_language_t corresponding to the BCP 47 language tag. * * Since: 0.9.2 **/ @@ -356,7 +354,7 @@ hb_language_from_string (const char *str, int len) { /* NUL-terminate it. */ char strbuf[64]; - len = MIN (len, (int) sizeof (strbuf) - 1); + len = hb_min (len, (int) sizeof (strbuf) - 1); memcpy (strbuf, str, len); strbuf[len] = '\0'; item = lang_find_or_insert (strbuf); @@ -382,7 +380,8 @@ hb_language_from_string (const char *str, int len) const char * hb_language_to_string (hb_language_t language) { - /* This is actually nullptr-safe! */ + if (unlikely (!language)) return nullptr; + return language->s; } @@ -422,12 +421,12 @@ hb_language_get_default () /** * hb_script_from_iso15924_tag: - * @tag: an #hb_tag_t representing an ISO 15924 tag. + * @tag: an #hb_tag_t representing an ISO 15924 tag. * - * Converts an ISO 15924 script tag to a corresponding #hb_script_t. + * Converts an ISO 15924 script tag to a corresponding #hb_script_t. * * Return value: - * An #hb_script_t corresponding to the ISO 15924 tag. + * An #hb_script_t corresponding to the ISO 15924 tag. * * Since: 0.9.2 **/ @@ -468,15 +467,15 @@ hb_script_from_iso15924_tag (hb_tag_t tag) /** * hb_script_from_string: * @str: (array length=len) (element-type uint8_t): a string representing an - * ISO 15924 tag. + * ISO 15924 tag. * @len: length of the @str, or -1 if it is %NULL-terminated. * - * Converts a string @str representing an ISO 15924 script tag to a + * Converts a string @str representing an ISO 15924 script tag to a * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then * hb_script_from_iso15924_tag(). * * Return value: - * An #hb_script_t corresponding to the ISO 15924 tag. + * An #hb_script_t corresponding to the ISO 15924 tag. * * Since: 0.9.2 **/ @@ -488,12 +487,12 @@ hb_script_from_string (const char *str, int len) /** * hb_script_to_iso15924_tag: - * @script: an #hb_script_ to convert. + * @script: an #hb_script_t to convert. * * See hb_script_from_iso15924_tag(). * * Return value: - * An #hb_tag_t representing an ISO 15924 script tag. + * An #hb_tag_t representing an ISO 15924 script tag. * * Since: 0.9.2 **/ @@ -575,6 +574,13 @@ hb_script_get_horizontal_direction (hb_script_t script) case HB_SCRIPT_OLD_SOGDIAN: case HB_SCRIPT_SOGDIAN: + /* Unicode-12.0 additions */ + case HB_SCRIPT_ELYMAIC: + + /* Unicode-13.0 additions */ + case HB_SCRIPT_CHORASMIAN: + case HB_SCRIPT_YEZIDI: + return HB_DIRECTION_RTL; @@ -590,38 +596,6 @@ hb_script_get_horizontal_direction (hb_script_t script) } -/* hb_user_data_array_t */ - -bool -hb_user_data_array_t::set (hb_user_data_key_t *key, - void * data, - hb_destroy_func_t destroy, - hb_bool_t replace) -{ - if (!key) - return false; - - if (replace) { - if (!data && !destroy) { - items.remove (key, lock); - return true; - } - } - hb_user_data_item_t item = {key, data, destroy}; - bool ret = !!items.replace_or_insert (item, lock, (bool) replace); - - return ret; -} - -void * -hb_user_data_array_t::get (hb_user_data_key_t *key) -{ - hb_user_data_item_t item = {nullptr, nullptr, nullptr}; - - return items.find (key, &item, lock) ? item.data : nullptr; -} - - /* hb_version */ @@ -719,131 +693,24 @@ parse_char (const char **pp, const char *end, char c) static bool parse_uint (const char **pp, const char *end, unsigned int *pv) { - char buf[32]; - unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp)); - strncpy (buf, *pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - unsigned int v; - - /* Intentionally use strtol instead of strtoul, such that - * -1 turns into "big number"... */ - errno = 0; - v = strtol (p, &pend, 0); - if (errno || p == pend) - return false; + /* Intentionally use hb_parse_int inside instead of hb_parse_uint, + * such that -1 turns into "big number"... */ + int v; + if (unlikely (!hb_parse_int (pp, end, &v))) return false; *pv = v; - *pp += pend - p; return true; } static bool parse_uint32 (const char **pp, const char *end, uint32_t *pv) { - char buf[32]; - unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp)); - strncpy (buf, *pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - unsigned int v; - - /* Intentionally use strtol instead of strtoul, such that - * -1 turns into "big number"... */ - errno = 0; - v = strtol (p, &pend, 0); - if (errno || p == pend) - return false; + /* Intentionally use hb_parse_int inside instead of hb_parse_uint, + * such that -1 turns into "big number"... */ + int v; + if (unlikely (!hb_parse_int (pp, end, &v))) return false; *pv = v; - *pp += pend - p; - return true; -} - -#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L) -#define USE_XLOCALE 1 -#define HB_LOCALE_T locale_t -#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr) -#define HB_FREE_LOCALE(loc) freelocale (loc) -#elif defined(_MSC_VER) -#define USE_XLOCALE 1 -#define HB_LOCALE_T _locale_t -#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName) -#define HB_FREE_LOCALE(loc) _free_locale (loc) -#define strtod_l(a, b, c) _strtod_l ((a), (b), (c)) -#endif - -#ifdef USE_XLOCALE - -#if HB_USE_ATEXIT -static void free_static_C_locale (); -#endif - -static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t -{ - static HB_LOCALE_T create () - { - HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C"); - -#if HB_USE_ATEXIT - atexit (free_static_C_locale); -#endif - - return C_locale; - } - static void destroy (HB_LOCALE_T p) - { - HB_FREE_LOCALE (p); - } - static HB_LOCALE_T get_null () - { - return nullptr; - } -} static_C_locale; - -#if HB_USE_ATEXIT -static -void free_static_C_locale () -{ - static_C_locale.free_instance (); -} -#endif - -static HB_LOCALE_T -get_C_locale () -{ - return static_C_locale.get_unconst (); -} -#endif /* USE_XLOCALE */ - -static bool -parse_float (const char **pp, const char *end, float *pv) -{ - char buf[32]; - unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp)); - strncpy (buf, *pp, len); - buf[len] = '\0'; - - char *p = buf; - char *pend = p; - float v; - - errno = 0; -#ifdef USE_XLOCALE - v = strtod_l (p, &pend, get_C_locale ()); -#else - v = strtod (p, &pend); -#endif - if (errno || p == pend) - return false; - - *pv = v; - *pp += pend - p; return true; } @@ -857,9 +724,14 @@ parse_bool (const char **pp, const char *end, uint32_t *pv) (*pp)++; /* CSS allows on/off as aliases 1/0. */ - if (*pp - p == 2 && 0 == strncmp (p, "on", 2)) + if (*pp - p == 2 + && TOLOWER (p[0]) == 'o' + && TOLOWER (p[1]) == 'n') *pv = 1; - else if (*pp - p == 3 && 0 == strncmp (p, "off", 3)) + else if (*pp - p == 3 + && TOLOWER (p[0]) == 'o' + && TOLOWER (p[1]) == 'f' + && TOLOWER (p[2]) == 'f') *pv = 0; else return false; @@ -974,7 +846,41 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature) * * Parses a string into a #hb_feature_t. * - * TODO: document the syntax here. + * The format for specifying feature strings follows. All valid CSS + * font-feature-settings values other than 'normal' and the global values are + * also accepted, though not documented below. CSS string escapes are not + * supported. + * + * The range indices refer to the positions between Unicode characters. The + * position before the first character is always 0. + * + * The format is Python-esque. Here is how it all works: + * + * + * + *

  • + * Syntax Value Start End + * + * + * Setting value: + * kern 1 0 Turn feature on + * +kern 1 0 Turn feature on + * -kern 0 0 Turn feature off + * kern=0 0 0 Turn feature off + * kern=1 1 0 Turn feature on + * aalt=2 2 0 Choose 2nd alternate + * Setting index: + * kern[] 1 0 Turn feature on + * kern[:] 1 0 Turn feature on + * kern[5:] 1 5 Turn feature on, partial + * kern[:5] 1 0 5 Turn feature on, partial + * kern[3:5] 1 3 5 Turn feature on, range + * kern[3] 1 3 3+1 Turn feature on, single char + * Mixing it all: + * aalt[3:5]=2 2 3 5 Turn 2nd alternate on for range + * + * + * * * Return value: * %true if @str is successfully parsed, %false otherwise. @@ -1028,25 +934,25 @@ hb_feature_to_string (hb_feature_t *feature, len += 4; while (len && s[len - 1] == ' ') len--; - if (feature->start != 0 || feature->end != (unsigned int) -1) + if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END) { s[len++] = '['; if (feature->start) - len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start)); + len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start)); if (feature->end != feature->start + 1) { s[len++] = ':'; - if (feature->end != (unsigned int) -1) - len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end)); + if (feature->end != HB_FEATURE_GLOBAL_END) + len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end)); } s[len++] = ']'; } if (feature->value > 1) { s[len++] = '='; - len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value)); + len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value)); } assert (len < ARRAY_LENGTH (s)); - len = MIN (len, size - 1); + len = hb_min (len, size - 1); memcpy (buf, s, len); buf[len] = '\0'; } @@ -1057,7 +963,11 @@ static bool parse_variation_value (const char **pp, const char *end, hb_variation_t *variation) { parse_char (pp, end, '='); /* Optional. */ - return parse_float (pp, end, &variation->value); + double v; + if (unlikely (!hb_parse_double (pp, end, &v))) return false; + + variation->value = v; + return true; } static bool @@ -1113,14 +1023,71 @@ hb_variation_to_string (hb_variation_t *variation, while (len && s[len - 1] == ' ') len--; s[len++] = '='; - len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value)); + len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value)); assert (len < ARRAY_LENGTH (s)); - len = MIN (len, size - 1); + len = hb_min (len, size - 1); memcpy (buf, s, len); buf[len] = '\0'; } +/** + * hb_color_get_alpha: + * color: a #hb_color_t we are interested in its channels. + * + * Return value: Alpha channel value of the given color + * + * Since: 2.1.0 + */ +uint8_t +(hb_color_get_alpha) (hb_color_t color) +{ + return hb_color_get_alpha (color); +} + +/** + * hb_color_get_red: + * color: a #hb_color_t we are interested in its channels. + * + * Return value: Red channel value of the given color + * + * Since: 2.1.0 + */ +uint8_t +(hb_color_get_red) (hb_color_t color) +{ + return hb_color_get_red (color); +} + +/** + * hb_color_get_green: + * color: a #hb_color_t we are interested in its channels. + * + * Return value: Green channel value of the given color + * + * Since: 2.1.0 + */ +uint8_t +(hb_color_get_green) (hb_color_t color) +{ + return hb_color_get_green (color); +} + +/** + * hb_color_get_blue: + * color: a #hb_color_t we are interested in its channels. + * + * Return value: Blue channel value of the given color + * + * Since: 2.1.0 + */ +uint8_t +(hb_color_get_blue) (hb_color_t color) +{ + return hb_color_get_blue (color); +} + + /* If there is no visibility control, then hb-static.cc will NOT * define anything. Instead, we get it to define one set in here * only, so only libharfbuzz.so defines them, not other libs. */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.h b/src/java.desktop/share/native/libharfbuzz/hb-common.h index fea193ada71..9614e720b32 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-common.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-common.h @@ -63,6 +63,8 @@ typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; +#elif defined (__KERNEL__) +# include #else # include #endif @@ -357,6 +359,22 @@ typedef enum /*11.0*/HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'), /*11.0*/HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'), + /* + * Since 2.4.0 + */ + /*12.0*/HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'), + /*12.0*/HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'), + /*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'), + /*12.0*/HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'), + + /* + * Since 2.6.7 + */ + /*13.0*/HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'), + /*13.0*/HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'), + /*13.0*/HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), + /*13.0*/HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), + /* No script set. */ HB_SCRIPT_INVALID = HB_TAG_NONE, @@ -415,6 +433,21 @@ typedef void (*hb_destroy_func_t) (void *user_data); */ #define HB_FEATURE_GLOBAL_END ((unsigned int) -1) +/** + * hb_feature_t: + * @tag: a feature tag + * @value: 0 disables the feature, non-zero (usually 1) enables the feature. + * For features implemented as lookup type 3 (like 'salt') the @value is a one + * based index into the alternates. + * @start: the cluster to start applying this feature setting (inclusive). + * @end: the cluster to end applying this feature setting (exclusive). + * + * The #hb_feature_t is the structure that holds information about requested + * feature application. The feature will be applied with the given value to all + * glyphs which are in clusters between @start (inclusive) and @end (exclusive). + * Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END + * specifies that the feature always applies to the entire buffer. + */ typedef struct hb_feature_t { hb_tag_t tag; uint32_t value; @@ -459,39 +492,21 @@ typedef uint32_t hb_color_t; #define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a))) -/** - * hb_color_get_alpha: - * - * - * - * Since: 2.1.0 - */ +HB_EXTERN uint8_t +hb_color_get_alpha (hb_color_t color); #define hb_color_get_alpha(color) ((color) & 0xFF) -/** - * hb_color_get_red: - * - * - * - * Since: 2.1.0 - */ + +HB_EXTERN uint8_t +hb_color_get_red (hb_color_t color); #define hb_color_get_red(color) (((color) >> 8) & 0xFF) -/** - * hb_color_get_green: - * - * - * - * Since: 2.1.0 - */ + +HB_EXTERN uint8_t +hb_color_get_green (hb_color_t color); #define hb_color_get_green(color) (((color) >> 16) & 0xFF) -/** - * hb_color_get_blue: - * - * - * - * Since: 2.1.0 - */ -#define hb_color_get_blue(color) (((color) >> 24) & 0xFF) +HB_EXTERN uint8_t +hb_color_get_blue (hb_color_t color); +#define hb_color_get_blue(color) (((color) >> 24) & 0xFF) HB_END_DECLS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-config.hh b/src/java.desktop/share/native/libharfbuzz/hb-config.hh new file mode 100644 index 00000000000..fc8d424bfb0 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-config.hh @@ -0,0 +1,163 @@ +/* + * Copyright © 2019 Facebook, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Facebook Author(s): Behdad Esfahbod + */ + +#ifndef HB_CONFIG_HH +#define HB_CONFIG_HH + +#if 0 /* Make test happy. */ +#include "hb.hh" +#endif + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + + +#ifdef HB_TINY +#define HB_LEAN +#define HB_MINI +#define HB_NO_MT +#define HB_NO_UCD_UNASSIGNED +#ifndef NDEBUG +#define NDEBUG +#endif +#ifndef __OPTIMIZE_SIZE__ +#define __OPTIMIZE_SIZE__ +#endif +#endif + +#ifdef HB_LEAN +#define HB_DISABLE_DEPRECATED +#define HB_NDEBUG +#define HB_NO_ATEXIT +#define HB_NO_BUFFER_MESSAGE +#define HB_NO_BUFFER_SERIALIZE +#define HB_NO_BITMAP +#define HB_NO_CFF +#define HB_NO_COLOR +#define HB_NO_DRAW +#define HB_NO_ERRNO +#define HB_NO_FACE_COLLECT_UNICODES +#define HB_NO_GETENV +#define HB_NO_HINTING +#define HB_NO_LANGUAGE_PRIVATE_SUBTAG +#define HB_NO_LAYOUT_FEATURE_PARAMS +#define HB_NO_LAYOUT_COLLECT_GLYPHS +#define HB_NO_LAYOUT_UNUSED +#define HB_NO_MATH +#define HB_NO_META +#define HB_NO_METRICS +#define HB_NO_MMAP +#define HB_NO_NAME +#define HB_NO_OPEN +#define HB_NO_SETLOCALE +#define HB_NO_OT_FONT_GLYPH_NAMES +#define HB_NO_OT_SHAPE_FRACTIONS +#define HB_NO_STYLE +#define HB_NO_SUBSET_LAYOUT +#define HB_NO_VAR +#endif + +#ifdef HB_MINI +#define HB_NO_AAT +#define HB_NO_LEGACY +#endif + + +/* Closure of options. */ + +#ifdef HB_DISABLE_DEPRECATED +#define HB_IF_NOT_DEPRECATED(x) +#else +#define HB_IF_NOT_DEPRECATED(x) x +#endif + +#ifdef HB_NO_AAT +#define HB_NO_OT_NAME_LANGUAGE_AAT +#define HB_NO_AAT_SHAPE +#endif + +#ifdef HB_NO_BITMAP +#define HB_NO_OT_FONT_BITMAP +#endif + +#ifdef HB_NO_CFF +#define HB_NO_OT_FONT_CFF +#define HB_NO_SUBSET_CFF +#endif + +#ifdef HB_NO_GETENV +#define HB_NO_UNISCRIBE_BUG_COMPATIBLE +#endif + +#ifdef HB_NO_LEGACY +#define HB_NO_CMAP_LEGACY_SUBTABLES +#define HB_NO_FALLBACK_SHAPE +#define HB_NO_OT_KERN +#define HB_NO_OT_LAYOUT_BLACKLIST +#define HB_NO_OT_SHAPE_FALLBACK +#endif + +#ifdef HB_NO_NAME +#define HB_NO_OT_NAME_LANGUAGE +#endif + +#ifdef HB_NO_OT +#define HB_NO_OT_FONT +#define HB_NO_OT_LAYOUT +#define HB_NO_OT_TAG +#define HB_NO_OT_SHAPE +#endif + +#ifdef HB_NO_OT_SHAPE +#define HB_NO_AAT_SHAPE +#endif + +#ifdef HB_NO_OT_SHAPE_FALLBACK +#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK +#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK +#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK +#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS +#endif + +#ifdef NDEBUG +#ifndef HB_NDEBUG +#define HB_NDEBUG +#endif +#endif + +#ifdef __OPTIMIZE_SIZE__ +#ifndef HB_OPTIMIZE_SIZE +#define HB_OPTIMIZE_SIZE +#endif +#endif + +#ifdef HAVE_CONFIG_OVERRIDE_H +#include "config-override.h" +#endif + + +#endif /* HB_CONFIG_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-coretext.cc b/src/java.desktop/share/native/libharfbuzz/hb-coretext.cc index f8d03085bd9..a382228f20d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-coretext.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-coretext.cc @@ -27,6 +27,9 @@ */ #include "hb.hh" + +#ifdef HAVE_CORETEXT + #include "hb-shaper-impl.hh" #include "hb-coretext.h" @@ -46,24 +49,6 @@ /* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */ #define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f -static CGFloat -coretext_font_size_from_ptem (float ptem) -{ - /* CoreText points are CSS pixels (96 per inch), - * NOT typographic points (72 per inch). - * - * https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html - */ - ptem *= 96.f / 72.f; - return ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : ptem; -} -static float -coretext_font_size_to_ptem (CGFloat size) -{ - size *= 72.f / 96.f; - return size <= 0.f ? 0 : size; -} - static void release_table_data (void *user_data) { @@ -72,7 +57,7 @@ release_table_data (void *user_data) } static hb_blob_t * -reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { CGFontRef cg_font = reinterpret_cast (user_data); CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag); @@ -171,7 +156,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) || CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay"))) { -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080 +#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080 # define kCTFontUIFontSystem kCTFontSystemFontType # define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType #endif @@ -214,7 +199,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) } CFURLRef original_url = nullptr; -#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060 ATSFontRef atsFont; FSRef fsref; OSStatus status; @@ -244,7 +229,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size) * process in Blink. This can be detected by the new file URL location * that the newly found font points to. */ CFURLRef new_url = nullptr; -#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060 atsFont = CTFontGetPlatformFont (new_ct_font, NULL); status = ATSFontGetFileReference (atsFont, &fsref); if (status == noErr) @@ -293,13 +278,32 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data) CFRelease ((CGFontRef) data); } +/** + * hb_coretext_face_create: + * @cg_font: The CGFontRef to work upon + * + * Creates an #hb_face_t face object from the specified + * CGFontRef. + * + * Return value: the new #hb_face_t face object + * + * Since: 0.9.10 + */ hb_face_t * hb_coretext_face_create (CGFontRef cg_font) { - return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release); + return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release); } -/* +/** + * hb_coretext_face_get_cg_font: + * @face: The #hb_face_t to work upon + * + * Fetches the CGFontRef associated with an #hb_face_t + * face object + * + * Return value: the CGFontRef found + * * Since: 0.9.10 */ CGFontRef @@ -317,7 +321,8 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font) if (unlikely (!face_data)) return nullptr; CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext; - CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size_from_ptem (font->ptem)); + CGFloat font_size = (CGFloat) (font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem); + CTFontRef ct_font = create_ct_font (cg_font, font_size); if (unlikely (!ct_font)) { @@ -341,7 +346,7 @@ hb_coretext_font_data_sync (hb_font_t *font) const hb_coretext_font_data_t *data = font->data.coretext; if (unlikely (!data)) return nullptr; - if (fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) > .5) + if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > .5) { /* XXX-MT-bug * Note that evaluating condition above can be dangerous if another thread @@ -365,10 +370,17 @@ hb_coretext_font_data_sync (hb_font_t *font) return font->data.coretext; } - -/* +/** + * hb_coretext_font_create: + * @ct_font: The CTFontRef to work upon + * + * Creates an #hb_font_t font object from the specified + * CTFontRef. + * + * Return value: the new #hb_font_t font object + * * Since: 1.7.2 - */ + **/ hb_font_t * hb_coretext_font_create (CTFontRef ct_font) { @@ -381,7 +393,7 @@ hb_coretext_font_create (CTFontRef ct_font) if (unlikely (hb_object_is_immutable (font))) return font; - hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font))); + hb_font_set_ptem (font, CTFontGetSize (ct_font)); /* Let there be dragons here... */ font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font)); @@ -389,6 +401,17 @@ hb_coretext_font_create (CTFontRef ct_font) return font; } +/** + * hb_coretext_face_get_ct_font: + * @font: #hb_font_t to work upon + * + * Fetches the CTFontRef associated with the specified + * #hb_font_t font object. + * + * Return value: the CTFontRef found + * + * Since: 0.9.10 + */ CTFontRef hb_coretext_font_get_ct_font (hb_font_t *font) { @@ -410,7 +433,7 @@ struct active_feature_t { feature_record_t rec; unsigned int order; - static int cmp (const void *pa, const void *pb) { + HB_INTERNAL static int cmp (const void *pa, const void *pb) { const active_feature_t *a = (const active_feature_t *) pa; const active_feature_t *b = (const active_feature_t *) pb; return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 : @@ -428,7 +451,7 @@ struct feature_event_t { bool start; active_feature_t feature; - static int cmp (const void *pa, const void *pb) { + HB_INTERNAL static int cmp (const void *pa, const void *pb) { const feature_event_t *a = (const feature_event_t *) pa; const feature_event_t *b = (const feature_event_t *) pb; return a->index < b->index ? -1 : a->index > b->index ? 1 : @@ -489,13 +512,19 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, hb_vector_t feature_events; for (unsigned int i = 0; i < num_features; i++) { + active_feature_t feature; + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag); if (!mapping) continue; - active_feature_t feature; feature.rec.feature = mapping->aatFeatureType; feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable; +#else + feature.rec.feature = features[i].tag; + feature.rec.setting = features[i].value; +#endif feature.order = i; feature_event_t *event; @@ -544,6 +573,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, /* active_features.qsort (); */ for (unsigned int j = 0; j < active_features.length; j++) { +#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000 CFStringRef keys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey @@ -552,6 +582,17 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature), CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting) }; +#else + char tag[5] = {HB_UNTAG (active_features[j].rec.feature)}; + CFTypeRef keys[] = { + kCTFontOpenTypeFeatureTag, + kCTFontOpenTypeFeatureValue + }; + CFTypeRef values[] = { + CFStringCreateWithCString (kCFAllocatorDefault, tag, kCFStringEncodingASCII), + CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting) + }; +#endif static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), ""); CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault, (const void **) keys, @@ -598,7 +639,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, } else { active_feature_t *feature = active_features.find (&event->feature); if (feature) - active_features.remove (feature - active_features.arrayZ ()); + active_features.remove (feature - active_features.arrayZ); } } } @@ -608,7 +649,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, #define ALLOCATE_ARRAY(Type, name, len, on_no_room) \ Type *name = (Type *) scratch; \ - { \ + do { \ unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \ if (unlikely (_consumed > scratch_size)) \ { \ @@ -617,9 +658,9 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, } \ scratch += _consumed; \ scratch_size -= _consumed; \ - } + } while (0) - ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/); + ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, ((void)nullptr) /*nothing*/); unsigned int chars_len = 0; for (unsigned int i = 0; i < buffer->len; i++) { hb_codepoint_t c = buffer->info[i].codepoint; @@ -633,7 +674,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, } } - ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/); + ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, ((void)nullptr) /*nothing*/); chars_len = 0; for (unsigned int i = 0; i < buffer->len; i++) { @@ -649,7 +690,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \ ret = false; \ goto fail; \ - } HB_STMT_END; + } HB_STMT_END bool ret = true; CFStringRef string_ref = nullptr; @@ -711,7 +752,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, /* What's the iOS equivalent of this check? * The symbols was introduced in iOS 7.0. * At any rate, our fallback is safe and works fine. */ -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090 +#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1090 # define kCTLanguageAttributeName CFSTR ("NSLanguage") #endif CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault, @@ -771,7 +812,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, feature.start < chars_len && feature.start < feature.end) { CFRange feature_range = CFRangeMake (feature.start, - MIN (feature.end, chars_len) - feature.start); + hb_min (feature.end, chars_len) - feature.start); if (feature.value) CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName); else @@ -783,7 +824,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1; CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level); -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060 extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel; #endif CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault, @@ -977,7 +1018,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, #define SCRATCH_RESTORE() \ scratch_size = scratch_size_saved; \ - scratch = scratch_saved; + scratch = scratch_saved { /* Setup glyphs */ SCRATCH_SAVE(); @@ -1069,7 +1110,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, if (false) { /* Make sure all runs had the expected direction. */ - bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); + HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); assert (bool (status_and & kCTRunStatusRightToLeft) == backward); assert (bool (status_or & kCTRunStatusRightToLeft) == backward); } @@ -1116,7 +1157,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, unsigned int cluster = info[count - 1].cluster; for (unsigned int i = count - 1; i > 0; i--) { - cluster = MIN (cluster, info[i - 1].cluster); + cluster = hb_min (cluster, info[i - 1].cluster); info[i - 1].cluster = cluster; } } @@ -1125,7 +1166,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, unsigned int cluster = info[0].cluster; for (unsigned int i = 1; i < count; i++) { - cluster = MIN (cluster, info[i].cluster); + cluster = hb_min (cluster, info[i].cluster); info[i].cluster = cluster; } } @@ -1150,57 +1191,4 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, } -/* - * AAT shaper - */ - -/* - * shaper face data - */ - -struct hb_coretext_aat_face_data_t {}; - -hb_coretext_aat_face_data_t * -_hb_coretext_aat_shaper_face_data_create (hb_face_t *face) -{ - return hb_aat_layout_has_substitution (face) || hb_aat_layout_has_positioning (face) ? - (hb_coretext_aat_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr; -} - -void -_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_face_data_t *data HB_UNUSED) -{ -} - - -/* - * shaper font data - */ - -struct hb_coretext_aat_font_data_t {}; - -hb_coretext_aat_font_data_t * -_hb_coretext_aat_shaper_font_data_create (hb_font_t *font) -{ - return font->data.coretext ? (hb_coretext_aat_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr; -} - -void -_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_font_data_t *data HB_UNUSED) -{ -} - - -/* - * shaper - */ - -hb_bool_t -_hb_coretext_aat_shape (hb_shape_plan_t *shape_plan, - hb_font_t *font, - hb_buffer_t *buffer, - const hb_feature_t *features, - unsigned int num_features) -{ - return _hb_coretext_shape (shape_plan, font, buffer, features, num_features); -} +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-coretext.h b/src/java.desktop/share/native/libharfbuzz/hb-coretext.h index 4b0a6f01b6f..55cac7e294a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-coretext.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-coretext.h @@ -40,8 +40,40 @@ HB_BEGIN_DECLS +/** + * HB_CORETEXT_TAG_MORT: + * + * The #hb_tag_t tag for the `mort` (glyph metamorphosis) table, + * which holds AAT features. + * + * For more information, see + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html + * + **/ #define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t') + +/** + * HB_CORETEXT_TAG_MORX: + * + * The #hb_tag_t tag for the `morx` (extended glyph metamorphosis) + * table, which holds AAT features. + * + * For more information, see + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html + * + **/ #define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x') + +/** + * HB_CORETEXT_TAG_KERX: + * + * The #hb_tag_t tag for the `kerx` (extended kerning) table, which + * holds AAT kerning information. + * + * For more information, see + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html + * + **/ #define HB_CORETEXT_TAG_KERX HB_TAG('k','e','r','x') diff --git a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh index d5ec94f4e47..db60837748f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh @@ -29,7 +29,7 @@ #include "hb.hh" #include "hb-atomic.hh" -#include "hb-dsalgs.hh" +#include "hb-algs.hh" #ifndef HB_DEBUG @@ -46,7 +46,6 @@ struct hb_options_t bool unused : 1; /* In-case sign bit is here. */ bool initialized : 1; bool uniscribe_bug_compatible : 1; - bool aat : 1; }; union hb_options_union_t { @@ -63,6 +62,9 @@ extern HB_INTERNAL hb_atomic_int_t _hb_options; static inline hb_options_t hb_options () { +#ifdef HB_NO_GETENV + return hb_options_t (); +#endif /* Make a local copy, so we can access bitfield threadsafely. */ hb_options_union_t u; u.i = _hb_options.get_relaxed (); @@ -158,7 +160,7 @@ _hb_debug_msg_va (const char *what, VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR; fprintf (stderr, "%2u %s" VRBAR "%s", level, - bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level), + bars + sizeof (bars) - 1 - hb_min ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level), level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR); } else fprintf (stderr, " " VRBAR LBAR); @@ -246,8 +248,8 @@ struct hb_printer_t { }; template <> -struct hb_printer_t { - const char *print (hb_void_t) { return ""; } +struct hb_printer_t { + const char *print (hb_empty_t) { return ""; } }; @@ -263,7 +265,7 @@ static inline void _hb_warn_no_return (bool returned) } } template <> -/*static*/ inline void _hb_warn_no_return (bool returned HB_UNUSED) +/*static*/ inline void _hb_warn_no_return (bool returned HB_UNUSED) {} template @@ -293,22 +295,23 @@ struct hb_auto_trace_t if (plevel) --*plevel; } - ret_t ret (ret_t v, - const char *func = "", - unsigned int line = 0) + template + T ret (T&& v, + const char *func = "", + unsigned int line = 0) { if (unlikely (returned)) { fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n"); - return v; + return hb_forward (v); } _hb_debug_msg (what, obj, func, true, plevel ? *plevel : 1, -1, "return %s (line %d)", - hb_printer_t().print (v), line); + hb_printer_t().print (v), line); if (plevel) --*plevel; plevel = nullptr; returned = true; - return v; + return hb_forward (v); } private: @@ -327,18 +330,20 @@ struct hb_auto_trace_t<0, ret_t> const char *message, ...) HB_PRINTF_FUNC(6, 7) {} - ret_t ret (ret_t v, - const char *func HB_UNUSED = nullptr, - unsigned int line HB_UNUSED = 0) { return v; } + template + T ret (T&& v, + const char *func HB_UNUSED = nullptr, + unsigned int line HB_UNUSED = 0) { return hb_forward (v); } }; /* For disabled tracing; optimize out everything. * https://github.com/harfbuzz/harfbuzz/pull/605 */ template struct hb_no_trace_t { - ret_t ret (ret_t v, - const char *func HB_UNUSED = "", - unsigned int line HB_UNUSED = 0) { return v; } + template + T ret (T&& v, + const char *func HB_UNUSED = nullptr, + unsigned int line HB_UNUSED = 0) { return hb_forward (v); } }; #define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__) @@ -368,10 +373,6 @@ struct hb_no_trace_t { #define HB_DEBUG_FT (HB_DEBUG+0) #endif -#ifndef HB_DEBUG_GET_COVERAGE -#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0) -#endif - #ifndef HB_DEBUG_OBJECT #define HB_DEBUG_OBJECT (HB_DEBUG+0) #endif @@ -408,7 +409,7 @@ struct hb_no_trace_t { #define TRACE_SANITIZE(this) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - " "); + " ") #else #define TRACE_SANITIZE(this) hb_no_trace_t trace #endif @@ -420,7 +421,7 @@ struct hb_no_trace_t { #define TRACE_SERIALIZE(this) \ hb_auto_trace_t trace \ (&c->debug_depth, "SERIALIZE", c, HB_FUNC, \ - " "); + " ") #else #define TRACE_SERIALIZE(this) hb_no_trace_t trace #endif @@ -432,37 +433,24 @@ struct hb_no_trace_t { #define TRACE_SUBSET(this) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - " "); + " ") #else #define TRACE_SUBSET(this) hb_no_trace_t trace #endif -#ifndef HB_DEBUG_WOULD_APPLY -#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) -#endif -#if HB_DEBUG_WOULD_APPLY -#define TRACE_WOULD_APPLY(this) \ - hb_auto_trace_t trace \ - (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - "%d glyphs", c->len); -#else -#define TRACE_WOULD_APPLY(this) hb_no_trace_t trace -#endif - #ifndef HB_DEBUG_DISPATCH #define HB_DEBUG_DISPATCH ( \ HB_DEBUG_APPLY + \ HB_DEBUG_SANITIZE + \ HB_DEBUG_SERIALIZE + \ - HB_DEBUG_SUBSET + \ - HB_DEBUG_WOULD_APPLY + \ + HB_DEBUG_SUBSET + \ 0) #endif #if HB_DEBUG_DISPATCH #define TRACE_DISPATCH(this, format) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - "format %d", (int) format); + "format %d", (int) format) #else #define TRACE_DISPATCH(this, format) hb_no_trace_t trace #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h index 9409f320781..5dd04050b8e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h @@ -63,7 +63,7 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t *glyph, void *user_data); -HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void +HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_func_t func, void *user_data, hb_destroy_func_t destroy); @@ -165,29 +165,8 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, hb_codepoint_t *decomposed); -typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data, - hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, - void *user_data); -typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t; typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t; -/** - * hb_font_funcs_set_glyph_h_kerning_func: - * @ffuncs: font functions. - * @func: (closure user_data) (destroy destroy) (scope notified): - * @user_data: - * @destroy: - * - * - * - * Since: 0.9.2 - * Deprecated: 2.0.0 - **/ -HB_EXTERN void -hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, - hb_font_get_glyph_h_kerning_func_t func, - void *user_data, hb_destroy_func_t destroy); - /** * hb_font_funcs_set_glyph_v_kerning_func: * @ffuncs: font functions. @@ -206,19 +185,9 @@ hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs, void *user_data, hb_destroy_func_t destroy); HB_EXTERN hb_position_t -hb_font_get_glyph_h_kerning (hb_font_t *font, - hb_codepoint_t left_glyph, hb_codepoint_t right_glyph); -HB_EXTERN hb_position_t hb_font_get_glyph_v_kerning (hb_font_t *font, hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph); -HB_EXTERN void -hb_font_get_glyph_kerning_for_direction (hb_font_t *font, - hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, - hb_direction_t direction, - hb_position_t *x, hb_position_t *y); - - #endif HB_END_DECLS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-dispatch.hh b/src/java.desktop/share/native/libharfbuzz/hb-dispatch.hh new file mode 100644 index 00000000000..e946f21c114 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-dispatch.hh @@ -0,0 +1,61 @@ +/* + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2012,2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_DISPATCH_HH +#define HB_DISPATCH_HH + +#include "hb.hh" + +/* + * Dispatch + */ + +template +struct hb_dispatch_context_t +{ + hb_dispatch_context_t () : debug_depth (0) {} + private: + /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ + const Context* thiz () const { return static_cast (this); } + Context* thiz () { return static_cast< Context *> (this); } + public: + const char *get_name () { return "UNKNOWN"; } + static constexpr unsigned max_debug_depth = MaxDebugDepth; + typedef Return return_t; + template + bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; } + template + return_t dispatch (const T &obj, Ts&&... ds) + { return obj.dispatch (thiz (), hb_forward (ds)...); } + static return_t no_dispatch_return_value () { return Context::default_return_value (); } + static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; } + unsigned debug_depth; +}; + + +#endif /* HB_DISPATCH_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc new file mode 100644 index 00000000000..72444a94c8a --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc @@ -0,0 +1,261 @@ +/* + * Copyright © 2019-2020 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" + +#ifndef HB_NO_DRAW +#ifdef HB_EXPERIMENTAL_API + +#include "hb-draw.hh" +#include "hb-ot.h" +#include "hb-ot-glyf-table.hh" +#include "hb-ot-cff1-table.hh" +#include "hb-ot-cff2-table.hh" + +/** + * hb_draw_funcs_set_move_to_func: + * @funcs: draw functions object + * @move_to: move-to callback + * + * Sets move-to callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs, + hb_draw_move_to_func_t move_to) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->move_to = move_to; +} + +/** + * hb_draw_funcs_set_line_to_func: + * @funcs: draw functions object + * @line_to: line-to callback + * + * Sets line-to callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs, + hb_draw_line_to_func_t line_to) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->line_to = line_to; +} + +/** + * hb_draw_funcs_set_quadratic_to_func: + * @funcs: draw functions object + * @move_to: quadratic-to callback + * + * Sets quadratic-to callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs, + hb_draw_quadratic_to_func_t quadratic_to) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->quadratic_to = quadratic_to; + funcs->is_quadratic_to_set = true; +} + +/** + * hb_draw_funcs_set_cubic_to_func: + * @funcs: draw functions + * @cubic_to: cubic-to callback + * + * Sets cubic-to callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs, + hb_draw_cubic_to_func_t cubic_to) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->cubic_to = cubic_to; +} + +/** + * hb_draw_funcs_set_close_path_func: + * @funcs: draw functions object + * @close_path: close-path callback + * + * Sets close-path callback to the draw functions object. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs, + hb_draw_close_path_func_t close_path) +{ + if (unlikely (hb_object_is_immutable (funcs))) return; + funcs->close_path = close_path; +} + +static void +_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} + +static void +_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} + +static void +_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED, + hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED, + hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED, + hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +_close_path_nil (void *user_data HB_UNUSED) {} + +/** + * hb_draw_funcs_create: + * + * Creates a new draw callbacks object. + * + * Since: EXPERIMENTAL + **/ +hb_draw_funcs_t * +hb_draw_funcs_create () +{ + hb_draw_funcs_t *funcs; + if (unlikely (!(funcs = hb_object_create ()))) + return const_cast (&Null (hb_draw_funcs_t)); + + funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil; + funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil; + funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil; + funcs->is_quadratic_to_set = false; + funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil; + funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil; + return funcs; +} + +/** + * hb_draw_funcs_reference: + * @funcs: draw functions + * + * Add to callbacks object refcount. + * + * Returns: The same object. + * Since: EXPERIMENTAL + **/ +hb_draw_funcs_t * +hb_draw_funcs_reference (hb_draw_funcs_t *funcs) +{ + return hb_object_reference (funcs); +} + +/** + * hb_draw_funcs_destroy: + * @funcs: draw functions + * + * Decreases refcount of callbacks object and deletes the object if it reaches + * to zero. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_destroy (hb_draw_funcs_t *funcs) +{ + if (!hb_object_destroy (funcs)) return; + + free (funcs); +} + +/** + * hb_draw_funcs_make_immutable: + * @funcs: draw functions + * + * Makes funcs object immutable. + * + * Since: EXPERIMENTAL + **/ +void +hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs) +{ + if (hb_object_is_immutable (funcs)) + return; + + hb_object_make_immutable (funcs); +} + +/** + * hb_draw_funcs_is_immutable: + * @funcs: draw functions + * + * Checks whether funcs is immutable. + * + * Returns: If is immutable. + * Since: EXPERIMENTAL + **/ +hb_bool_t +hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs) +{ + return hb_object_is_immutable (funcs); +} + +/** + * hb_font_draw_glyph: + * @font: a font object + * @glyph: a glyph id + * @funcs: draw callbacks object + * @user_data: parameter you like be passed to the callbacks when are called + * + * Draw a glyph. + * + * Returns: Whether the font had the glyph and the operation completed successfully. + * Since: EXPERIMENTAL + **/ +hb_bool_t +hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, + const hb_draw_funcs_t *funcs, + void *user_data) +{ + if (unlikely (funcs == &Null (hb_draw_funcs_t) || + glyph >= font->face->get_num_glyphs ())) + return false; + + draw_helper_t draw_helper (funcs, user_data); + if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true; +#ifndef HB_NO_CFF + if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true; + if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true; +#endif + + return false; +} + +#endif +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.h b/src/java.desktop/share/native/libharfbuzz/hb-draw.h new file mode 100644 index 00000000000..d5eb6ecc65b --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.h @@ -0,0 +1,98 @@ +/* + * Copyright © 2019-2020 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_H_IN +#error "Include instead." +#endif + +#ifndef HB_DRAW_H +#define HB_DRAW_H + +#include "hb.h" + +HB_BEGIN_DECLS + +#ifdef HB_EXPERIMENTAL_API +typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data); +typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data); +typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y, + hb_position_t to_x, hb_position_t to_y, + void *user_data); +typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y, + hb_position_t control2_x, hb_position_t control2_y, + hb_position_t to_x, hb_position_t to_y, + void *user_data); +typedef void (*hb_draw_close_path_func_t) (void *user_data); + +/** + * hb_draw_funcs_t: + * + * Glyph draw callbacks. + * + * _move_to, _line_to and _cubic_to calls are nessecary to be defined but we + * translate _quadratic_to calls to _cubic_to if the callback isn't defined. + * + * Since: EXPERIMENTAL + **/ +typedef struct hb_draw_funcs_t hb_draw_funcs_t; + +HB_EXTERN void +hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs, + hb_draw_move_to_func_t move_to); + +HB_EXTERN void +hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs, + hb_draw_line_to_func_t line_to); + +HB_EXTERN void +hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs, + hb_draw_quadratic_to_func_t quadratic_to); + +HB_EXTERN void +hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs, + hb_draw_cubic_to_func_t cubic_to); + +HB_EXTERN void +hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs, + hb_draw_close_path_func_t close_path); + +HB_EXTERN hb_draw_funcs_t * +hb_draw_funcs_create (void); + +HB_EXTERN hb_draw_funcs_t * +hb_draw_funcs_reference (hb_draw_funcs_t *funcs); + +HB_EXTERN void +hb_draw_funcs_destroy (hb_draw_funcs_t *funcs); + +HB_EXTERN void +hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs); + +HB_EXTERN hb_bool_t +hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs); +#endif + +HB_END_DECLS + +#endif /* HB_DRAW_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.hh b/src/java.desktop/share/native/libharfbuzz/hb-draw.hh new file mode 100644 index 00000000000..0e5101f9cd2 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.hh @@ -0,0 +1,139 @@ +/* + * Copyright © 2020 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_DRAW_HH +#define HB_DRAW_HH + +#include "hb.hh" + +#ifdef HB_EXPERIMENTAL_API +struct hb_draw_funcs_t +{ + hb_object_header_t header; + + hb_draw_move_to_func_t move_to; + hb_draw_line_to_func_t line_to; + hb_draw_quadratic_to_func_t quadratic_to; + bool is_quadratic_to_set; + hb_draw_cubic_to_func_t cubic_to; + hb_draw_close_path_func_t close_path; +}; + +struct draw_helper_t +{ + draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_) + { + funcs = funcs_; + user_data = user_data_; + path_open = false; + path_start_x = current_x = path_start_y = current_y = 0; + } + ~draw_helper_t () { end_path (); } + + void move_to (hb_position_t x, hb_position_t y) + { + if (path_open) end_path (); + current_x = path_start_x = x; + current_y = path_start_y = y; + } + + void line_to (hb_position_t x, hb_position_t y) + { + if (equal_to_current (x, y)) return; + if (!path_open) start_path (); + funcs->line_to (x, y, user_data); + current_x = x; + current_y = y; + } + + void + quadratic_to (hb_position_t control_x, hb_position_t control_y, + hb_position_t to_x, hb_position_t to_y) + { + if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y)) + return; + if (!path_open) start_path (); + if (funcs->is_quadratic_to_set) + funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data); + else + funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f), + roundf ((current_y + 2.f * control_y) / 3.f), + roundf ((to_x + 2.f * control_x) / 3.f), + roundf ((to_y + 2.f * control_y) / 3.f), + to_x, to_y, user_data); + current_x = to_x; + current_y = to_y; + } + + void + cubic_to (hb_position_t control1_x, hb_position_t control1_y, + hb_position_t control2_x, hb_position_t control2_y, + hb_position_t to_x, hb_position_t to_y) + { + if (equal_to_current (control1_x, control1_y) && + equal_to_current (control2_x, control2_y) && + equal_to_current (to_x, to_y)) + return; + if (!path_open) start_path (); + funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data); + current_x = to_x; + current_y = to_y; + } + + void end_path () + { + if (path_open) + { + if ((path_start_x != current_x) || (path_start_y != current_y)) + funcs->line_to (path_start_x, path_start_y, user_data); + funcs->close_path (user_data); + } + path_open = false; + path_start_x = current_x = path_start_y = current_y = 0; + } + + protected: + bool equal_to_current (hb_position_t x, hb_position_t y) + { return current_x == x && current_y == y; } + + void start_path () + { + if (path_open) end_path (); + path_open = true; + funcs->move_to (path_start_x, path_start_y, user_data); + } + + hb_position_t path_start_x; + hb_position_t path_start_y; + + hb_position_t current_x; + hb_position_t current_y; + + bool path_open; + const hb_draw_funcs_t *funcs; + void *user_data; +}; +#endif + +#endif /* HB_DRAW_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-dsalgs.hh b/src/java.desktop/share/native/libharfbuzz/hb-dsalgs.hh deleted file mode 100644 index f5f28688327..00000000000 --- a/src/java.desktop/share/native/libharfbuzz/hb-dsalgs.hh +++ /dev/null @@ -1,632 +0,0 @@ -/* - * Copyright © 2017 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_DSALGS_HH -#define HB_DSALGS_HH - -#include "hb.hh" -#include "hb-null.hh" - - -/* Void! For when we need a expression-type of void. */ -typedef const struct _hb_void_t *hb_void_t; -#define HB_VOID ((const _hb_void_t *) nullptr) - - -/* - * Bithacks. - */ - -/* Return the number of 1 bits in v. */ -template -static inline HB_CONST_FUNC unsigned int -hb_popcount (T v) -{ -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) - if (sizeof (T) <= sizeof (unsigned int)) - return __builtin_popcount (v); - - if (sizeof (T) <= sizeof (unsigned long)) - return __builtin_popcountl (v); - - if (sizeof (T) <= sizeof (unsigned long long)) - return __builtin_popcountll (v); -#endif - - if (sizeof (T) <= 4) - { - /* "HACKMEM 169" */ - uint32_t y; - y = (v >> 1) &033333333333; - y = v - y - ((y >>1) & 033333333333); - return (((y + (y >> 3)) & 030707070707) % 077); - } - - if (sizeof (T) == 8) - { - unsigned int shift = 32; - return hb_popcount ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift)); - } - - if (sizeof (T) == 16) - { - unsigned int shift = 64; - return hb_popcount ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift)); - } - - assert (0); - return 0; /* Shut up stupid compiler. */ -} - -/* Returns the number of bits needed to store number */ -template -static inline HB_CONST_FUNC unsigned int -hb_bit_storage (T v) -{ - if (unlikely (!v)) return 0; - -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) - if (sizeof (T) <= sizeof (unsigned int)) - return sizeof (unsigned int) * 8 - __builtin_clz (v); - - if (sizeof (T) <= sizeof (unsigned long)) - return sizeof (unsigned long) * 8 - __builtin_clzl (v); - - if (sizeof (T) <= sizeof (unsigned long long)) - return sizeof (unsigned long long) * 8 - __builtin_clzll (v); -#endif - -#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) - if (sizeof (T) <= sizeof (unsigned int)) - { - unsigned long where; - _BitScanReverse (&where, v); - return 1 + where; - } -# if defined(_WIN64) - if (sizeof (T) <= 8) - { - unsigned long where; - _BitScanReverse64 (&where, v); - return 1 + where; - } -# endif -#endif - - if (sizeof (T) <= 4) - { - /* "bithacks" */ - const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000}; - const unsigned int S[] = {1, 2, 4, 8, 16}; - unsigned int r = 0; - for (int i = 4; i >= 0; i--) - if (v & b[i]) - { - v >>= S[i]; - r |= S[i]; - } - return r + 1; - } - if (sizeof (T) <= 8) - { - /* "bithacks" */ - const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL}; - const unsigned int S[] = {1, 2, 4, 8, 16, 32}; - unsigned int r = 0; - for (int i = 5; i >= 0; i--) - if (v & b[i]) - { - v >>= S[i]; - r |= S[i]; - } - return r + 1; - } - if (sizeof (T) == 16) - { - unsigned int shift = 64; - return (v >> shift) ? hb_bit_storage ((uint64_t) (v >> shift)) + shift : - hb_bit_storage ((uint64_t) v); - } - - assert (0); - return 0; /* Shut up stupid compiler. */ -} - -/* Returns the number of zero bits in the least significant side of v */ -template -static inline HB_CONST_FUNC unsigned int -hb_ctz (T v) -{ - if (unlikely (!v)) return 0; - -#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__) - if (sizeof (T) <= sizeof (unsigned int)) - return __builtin_ctz (v); - - if (sizeof (T) <= sizeof (unsigned long)) - return __builtin_ctzl (v); - - if (sizeof (T) <= sizeof (unsigned long long)) - return __builtin_ctzll (v); -#endif - -#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) - if (sizeof (T) <= sizeof (unsigned int)) - { - unsigned long where; - _BitScanForward (&where, v); - return where; - } -# if defined(_WIN64) - if (sizeof (T) <= 8) - { - unsigned long where; - _BitScanForward64 (&where, v); - return where; - } -# endif -#endif - - if (sizeof (T) <= 4) - { - /* "bithacks" */ - unsigned int c = 32; - v &= - (int32_t) v; - if (v) c--; - if (v & 0x0000FFFF) c -= 16; - if (v & 0x00FF00FF) c -= 8; - if (v & 0x0F0F0F0F) c -= 4; - if (v & 0x33333333) c -= 2; - if (v & 0x55555555) c -= 1; - return c; - } - if (sizeof (T) <= 8) - { - /* "bithacks" */ - unsigned int c = 64; - v &= - (int64_t) (v); - if (v) c--; - if (v & 0x00000000FFFFFFFFULL) c -= 32; - if (v & 0x0000FFFF0000FFFFULL) c -= 16; - if (v & 0x00FF00FF00FF00FFULL) c -= 8; - if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4; - if (v & 0x3333333333333333ULL) c -= 2; - if (v & 0x5555555555555555ULL) c -= 1; - return c; - } - if (sizeof (T) == 16) - { - unsigned int shift = 64; - return (uint64_t) v ? hb_bit_storage ((uint64_t) v) : - hb_bit_storage ((uint64_t) (v >> shift)) + shift; - } - - assert (0); - return 0; /* Shut up stupid compiler. */ -} - - -/* - * Tiny stuff. - */ - -template -static inline T* hb_addressof (T& arg) -{ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-align" - /* https://en.cppreference.com/w/cpp/memory/addressof */ - return reinterpret_cast( - &const_cast( - reinterpret_cast(arg))); -#pragma GCC diagnostic pop -} - -/* ASCII tag/character handling */ -static inline bool ISALPHA (unsigned char c) -{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } -static inline bool ISALNUM (unsigned char c) -{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); } -static inline bool ISSPACE (unsigned char c) -{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; } -static inline unsigned char TOUPPER (unsigned char c) -{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; } -static inline unsigned char TOLOWER (unsigned char c) -{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; } - -#undef MIN -template -static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; } - -#undef MAX -template -static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; } - -static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b) -{ return (a + (b - 1)) / b; } - - -#undef ARRAY_LENGTH -template -static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; } -/* A const version, but does not detect erratically being called on pointers. */ -#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0]))) - - -static inline int -hb_memcmp (const void *a, const void *b, unsigned int len) -{ - /* It's illegal to pass NULL to memcmp(), even if len is zero. - * So, wrap it. - * https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */ - if (!len) return 0; - return memcmp (a, b, len); -} - -static inline bool -hb_unsigned_mul_overflows (unsigned int count, unsigned int size) -{ - return (size > 0) && (count >= ((unsigned int) -1) / size); -} - -static inline unsigned int -hb_ceil_to_4 (unsigned int v) -{ - return ((v - 1) | 3) + 1; -} - -template struct hb_is_signed; -/* https://github.com/harfbuzz/harfbuzz/issues/1535 */ -template <> struct hb_is_signed { enum { value = true }; }; -template <> struct hb_is_signed { enum { value = true }; }; -template <> struct hb_is_signed { enum { value = true }; }; -template <> struct hb_is_signed { enum { value = true }; }; -template <> struct hb_is_signed { enum { value = false }; }; -template <> struct hb_is_signed { enum { value = false }; }; -template <> struct hb_is_signed { enum { value = false }; }; -template <> struct hb_is_signed { enum { value = false }; }; - -template static inline bool -hb_in_range (T u, T lo, T hi) -{ - /* The sizeof() is here to force template instantiation. - * I'm sure there are better ways to do this but can't think of - * one right now. Declaring a variable won't work as HB_UNUSED - * is unusable on some platforms and unused types are less likely - * to generate a warning than unused variables. */ - static_assert (!hb_is_signed::value, ""); - - /* The casts below are important as if T is smaller than int, - * the subtract results will become a signed int! */ - return (T)(u - lo) <= (T)(hi - lo); -} -template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2) -{ - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2); -} -template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) -{ - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3); -} - - -/* - * Sort and search. - */ - -static inline void * -hb_bsearch (const void *key, const void *base, - size_t nmemb, size_t size, - int (*compar)(const void *_key, const void *_item)) -{ - int min = 0, max = (int) nmemb - 1; - while (min <= max) - { - int mid = (min + max) / 2; - const void *p = (const void *) (((const char *) base) + (mid * size)); - int c = compar (key, p); - if (c < 0) - max = mid - 1; - else if (c > 0) - min = mid + 1; - else - return (void *) p; - } - return nullptr; -} - -static inline void * -hb_bsearch_r (const void *key, const void *base, - size_t nmemb, size_t size, - int (*compar)(const void *_key, const void *_item, void *_arg), - void *arg) -{ - int min = 0, max = (int) nmemb - 1; - while (min <= max) - { - int mid = ((unsigned int) min + (unsigned int) max) / 2; - const void *p = (const void *) (((const char *) base) + (mid * size)); - int c = compar (key, p, arg); - if (c < 0) - max = mid - 1; - else if (c > 0) - min = mid + 1; - else - return (void *) p; - } - return nullptr; -} - - -/* From https://github.com/noporpoise/sort_r - * With following modifications: - * - * 10 November 2018: - * https://github.com/noporpoise/sort_r/issues/7 - */ - -/* Isaac Turner 29 April 2014 Public Domain */ - -/* - -hb_sort_r function to be exported. - -Parameters: - base is the array to be sorted - nel is the number of elements in the array - width is the size in bytes of each element of the array - compar is the comparison function - arg is a pointer to be passed to the comparison function - -void hb_sort_r(void *base, size_t nel, size_t width, - int (*compar)(const void *_a, const void *_b, void *_arg), - void *arg); -*/ - - -/* swap a, b iff a>b */ -/* __restrict is same as restrict but better support on old machines */ -static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w, - int (*compar)(const void *_a, const void *_b, - void *_arg), - void *arg) -{ - char tmp, *end = a+w; - if(compar(a, b, arg) > 0) { - for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; } - return 1; - } - return 0; -} - -/* Note: quicksort is not stable, equivalent values may be swapped */ -static inline void sort_r_simple(void *base, size_t nel, size_t w, - int (*compar)(const void *_a, const void *_b, - void *_arg), - void *arg) -{ - char *b = (char *)base, *end = b + nel*w; - if(nel < 7) { - /* Insertion sort for arbitrarily small inputs */ - char *pi, *pj; - for(pi = b+w; pi < end; pi += w) { - for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {} - } - } - else - { - /* nel > 6; Quicksort */ - - /* Use median of first, middle and last items as pivot */ - char *x, *y, *xend, ch; - char *pl, *pm, *pr; - char *last = b+w*(nel-1), *tmp; - char *l[3]; - l[0] = b; - l[1] = b+w*(nel/2); - l[2] = last; - - if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; } - if(compar(l[1],l[2],arg) > 0) { - tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */ - if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; } - } - - /* swap l[id], l[2] to put pivot as last element */ - for(x = l[1], y = last, xend = x+w; x>1); - for(; pl < pm; pl += w) { - if(sort_r_cmpswap(pl, pr, w, compar, arg)) { - pr -= w; /* pivot now at pl */ - break; - } - } - pm = pl+((pr-pl)>>1); - for(; pm < pr; pr -= w) { - if(sort_r_cmpswap(pl, pr, w, compar, arg)) { - pl += w; /* pivot now at pr */ - break; - } - } - } - - sort_r_simple(b, (pl-b)/w, w, compar, arg); - sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg); - } -} - -static inline void hb_sort_r(void *base, size_t nel, size_t width, - int (*compar)(const void *_a, const void *_b, void *_arg), - void *arg) -{ - sort_r_simple(base, nel, width, compar, arg); -} - - -template static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2) -{ - for (unsigned int i = 1; i < len; i++) - { - unsigned int j = i; - while (j && compar (&array[j - 1], &array[i]) > 0) - j--; - if (i == j) - continue; - /* Move item i to occupy place for item j, shift what's in between. */ - { - T t = array[i]; - memmove (&array[j + 1], &array[j], (i - j) * sizeof (T)); - array[j] = t; - } - if (array2) - { - T2 t = array2[i]; - memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2)); - array2[j] = t; - } - } -} - -template static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) -{ - hb_stable_sort (array, len, compar, (int *) nullptr); -} - -static inline hb_bool_t -hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) -{ - /* Pain because we don't know whether s is nul-terminated. */ - char buf[64]; - len = MIN (ARRAY_LENGTH (buf) - 1, len); - strncpy (buf, s, len); - buf[len] = '\0'; - - char *end; - errno = 0; - unsigned long v = strtoul (buf, &end, base); - if (errno) return false; - if (*end) return false; - *out = v; - return true; -} - - -struct HbOpOr -{ - static constexpr bool passthru_left = true; - static constexpr bool passthru_right = true; - template static void process (T &o, const T &a, const T &b) { o = a | b; } -}; -struct HbOpAnd -{ - static constexpr bool passthru_left = false; - static constexpr bool passthru_right = false; - template static void process (T &o, const T &a, const T &b) { o = a & b; } -}; -struct HbOpMinus -{ - static constexpr bool passthru_left = true; - static constexpr bool passthru_right = false; - template static void process (T &o, const T &a, const T &b) { o = a & ~b; } -}; -struct HbOpXor -{ - static constexpr bool passthru_left = true; - static constexpr bool passthru_right = true; - template static void process (T &o, const T &a, const T &b) { o = a ^ b; } -}; - - -/* Compiler-assisted vectorization. */ - -/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), - * using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128). - * Define that to 0 to disable. */ -template -struct hb_vector_size_t -{ - elt_t& operator [] (unsigned int i) { return u.v[i]; } - const elt_t& operator [] (unsigned int i) const { return u.v[i]; } - - void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); } - - template - hb_vector_size_t process (const hb_vector_size_t &o) const - { - hb_vector_size_t r; -#if HB_VECTOR_SIZE - if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE) - for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++) - Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]); - else -#endif - for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++) - Op::process (r.u.v[i], u.v[i], o.u.v[i]); - return r; - } - hb_vector_size_t operator | (const hb_vector_size_t &o) const - { return process (o); } - hb_vector_size_t operator & (const hb_vector_size_t &o) const - { return process (o); } - hb_vector_size_t operator ^ (const hb_vector_size_t &o) const - { return process (o); } - hb_vector_size_t operator ~ () const - { - hb_vector_size_t r; -#if HB_VECTOR_SIZE && 0 - if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE) - for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++) - r.u.vec[i] = ~u.vec[i]; - else -#endif - for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++) - r.u.v[i] = ~u.v[i]; - return r; - } - - private: - static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, ""); - union { - elt_t v[byte_size / sizeof (elt_t)]; -#if HB_VECTOR_SIZE - hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)]; -#endif - } u; -}; - - -#endif /* HB_DSALGS_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.cc b/src/java.desktop/share/native/libharfbuzz/hb-face.cc index e3dc46922f5..6d96dcc3848 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-face.cc @@ -200,10 +200,15 @@ hb_face_create (hb_blob_t *blob, if (unlikely (!blob)) blob = hb_blob_get_empty (); - hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (hb_sanitize_context_t ().sanitize_blob (hb_blob_reference (blob)), index); + blob = hb_sanitize_context_t ().sanitize_blob (hb_blob_reference (blob)); + + hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index); if (unlikely (!closure)) + { + hb_blob_destroy (blob); return hb_face_get_empty (); + } face = hb_face_create_for_tables (_hb_face_for_data_reference_table, closure, @@ -226,7 +231,7 @@ hb_face_create (hb_blob_t *blob, hb_face_t * hb_face_get_empty () { - return const_cast (&Null(hb_face_t)); + return const_cast (&Null (hb_face_t)); } @@ -367,6 +372,9 @@ hb_blob_t * hb_face_reference_table (const hb_face_t *face, hb_tag_t tag) { + if (unlikely (tag == HB_TAG_NONE)) + return hb_blob_get_empty (); + return face->reference_table (tag); } @@ -531,6 +539,7 @@ hb_face_get_table_tags (const hb_face_t *face, */ +#ifndef HB_NO_FACE_COLLECT_UNICODES /** * hb_face_collect_unicodes: * @face: font face. @@ -542,9 +551,8 @@ void hb_face_collect_unicodes (hb_face_t *face, hb_set_t *out) { - face->table.cmap->collect_unicodes (out); + face->table.cmap->collect_unicodes (out, face->get_num_glyphs ()); } - /** * hb_face_collect_variation_selectors: * @face: font face. @@ -560,7 +568,6 @@ hb_face_collect_variation_selectors (hb_face_t *face, { face->table.cmap->collect_variation_selectors (out); } - /** * hb_face_collect_variation_unicodes: * @face: font face. @@ -577,7 +584,7 @@ hb_face_collect_variation_unicodes (hb_face_t *face, { face->table.cmap->collect_variation_unicodes (variation_selector, out); } - +#endif /* @@ -714,7 +721,10 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) return false; hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + hb_face_builder_data_t::table_entry_t *entry = data->tables.push (); + if (data->tables.in_error()) + return false; entry->tag = tag; entry->blob = hb_blob_reference (blob); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.hh b/src/java.desktop/share/native/libharfbuzz/hb-face.hh index b2730eb0a42..010eaba9e6f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-face.hh @@ -94,7 +94,7 @@ struct hb_face_t unsigned int get_num_glyphs () const { unsigned int ret = num_glyphs.get_relaxed (); - if (unlikely (ret == (unsigned int) -1)) + if (unlikely (ret == UINT_MAX)) return load_num_glyphs (); return ret; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc index df30871ecde..d1d26b6a9f2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc @@ -26,6 +26,7 @@ #include "hb-shaper-impl.hh" +#ifndef HB_NO_FALLBACK_SHAPE /* * shaper face data @@ -120,3 +121,5 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED, return true; } + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-font.cc index 855c9983328..42bf3e948d2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.cc @@ -33,6 +33,9 @@ #include "hb-ot.h" +#include "hb-ot-var-avar-table.hh" +#include "hb-ot-var-fvar-table.hh" + /** * SECTION:hb-font @@ -355,6 +358,7 @@ hb_font_get_glyph_h_kerning_default (hb_font_t *font, return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph)); } +#ifndef HB_DISABLE_DEPRECATED static hb_position_t hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED, void *font_data HB_UNUSED, @@ -373,6 +377,7 @@ hb_font_get_glyph_v_kerning_default (hb_font_t *font, { return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph)); } +#endif static hb_bool_t hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, @@ -672,7 +677,8 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ void *user_data, \ hb_destroy_func_t destroy) \ { \ - if (hb_object_is_immutable (ffuncs)) { \ + if (hb_object_is_immutable (ffuncs)) \ + { \ if (destroy) \ destroy (user_data); \ return; \ @@ -789,6 +795,29 @@ hb_font_get_nominal_glyph (hb_font_t *font, return font->get_nominal_glyph (unicode, glyph); } +/** + * hb_font_get_nominal_glyphs: + * @font: a font. + * + * + * + * Return value: + * + * Since: 2.6.3 + **/ +unsigned int +hb_font_get_nominal_glyphs (hb_font_t *font, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride) +{ + return font->get_nominal_glyphs (count, + first_unicode, unicode_stride, + first_glyph, glyph_stride); +} + /** * hb_font_get_variation_glyph: * @font: a font. @@ -936,7 +965,6 @@ hb_font_get_glyph_v_origin (hb_font_t *font, * Return value: * * Since: 0.9.2 - * Deprecated: 2.0.0 **/ hb_position_t hb_font_get_glyph_h_kerning (hb_font_t *font, @@ -945,6 +973,7 @@ hb_font_get_glyph_h_kerning (hb_font_t *font, return font->get_glyph_h_kerning (left_glyph, right_glyph); } +#ifndef HB_DISABLE_DEPRECATED /** * hb_font_get_glyph_v_kerning: * @font: a font. @@ -964,6 +993,7 @@ hb_font_get_glyph_v_kerning (hb_font_t *font, { return font->get_glyph_v_kerning (top_glyph, bottom_glyph); } +#endif /** * hb_font_get_glyph_extents: @@ -1185,7 +1215,6 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, * * * Since: 0.9.2 - * Deprecated: 2.0.0 **/ void hb_font_get_glyph_kerning_for_direction (hb_font_t *font, @@ -1298,6 +1327,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* x_scale */ 1000, /* y_scale */ + 1<<16, /* x_mult */ + 1<<16, /* y_mult */ 0, /* x_ppem */ 0, /* y_ppem */ @@ -1305,6 +1336,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 0, /* num_coords */ nullptr, /* coords */ + nullptr, /* design_coords */ const_cast (&_hb_Null_hb_font_funcs_t), @@ -1328,6 +1360,7 @@ _hb_font_create (hb_face_t *face) font->klass = hb_font_funcs_get_empty (); font->data.init0 (font); font->x_scale = font->y_scale = hb_face_get_upem (face); + font->x_mult = font->y_mult = 1 << 16; return font; } @@ -1347,12 +1380,28 @@ hb_font_create (hb_face_t *face) { hb_font_t *font = _hb_font_create (face); +#ifndef HB_NO_OT_FONT /* Install our in-house, very lightweight, funcs. */ hb_ot_font_set_funcs (font); +#endif return font; } +static void +_hb_font_adopt_var_coords (hb_font_t *font, + int *coords, /* 2.14 normalized */ + float *design_coords, + unsigned int coords_length) +{ + free (font->coords); + free (font->design_coords); + + font->coords = coords; + font->design_coords = design_coords; + font->num_coords = coords_length; +} + /** * hb_font_create_sub_font: * @parent: parent font. @@ -1378,21 +1427,27 @@ hb_font_create_sub_font (hb_font_t *parent) font->x_scale = parent->x_scale; font->y_scale = parent->y_scale; + font->mults_changed (); font->x_ppem = parent->x_ppem; font->y_ppem = parent->y_ppem; font->ptem = parent->ptem; - font->num_coords = parent->num_coords; - if (!font->num_coords) - font->coords = nullptr; - else + unsigned int num_coords = parent->num_coords; + if (num_coords) { - unsigned int size = parent->num_coords * sizeof (parent->coords[0]); - font->coords = (int *) malloc (size); - if (unlikely (!font->coords)) - font->num_coords = 0; + int *coords = (int *) calloc (num_coords, sizeof (parent->coords[0])); + float *design_coords = (float *) calloc (num_coords, sizeof (parent->design_coords[0])); + if (likely (coords && design_coords)) + { + memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0])); + memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0])); + _hb_font_adopt_var_coords (font, coords, design_coords, num_coords); + } else - memcpy (font->coords, parent->coords, size); + { + free (coords); + free (design_coords); + } } return font; @@ -1410,7 +1465,7 @@ hb_font_create_sub_font (hb_font_t *parent) hb_font_t * hb_font_get_empty () { - return const_cast (&Null(hb_font_t)); + return const_cast (&Null (hb_font_t)); } /** @@ -1452,6 +1507,7 @@ hb_font_destroy (hb_font_t *font) hb_font_funcs_destroy (font->klass); free (font->coords); + free (font->design_coords); free (font); } @@ -1597,7 +1653,9 @@ hb_font_set_face (hb_font_t *font, hb_face_t *old = font->face; + hb_face_make_immutable (face); font->face = hb_face_reference (face); + font->mults_changed (); hb_face_destroy (old); } @@ -1707,6 +1765,7 @@ hb_font_set_scale (hb_font_t *font, font->x_scale = x_scale; font->y_scale = y_scale; + font->mults_changed (); } /** @@ -1805,21 +1864,11 @@ hb_font_get_ptem (hb_font_t *font) return font->ptem; } +#ifndef HB_NO_VAR /* * Variations */ -static void -_hb_font_adopt_var_coords_normalized (hb_font_t *font, - int *coords, /* 2.14 normalized */ - unsigned int coords_length) -{ - free (font->coords); - - font->coords = coords; - font->num_coords = coords_length; -} - /** * hb_font_set_variations: * @@ -1842,13 +1891,30 @@ hb_font_set_variations (hb_font_t *font, unsigned int coords_length = hb_ot_var_get_axis_count (font->face); int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr; - if (unlikely (coords_length && !normalized)) + float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr; + + if (unlikely (coords_length && !(normalized && design_coords))) + { + free (normalized); + free (design_coords); return; + } - hb_ot_var_normalize_variations (font->face, - variations, variations_length, - normalized, coords_length); - _hb_font_adopt_var_coords_normalized (font, normalized, coords_length); + const OT::fvar &fvar = *font->face->table.fvar; + for (unsigned int i = 0; i < variations_length; i++) + { + hb_ot_var_axis_info_t info; + if (hb_ot_var_find_axis_info (font->face, variations[i].tag, &info) && + info.axis_index < coords_length) + { + float v = variations[i].value; + design_coords[info.axis_index] = v; + normalized[info.axis_index] = fvar.normalize_axis_value (info.axis_index, v); + } + } + font->face->table.avar->map_coords (normalized, coords_length); + + _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); } /** @@ -1865,11 +1931,47 @@ hb_font_set_var_coords_design (hb_font_t *font, return; int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr; - if (unlikely (coords_length && !normalized)) + float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr; + + if (unlikely (coords_length && !(normalized && design_coords))) + { + free (normalized); + free (design_coords); return; + } + + if (coords_length) + memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0])); hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized); - _hb_font_adopt_var_coords_normalized (font, normalized, coords_length); + _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); +} + +/** + * hb_font_set_var_named_instance: + * @font: a font. + * @instance_index: named instance index. + * + * Sets design coords of a font from a named instance index. + * + * Since: 2.6.0 + */ +void +hb_font_set_var_named_instance (hb_font_t *font, + unsigned instance_index) +{ + if (hb_object_is_immutable (font)) + return; + + unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr); + + float *coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr; + if (unlikely (coords_length && !coords)) + return; + + hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords); + hb_font_set_var_coords_design (font, coords, coords_length); + free (coords); } /** @@ -1886,13 +1988,30 @@ hb_font_set_var_coords_normalized (hb_font_t *font, return; int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr; - if (unlikely (coords_length && !copy)) + int *unmapped = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr; + float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (design_coords[0])) : nullptr; + + if (unlikely (coords_length && !(copy && unmapped && design_coords))) + { + free (copy); + free (unmapped); + free (design_coords); return; + } if (coords_length) + { memcpy (copy, coords, coords_length * sizeof (coords[0])); + memcpy (unmapped, coords, coords_length * sizeof (coords[0])); + } + + /* Best effort design coords simulation */ + font->face->table.avar->unmap_coords (unmapped, coords_length); + for (unsigned int i = 0; i < coords_length; ++i) + design_coords[i] = font->face->table.fvar->unnormalize_axis_value (i, unmapped[i]); + free (unmapped); - _hb_font_adopt_var_coords_normalized (font, copy, coords_length); + _hb_font_adopt_var_coords (font, copy, design_coords, coords_length); } /** @@ -1913,7 +2032,28 @@ hb_font_get_var_coords_normalized (hb_font_t *font, return font->coords; } +#ifdef HB_EXPERIMENTAL_API +/** + * hb_font_get_var_coords_design: + * + * Return value is valid as long as variation coordinates of the font + * are not modified. + * + * Since: EXPERIMENTAL + */ +const float * +hb_font_get_var_coords_design (hb_font_t *font, + unsigned int *length) +{ + if (length) + *length = font->num_coords; + + return font->design_coords; +} +#endif +#endif +#ifndef HB_DISABLE_DEPRECATED /* * Deprecated get_glyph_func(): */ @@ -2015,6 +2155,13 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_func_t func, void *user_data, hb_destroy_func_t destroy) { + if (hb_object_is_immutable (ffuncs)) + { + if (destroy) + destroy (user_data); + return; + } + hb_font_get_glyph_trampoline_t *trampoline; trampoline = trampoline_create (func, user_data, destroy); @@ -2036,3 +2183,4 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, trampoline, trampoline_destroy); } +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.h b/src/java.desktop/share/native/libharfbuzz/hb-font.h index 85893f97c63..217bf33f440 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.h @@ -33,6 +33,7 @@ #include "hb-common.h" #include "hb-face.h" +#include "hb-draw.h" HB_BEGIN_DECLS @@ -157,6 +158,11 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t; typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t; +typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + void *user_data); +typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t; + typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, @@ -356,6 +362,22 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_v_origin_func_t func, void *user_data, hb_destroy_func_t destroy); +/** + * hb_font_funcs_set_glyph_h_kerning_func: + * @ffuncs: font functions. + * @func: (closure user_data) (destroy destroy) (scope notified): + * @user_data: + * @destroy: + * + * + * + * Since: 0.9.2 + **/ +HB_EXTERN void +hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_h_kerning_func_t func, + void *user_data, hb_destroy_func_t destroy); + /** * hb_font_funcs_set_glyph_extents_func: * @ffuncs: font functions. @@ -438,6 +460,14 @@ hb_font_get_variation_glyph (hb_font_t *font, hb_codepoint_t unicode, hb_codepoint_t variation_selector, hb_codepoint_t *glyph); +HB_EXTERN unsigned int +hb_font_get_nominal_glyphs (hb_font_t *font, + unsigned int count, + const hb_codepoint_t *first_unicode, + unsigned int unicode_stride, + hb_codepoint_t *first_glyph, + unsigned int glyph_stride); + HB_EXTERN hb_position_t hb_font_get_glyph_h_advance (hb_font_t *font, hb_codepoint_t glyph); @@ -469,6 +499,10 @@ hb_font_get_glyph_v_origin (hb_font_t *font, hb_codepoint_t glyph, hb_position_t *x, hb_position_t *y); +HB_EXTERN hb_position_t +hb_font_get_glyph_h_kerning (hb_font_t *font, + hb_codepoint_t left_glyph, hb_codepoint_t right_glyph); + HB_EXTERN hb_bool_t hb_font_get_glyph_extents (hb_font_t *font, hb_codepoint_t glyph, @@ -531,6 +565,12 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font, hb_direction_t direction, hb_position_t *x, hb_position_t *y); +HB_EXTERN void +hb_font_get_glyph_kerning_for_direction (hb_font_t *font, + hb_codepoint_t first_glyph, hb_codepoint_t second_glyph, + hb_direction_t direction, + hb_position_t *x, hb_position_t *y); + HB_EXTERN hb_bool_t hb_font_get_glyph_extents_for_origin (hb_font_t *font, hb_codepoint_t glyph, @@ -665,6 +705,12 @@ hb_font_set_var_coords_design (hb_font_t *font, const float *coords, unsigned int coords_length); +#ifdef HB_EXPERIMENTAL_API +HB_EXTERN const float * +hb_font_get_var_coords_design (hb_font_t *font, + unsigned int *length); +#endif + HB_EXTERN void hb_font_set_var_coords_normalized (hb_font_t *font, const int *coords, /* 2.14 normalized */ @@ -674,6 +720,16 @@ HB_EXTERN const int * hb_font_get_var_coords_normalized (hb_font_t *font, unsigned int *length); +HB_EXTERN void +hb_font_set_var_named_instance (hb_font_t *font, + unsigned instance_index); + +#ifdef HB_EXPERIMENTAL_API +HB_EXTERN hb_bool_t +hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, + const hb_draw_funcs_t *funcs, void *user_data); +#endif + HB_END_DECLS #endif /* HB_FONT_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.hh b/src/java.desktop/share/native/libharfbuzz/hb-font.hh index dd33d2f7d7c..2fa9cea7388 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.hh @@ -52,7 +52,7 @@ HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \ HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \ HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \ - HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \ + HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \ HB_FONT_FUNC_IMPLEMENT (glyph_extents) \ HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \ HB_FONT_FUNC_IMPLEMENT (glyph_name) \ @@ -107,8 +107,10 @@ struct hb_font_t hb_font_t *parent; hb_face_t *face; - int x_scale; - int y_scale; + int32_t x_scale; + int32_t y_scale; + int64_t x_mult; + int64_t y_mult; unsigned int x_ppem; unsigned int y_ppem; @@ -118,6 +120,7 @@ struct hb_font_t /* Font variation coordinates. */ unsigned int num_coords; int *coords; + float *design_coords; hb_font_funcs_t *klass; void *user_data; @@ -127,16 +130,16 @@ struct hb_font_t /* Convert from font-space to user-space */ - int dir_scale (hb_direction_t direction) - { return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; } - hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); } - hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); } - hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); } - hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); } + int64_t dir_mult (hb_direction_t direction) + { return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; } + hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); } + hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); } + hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); } + hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); } float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); } float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); } hb_position_t em_scale_dir (int16_t v, hb_direction_t direction) - { return em_scale (v, dir_scale (direction)); } + { return em_mult (v, dir_mult (direction)); } /* Convert from parent-font user-space to our user-space */ hb_position_t parent_scale_x_distance (hb_position_t v) @@ -214,7 +217,7 @@ struct hb_font_t } hb_bool_t get_nominal_glyph (hb_codepoint_t unicode, - hb_codepoint_t *glyph) + hb_codepoint_t *glyph) { *glyph = 0; return klass->get.f.nominal_glyph (this, user_data, @@ -284,7 +287,7 @@ struct hb_font_t } hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph, - hb_position_t *x, hb_position_t *y) + hb_position_t *x, hb_position_t *y) { *x = *y = 0; return klass->get.f.glyph_h_origin (this, user_data, @@ -304,21 +307,29 @@ struct hb_font_t hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph, hb_codepoint_t right_glyph) { +#ifdef HB_DISABLE_DEPRECATED + return 0; +#else return klass->get.f.glyph_h_kerning (this, user_data, left_glyph, right_glyph, klass->user_data.glyph_h_kerning); +#endif } hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph) { +#ifdef HB_DISABLE_DEPRECATED + return 0; +#else return klass->get.f.glyph_v_kerning (this, user_data, top_glyph, bottom_glyph, klass->user_data.glyph_v_kerning); +#endif } hb_bool_t get_glyph_extents (hb_codepoint_t glyph, - hb_glyph_extents_t *extents) + hb_glyph_extents_t *extents) { memset (extents, 0, sizeof (*extents)); return klass->get.f.glyph_extents (this, user_data, @@ -328,7 +339,7 @@ struct hb_font_t } hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index, - hb_position_t *x, hb_position_t *y) + hb_position_t *x, hb_position_t *y) { *x = *y = 0; return klass->get.f.glyph_contour_point (this, user_data, @@ -599,15 +610,19 @@ struct hb_font_t return false; } - hb_position_t em_scale (int16_t v, int scale) + void mults_changed () + { + signed upem = face->get_upem (); + x_mult = ((int64_t) x_scale << 16) / upem; + y_mult = ((int64_t) y_scale << 16) / upem; + } + + hb_position_t em_mult (int16_t v, int64_t mult) { - int upem = face->get_upem (); - int64_t scaled = v * (int64_t) scale; - scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */ - return (hb_position_t) (scaled / upem); + return (hb_position_t) ((v * mult) >> 16); } hb_position_t em_scalef (float v, int scale) - { return (hb_position_t) round (v * scale / face->get_upem ()); } + { return (hb_position_t) roundf (v * scale / face->get_upem ()); } float em_fscale (int16_t v, int scale) { return (float) v * scale / face->get_upem (); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc index d73c4aaac73..6b7b9e08771 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc @@ -29,6 +29,8 @@ #include "hb.hh" +#ifdef HAVE_FREETYPE + #include "hb-ft.h" #include "hb-font.hh" @@ -46,8 +48,13 @@ * @short_description: FreeType integration * @include: hb-ft.h * - * Functions for using HarfBuzz with the FreeType library to provide face and + * Functions for using HarfBuzz with the FreeType library. + * + * HarfBuzz supports using FreeType to provide face and * font data. + * + * Note that FreeType is not thread-safe, therefore these + * functions are not thread-safe either. **/ @@ -85,9 +92,7 @@ static hb_ft_font_t * _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) { hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t)); - - if (unlikely (!ft_font)) - return nullptr; + if (unlikely (!ft_font)) return nullptr; ft_font->lock.init (); ft_font->ft_face = ft_face; @@ -96,7 +101,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref) ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; - ft_font->cached_x_scale.set (0); + ft_font->cached_x_scale.set_relaxed (0); ft_font->advance_cache.init (); return ft_font; @@ -125,10 +130,13 @@ _hb_ft_font_destroy (void *data) /** * hb_ft_font_set_load_flags: - * @font: - * @load_flags: + * @font: #hb_font_t to work upon + * @load_flags: The FreeType load flags to set * + * Sets the FT_Load_Glyph load flags for the specified #hb_font_t. * + * For more information, see + * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx * * Since: 1.0.5 **/ @@ -138,7 +146,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) if (hb_object_is_immutable (font)) return; - if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) return; hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; @@ -148,17 +156,21 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) /** * hb_ft_font_get_load_flags: - * @font: + * @font: #hb_font_t to work upon * + * Fetches the FT_Load_Glyph load flags of the specified #hb_font_t. * + * For more information, see + * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx + * + * Return value: FT_Load_Glyph flags found * - * Return value: * Since: 1.0.5 **/ int hb_ft_font_get_load_flags (hb_font_t *font) { - if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) return 0; const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; @@ -166,17 +178,69 @@ hb_ft_font_get_load_flags (hb_font_t *font) return ft_font->load_flags; } +/** + * hb_ft_get_face: + * @font: #hb_font_t to work upon + * + * Fetches the FT_Face associated with the specified #hb_font_t + * font object. + * + * Return value: the FT_Face found + * + * Since: 0.9.2 + **/ FT_Face hb_ft_font_get_face (hb_font_t *font) { - if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy) + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) + return nullptr; + + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; + + return ft_font->ft_face; +} + +/** + * hb_ft_font_lock_face: + * @font: + * + * + * + * Return value: + * Since: 2.6.5 + **/ +FT_Face +hb_ft_font_lock_face (hb_font_t *font) +{ + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) return nullptr; const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; + ft_font->lock.lock (); + return ft_font->ft_face; } +/** + * hb_ft_font_unlock_face: + * @font: + * + * + * + * Return value: + * Since: 2.6.5 + **/ +void +hb_ft_font_unlock_face (hb_font_t *font) +{ + if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)) + return; + + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data; + + ft_font->lock.unlock (); +} static hb_bool_t @@ -346,6 +410,25 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, return true; } +#ifndef HB_NO_OT_SHAPE_FALLBACK +static hb_position_t +hb_ft_get_glyph_h_kerning (hb_font_t *font, + void *font_data, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + FT_Vector kerningv; + + FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED; + if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv)) + return 0; + + return kerningv.x; +} +#endif + static hb_bool_t hb_ft_get_glyph_extents (hb_font_t *font, void *font_data, @@ -439,7 +522,7 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED, else { /* Make a nul-terminated version. */ char buf[128]; - len = MIN (len, (int) sizeof (buf) - 1); + len = hb_min (len, (int) sizeof (buf) - 1); strncpy (buf, name, len); buf[len] = '\0'; *glyph = FT_Get_Name_Index (ft_face, buf); @@ -497,6 +580,10 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_tcharmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL; + hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref); + if (unlikely (!ft_font)) return; + hb_font_set_funcs (font, _hb_ft_get_font_funcs (), - _hb_ft_font_create (ft_face, symbol, unref), + ft_font, _hb_ft_font_destroy); } static hb_blob_t * -reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { FT_Face ft_face = (FT_Face) user_data; FT_Byte *buffer; @@ -570,12 +660,22 @@ reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) /** * hb_ft_face_create: - * @ft_face: (destroy destroy) (scope notified): - * @destroy: + * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon + * @destroy: A callback to call when the face object is not needed anymore + * + * Creates an #hb_face_t face object from the specified FT_Face. * + * This variant of the function does not provide any life-cycle management. * + * Most client programs should use hb_ft_face_create_referenced() + * (or, perhaps, hb_ft_face_create_cached()) instead. + * + * If you know you have valid reasons not to use hb_ft_face_create_referenced(), + * then it is the client program's responsibility to destroy @ft_face + * after the #hb_face_t face object has been destroyed. + * + * Return value: (transfer full): the new #hb_face_t face object * - * Return value: (transfer full): * Since: 0.9.2 **/ hb_face_t * @@ -594,7 +694,7 @@ hb_ft_face_create (FT_Face ft_face, face = hb_face_create (blob, ft_face->face_index); hb_blob_destroy (blob); } else { - face = hb_face_create_for_tables (reference_table, ft_face, destroy); + face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy); } hb_face_set_index (face, ft_face->face_index); @@ -605,11 +705,20 @@ hb_ft_face_create (FT_Face ft_face, /** * hb_ft_face_create_referenced: - * @ft_face: + * @ft_face: FT_Face to work upon + * + * Creates an #hb_face_t face object from the specified FT_Face. * + * This is the preferred variant of the hb_ft_face_create* + * function family, because it calls FT_Reference_Face() on @ft_face, + * ensuring that @ft_face remains alive as long as the resulting + * #hb_face_t face object remains alive. Also calls FT_Done_Face() + * when the #hb_face_t face object is destroyed. * + * Use this version unless you know you have good reasons not to. + * + * Return value: (transfer full): the new #hb_face_t face object * - * Return value: (transfer full): * Since: 0.9.38 **/ hb_face_t * @@ -627,11 +736,21 @@ hb_ft_face_finalize (FT_Face ft_face) /** * hb_ft_face_create_cached: - * @ft_face: + * @ft_face: FT_Face to work upon + * + * Creates an #hb_face_t face object from the specified FT_Face. + * + * This variant of the function caches the newly created #hb_face_t + * face object, using the @generic pointer of @ft_face. Subsequent function + * calls that are passed the same @ft_face parameter will have the same + * #hb_face_t returned to them, and that #hb_face_t will be correctly + * reference counted. * + * However, client programs are still responsible for destroying + * @ft_face after the last #hb_face_t face object has been destroyed. * + * Return value: (transfer full): the new #hb_face_t face object * - * Return value: (transfer full): * Since: 0.9.2 **/ hb_face_t * @@ -649,15 +768,34 @@ hb_ft_face_create_cached (FT_Face ft_face) return hb_face_reference ((hb_face_t *) ft_face->generic.data); } - /** * hb_ft_font_create: - * @ft_face: (destroy destroy) (scope notified): - * @destroy: + * @ft_face: (destroy destroy) (scope notified): FT_Face to work upon + * @destroy: (optional): A callback to call when the font object is not needed anymore + * + * Creates an #hb_font_t font object from the specified FT_Face. + * + * Note: You must set the face size on @ft_face before calling + * hb_ft_font_create() on it. Otherwise, HarfBuzz will not pick up + * the face size. * + * This variant of the function does not provide any life-cycle management. * + * Most client programs should use hb_ft_font_create_referenced() + * instead. + * + * If you know you have valid reasons not to use hb_ft_font_create_referenced(), + * then it is the client program's responsibility to destroy @ft_face + * after the #hb_font_t font object has been destroyed. + * + * HarfBuzz will use the @destroy callback on the #hb_font_t font object + * if it is supplied when you use this function. However, even if @destroy + * is provided, it is the client program's responsibility to destroy @ft_face, + * and it is the client program's responsibility to ensure that @ft_face is + * destroyed only after the #hb_font_t font object has been destroyed. + * + * Return value: (transfer full): the new #hb_font_t font object * - * Return value: (transfer full): * Since: 0.9.2 **/ hb_font_t * @@ -675,6 +813,16 @@ hb_ft_font_create (FT_Face ft_face, return font; } +/** + * hb_ft_font_has_changed: + * @font: #hb_font_t to work upon + * + * Refreshes the state of @font when the underlying FT_Face has changed. + * This function should be called after changing the size or + * variation-axis settings on the FT_Face. + * + * Since: 1.0.5 + **/ void hb_ft_font_changed (hb_font_t *font) { @@ -682,6 +830,7 @@ hb_ft_font_changed (hb_font_t *font) return; hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; + FT_Face ft_face = ft_font->ft_face; hb_font_set_scale (font, @@ -693,7 +842,7 @@ hb_ft_font_changed (hb_font_t *font) ft_face->size->metrics.y_ppem); #endif -#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES +#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) FT_MM_Var *mm_var = nullptr; if (!FT_Get_MM_Var (ft_face, &mm_var)) { @@ -730,11 +879,23 @@ hb_ft_font_changed (hb_font_t *font) /** * hb_ft_font_create_referenced: - * @ft_face: + * @ft_face: FT_Face to work upon + * + * Creates an #hb_font_t font object from the specified FT_Face. + * + * Note: You must set the face size on @ft_face before calling + * hb_ft_font_create_references() on it. Otherwise, HarfBuzz will not pick up + * the face size. + * + * This is the preferred variant of the hb_ft_font_create* + * function family, because it calls FT_Reference_Face() on @ft_face, + * ensuring that @ft_face remains alive as long as the resulting + * #hb_font_t font object remains alive. * + * Use this version unless you know you have good reasons not to. * + * Return value: (transfer full): the new #hb_font_t font object * - * Return value: (transfer full): * Since: 0.9.38 **/ hb_font_t * @@ -748,7 +909,7 @@ hb_ft_font_create_referenced (FT_Face ft_face) static void free_static_ft_library (); #endif -static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t, hb_ft_library_lazy_loader_t> { static FT_Library create () @@ -793,6 +954,28 @@ _release_blob (FT_Face ft_face) hb_blob_destroy ((hb_blob_t *) ft_face->generic.data); } +/** + * hb_ft_font_set_funcs: + * @font: #hb_font_t to work upon + * + * Configures the font-functions structure of the specified + * #hb_font_t font object to use FreeType font functions. + * + * In particular, you can use this function to configure an + * existing #hb_face_t face object for use with FreeType font + * functions even if that #hb_face_t face object was initially + * created with hb_face_create(), and therefore was not + * initially configured to use FreeType font functions. + * + * An #hb_face_t face object created with hb_ft_face_create() + * is preconfigured for FreeType font functions and does not + * require this function to be used. + * + * Note: Internally, this function creates an FT_Face. +* + * + * Since: 1.0.5 + **/ void hb_ft_font_set_funcs (hb_font_t *font) { @@ -815,8 +998,8 @@ hb_ft_font_set_funcs (hb_font_t *font) return; } - if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE)) - FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL); + if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL)) + FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); FT_Set_Char_Size (ft_face, abs (font->x_scale), abs (font->y_scale), @@ -832,7 +1015,7 @@ hb_ft_font_set_funcs (hb_font_t *font) FT_Set_Transform (ft_face, &matrix, nullptr); } -#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES +#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) unsigned int num_coords; const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); if (num_coords) @@ -841,7 +1024,7 @@ hb_ft_font_set_funcs (hb_font_t *font) if (ft_coords) { for (unsigned int i = 0; i < num_coords; i++) - ft_coords[i] = coords[i] << 2; + ft_coords[i] = coords[i] * 4; FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords); free (ft_coords); } @@ -854,3 +1037,6 @@ hb_ft_font_set_funcs (hb_font_t *font) _hb_ft_font_set_funcs (font, ft_face, true); hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.h b/src/java.desktop/share/native/libharfbuzz/hb-ft.h index dda30d38157..4962eaf38d4 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ft.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.h @@ -110,6 +110,12 @@ hb_ft_font_create_referenced (FT_Face ft_face); HB_EXTERN FT_Face hb_ft_font_get_face (hb_font_t *font); +HB_EXTERN FT_Face +hb_ft_font_lock_face (hb_font_t *font); + +HB_EXTERN void +hb_ft_font_unlock_face (hb_font_t *font); + HB_EXTERN void hb_ft_font_set_load_flags (hb_font_t *font, int load_flags); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh index c4ab26dc063..99a441af44f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh @@ -1,5 +1,6 @@ /* * Copyright © 2018 Google, Inc. + * Copyright © 2019 Facebook, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -22,13 +23,15 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * Google Author(s): Behdad Esfahbod + * Facebook Author(s): Behdad Esfahbod */ #ifndef HB_ITER_HH #define HB_ITER_HH #include "hb.hh" -#include "hb-null.hh" +#include "hb-algs.hh" +#include "hb-meta.hh" /* Unified iterator object. @@ -39,16 +42,32 @@ * copied by value. If the collection / object being iterated on * is writable, then the iterator returns lvalues, otherwise it * returns rvalues. + * + * TODO Document more. + * + * If iterator implementation implements operator!=, then can be + * used in range-based for loop. That comes free if the iterator + * is random-access. Otherwise, the range-based for loop incurs + * one traversal to find end(), which can be avoided if written + * as a while-style for loop, or if iterator implements a faster + * __end__() method. + * TODO When opting in for C++17, address this by changing return + * type of .end()? + */ + +/* + * Base classes for iterators. */ /* Base class for all iterators. */ -template +template struct hb_iter_t { - typedef Iter iter_t; - typedef iter_t const_iter_t; typedef Item item_t; - static constexpr unsigned item_size = hb_static_size (Item); + constexpr unsigned get_item_size () const { return hb_static_size (Item); } + static constexpr bool is_iterator = true; + static constexpr bool is_random_access_iterator = false; + static constexpr bool is_sorted_iterator = false; private: /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ @@ -56,53 +75,119 @@ struct hb_iter_t iter_t* thiz () { return static_cast< iter_t *> (this); } public: - /* Operators. */ - operator iter_t () { return iter(); } - explicit_operator bool () const { return more (); } - item_t& operator * () const { return item (); } - item_t& operator [] (signed i) const { return item_at ((unsigned) i); } - iter_t& operator += (unsigned count) { forward (count); return *thiz(); } - iter_t& operator ++ () { next (); return *thiz(); } - iter_t& operator -= (unsigned count) { rewind (count); return *thiz(); } - iter_t& operator -- () { prev (); return *thiz(); } - iter_t operator + (unsigned count) { iter_t c (*thiz()); c += count; return c; } - iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; } - iter_t operator - (unsigned count) { iter_t c (*thiz()); c -= count; return c; } - iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; } + /* TODO: + * Port operators below to use hb_enable_if to sniff which method implements + * an operator and use it, and remove hb_iter_fallback_mixin_t completely. */ - /* Methods. */ + /* Operators. */ iter_t iter () const { return *thiz(); } - const_iter_t const_iter () const { return iter (); } - item_t& item () const { return thiz()->__item__ (); } - item_t& item_at (unsigned i) const { return thiz()->__item_at__ (i); } - bool more () const { return thiz()->__more__ (); } + iter_t operator + () const { return *thiz(); } + iter_t begin () const { return *thiz(); } + iter_t end () const { return thiz()->__end__ (); } + explicit operator bool () const { return thiz()->__more__ (); } unsigned len () const { return thiz()->__len__ (); } - void next () { thiz()->__next__ (); } - void forward (unsigned n) { thiz()->__forward__ (n); } - void prev () { thiz()->__prev__ (); } - void rewind (unsigned n) { thiz()->__rewind__ (n); } - bool random_access () const { return thiz()->__random_access__ (); } + /* The following can only be enabled if item_t is reference type. Otherwise + * it will be returning pointer to temporary rvalue. + * TODO Use a wrapper return type to fix for non-reference type. */ + template + hb_remove_reference* operator -> () const { return hb_addressof (**thiz()); } + item_t operator * () const { return thiz()->__item__ (); } + item_t operator * () { return thiz()->__item__ (); } + item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); } + item_t operator [] (unsigned i) { return thiz()->__item_at__ (i); } + iter_t& operator += (unsigned count) & { thiz()->__forward__ (count); return *thiz(); } + iter_t operator += (unsigned count) && { thiz()->__forward__ (count); return *thiz(); } + iter_t& operator ++ () & { thiz()->__next__ (); return *thiz(); } + iter_t operator ++ () && { thiz()->__next__ (); return *thiz(); } + iter_t& operator -= (unsigned count) & { thiz()->__rewind__ (count); return *thiz(); } + iter_t operator -= (unsigned count) && { thiz()->__rewind__ (count); return *thiz(); } + iter_t& operator -- () & { thiz()->__prev__ (); return *thiz(); } + iter_t operator -- () && { thiz()->__prev__ (); return *thiz(); } + iter_t operator + (unsigned count) const { auto c = thiz()->iter (); c += count; return c; } + friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; } + iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; } + iter_t operator - (unsigned count) const { auto c = thiz()->iter (); c -= count; return c; } + iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; } + template + iter_t& operator >> (T &v) & { v = **thiz(); ++*thiz(); return *thiz(); } + template + iter_t operator >> (T &v) && { v = **thiz(); ++*thiz(); return *thiz(); } + template + iter_t& operator << (const T v) & { **thiz() = v; ++*thiz(); return *thiz(); } + template + iter_t operator << (const T v) && { **thiz() = v; ++*thiz(); return *thiz(); } protected: - hb_iter_t () {} - hb_iter_t (const hb_iter_t &o HB_UNUSED) {} - void operator = (const hb_iter_t &o HB_UNUSED) {} + hb_iter_t () = default; + hb_iter_t (const hb_iter_t &o HB_UNUSED) = default; + hb_iter_t (hb_iter_t &&o HB_UNUSED) = default; + hb_iter_t& operator = (const hb_iter_t &o HB_UNUSED) = default; + hb_iter_t& operator = (hb_iter_t &&o HB_UNUSED) = default; }; -/* Base class for sorted iterators. Does not enforce anything. - * Just for class taxonomy and requirements. */ -template -struct hb_sorted_iter_t : hb_iter_t +#define HB_ITER_USING(Name) \ + using item_t = typename Name::item_t; \ + using Name::begin; \ + using Name::end; \ + using Name::get_item_size; \ + using Name::is_iterator; \ + using Name::iter; \ + using Name::operator bool; \ + using Name::len; \ + using Name::operator ->; \ + using Name::operator *; \ + using Name::operator []; \ + using Name::operator +=; \ + using Name::operator ++; \ + using Name::operator -=; \ + using Name::operator --; \ + using Name::operator +; \ + using Name::operator -; \ + using Name::operator >>; \ + using Name::operator <<; \ + static_assert (true, "") + +/* Returns iterator / item type of a type. */ +template +using hb_iter_type = decltype (hb_deref (hb_declval (Iterable)).iter ()); +template +using hb_item_type = decltype (*hb_deref (hb_declval (Iterable)).iter ()); + + +template struct hb_array_t; +template struct hb_sorted_array_t; + +struct { - protected: - hb_sorted_iter_t () {} - hb_sorted_iter_t (const hb_sorted_iter_t &o) : hb_iter_t (o) {} - void operator = (const hb_sorted_iter_t &o HB_UNUSED) {} -}; + template hb_iter_type + operator () (T&& c) const + { return hb_deref (hb_forward (c)).iter (); } + + /* Specialization for C arrays. */ + + template inline hb_array_t + operator () (Type *array, unsigned int length) const + { return hb_array_t (array, length); } + + template hb_array_t + operator () (Type (&array)[length]) const + { return hb_array_t (array, length); } + +} +HB_FUNCOBJ (hb_iter); +struct +{ + template unsigned + operator () (T&& c) const + { return c.len (); } + +} +HB_FUNCOBJ (hb_len); /* Mixin to fill in what the subclass doesn't provide. */ -template -struct hb_iter_mixin_t +template +struct hb_iter_fallback_mixin_t { private: /* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */ @@ -111,42 +196,743 @@ struct hb_iter_mixin_t public: /* Access: Implement __item__(), or __item_at__() if random-access. */ - item_t& __item__ () const { return thiz()->item_at (0); } - item_t& __item_at__ (unsigned i) const { return *(thiz() + i); } + item_t __item__ () const { return (*thiz())[0]; } + item_t __item_at__ (unsigned i) const { return *(*thiz() + i); } /* Termination: Implement __more__(), or __len__() if random-access. */ - bool __more__ () const { return thiz()->__len__ (); } + bool __more__ () const { return bool (thiz()->len ()); } unsigned __len__ () const - { iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; }; return l; } + { iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; } return l; } /* Advancing: Implement __next__(), or __forward__() if random-access. */ - void __next__ () { thiz()->forward (1); } - void __forward__ (unsigned n) { while (n--) thiz()->next (); } + void __next__ () { *thiz() += 1; } + void __forward__ (unsigned n) { while (*thiz() && n--) ++*thiz(); } /* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */ - void __prev__ () { thiz()->rewind (1); } - void __rewind__ (unsigned n) { while (n--) thiz()->prev (); } + void __prev__ () { *thiz() -= 1; } + void __rewind__ (unsigned n) { while (*thiz() && n--) --*thiz(); } + + /* Range-based for: Implement __end__() if can be done faster, + * and operator!=. */ + iter_t __end__ () const + { + if (thiz()->is_random_access_iterator) + return *thiz() + thiz()->len (); + /* Above expression loops twice. Following loops once. */ + auto it = *thiz(); + while (it) ++it; + return it; + } + + protected: + hb_iter_fallback_mixin_t () = default; + hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default; + hb_iter_fallback_mixin_t (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default; + hb_iter_fallback_mixin_t& operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default; + hb_iter_fallback_mixin_t& operator = (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default; +}; + +template +struct hb_iter_with_fallback_t : + hb_iter_t, + hb_iter_fallback_mixin_t +{ + protected: + hb_iter_with_fallback_t () = default; + hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) = default; + hb_iter_with_fallback_t (hb_iter_with_fallback_t &&o HB_UNUSED) = default; + hb_iter_with_fallback_t& operator = (const hb_iter_with_fallback_t &o HB_UNUSED) = default; + hb_iter_with_fallback_t& operator = (hb_iter_with_fallback_t &&o HB_UNUSED) = default; +}; + +/* + * Meta-programming predicates. + */ + +/* hb_is_iterator() / hb_is_iterator_of() */ + +template +struct hb_is_iterator_of +{ + template + static hb_true_type impl (hb_priority<2>, hb_iter_t> *); + static hb_false_type impl (hb_priority<0>, const void *); + + public: + static constexpr bool value = decltype (impl (hb_prioritize, hb_declval (Iter*)))::value; +}; +#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of::value +#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t) + +/* hb_is_iterable() */ + +template +struct hb_is_iterable +{ + private: + + template + static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_type ()); + + template + static hb_false_type impl (hb_priority<0>); + + public: + static constexpr bool value = decltype (impl (hb_prioritize))::value; +}; +#define hb_is_iterable(Iterable) hb_is_iterable::value + +/* hb_is_source_of() / hb_is_sink_of() */ + +template +struct hb_is_source_of +{ + private: + template >))> + static hb_true_type impl (hb_priority<2>); + template + static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ()); + static hb_false_type impl (hb_priority<0>); + + public: + static constexpr bool value = decltype (impl (hb_prioritize))::value; +}; +#define hb_is_source_of(Iter, Item) hb_is_source_of::value + +template +struct hb_is_sink_of +{ + private: + template ))> + static hb_true_type impl (hb_priority<2>); + template + static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) << hb_declval (Item), hb_true_type ()); + static hb_false_type impl (hb_priority<0>); + + public: + static constexpr bool value = decltype (impl (hb_prioritize))::value; +}; +#define hb_is_sink_of(Iter, Item) hb_is_sink_of::value + +/* This is commonly used, so define: */ +#define hb_is_sorted_source_of(Iter, Item) \ + (hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator) + + +/* Range-based 'for' for iterables. */ + +template +static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ()) + +template +static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ()) + +/* begin()/end() are NOT looked up non-ADL. So each namespace must declare them. + * Do it for namespace OT. */ +namespace OT { + +template +static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ()) + +template +static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ()) + +} + + +/* + * Adaptors, combiners, etc. + */ + +template +static inline auto +operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (hb_forward (rhs) (hb_forward (lhs))) + +/* hb_map(), hb_filter(), hb_reduce() */ + +enum class hb_function_sortedness_t { + NOT_SORTED, + RETAINS_SORTING, + SORTED, +}; + +template +struct hb_map_iter_t : + hb_iter_t, + decltype (hb_get (hb_declval (Proj), *hb_declval (Iter)))> +{ + hb_map_iter_t (const Iter& it, Proj f_) : it (it), f (f_) {} + + typedef decltype (hb_get (hb_declval (Proj), *hb_declval (Iter))) __item_t__; + static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator; + static constexpr bool is_sorted_iterator = + Sorted == hb_function_sortedness_t::SORTED ? true : + Sorted == hb_function_sortedness_t::RETAINS_SORTING ? Iter::is_sorted_iterator : + false; + __item_t__ __item__ () const { return hb_get (f.get (), *it); } + __item_t__ __item_at__ (unsigned i) const { return hb_get (f.get (), it[i]); } + bool __more__ () const { return bool (it); } + unsigned __len__ () const { return it.len (); } + void __next__ () { ++it; } + void __forward__ (unsigned n) { it += n; } + void __prev__ () { --it; } + void __rewind__ (unsigned n) { it -= n; } + hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); } + bool operator != (const hb_map_iter_t& o) const + { return it != o.it; } + + private: + Iter it; + hb_reference_wrapper f; +}; + +template +struct hb_map_iter_factory_t +{ + hb_map_iter_factory_t (Proj f) : f (f) {} + + template + hb_map_iter_t + operator () (Iter it) + { return hb_map_iter_t (it, f); } + + private: + Proj f; +}; +struct +{ + template + hb_map_iter_factory_t + operator () (Proj&& f) const + { return hb_map_iter_factory_t (f); } +} +HB_FUNCOBJ (hb_map); +struct +{ + template + hb_map_iter_factory_t + operator () (Proj&& f) const + { return hb_map_iter_factory_t (f); } +} +HB_FUNCOBJ (hb_map_retains_sorting); +struct +{ + template + hb_map_iter_factory_t + operator () (Proj&& f) const + { return hb_map_iter_factory_t (f); } +} +HB_FUNCOBJ (hb_map_sorted); + +template +struct hb_filter_iter_t : + hb_iter_with_fallback_t, + typename Iter::item_t> +{ + hb_filter_iter_t (const Iter& it_, Pred p_, Proj f_) : it (it_), p (p_), f (f_) + { while (it && !hb_has (p.get (), hb_get (f.get (), *it))) ++it; } + + typedef typename Iter::item_t __item_t__; + static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator; + __item_t__ __item__ () const { return *it; } + bool __more__ () const { return bool (it); } + void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); } + void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); } + hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); } + bool operator != (const hb_filter_iter_t& o) const + { return it != o.it; } + + private: + Iter it; + hb_reference_wrapper p; + hb_reference_wrapper f; +}; +template +struct hb_filter_iter_factory_t +{ + hb_filter_iter_factory_t (Pred p, Proj f) : p (p), f (f) {} + + template + hb_filter_iter_t + operator () (Iter it) + { return hb_filter_iter_t (it, p, f); } + + private: + Pred p; + Proj f; +}; +struct +{ + template + hb_filter_iter_factory_t + operator () (Pred&& p = hb_identity, Proj&& f = hb_identity) const + { return hb_filter_iter_factory_t (p, f); } +} +HB_FUNCOBJ (hb_filter); + +template +struct hb_reduce_t +{ + hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {} + + template > + AccuT + operator () (Iter it) + { + AccuT value = init_value; + for (; it; ++it) + value = r (value, *it); + return value; + } + + private: + Redu r; + InitT init_value; +}; +struct +{ + template + hb_reduce_t + operator () (Redu&& r, InitT init_value) const + { return hb_reduce_t (r, init_value); } +} +HB_FUNCOBJ (hb_reduce); + + +/* hb_zip() */ - /* Random access: Return true if item_at(), len(), forward() are fast. */ - bool __random_access__ () const { return false; } +template +struct hb_zip_iter_t : + hb_iter_t, + hb_pair_t> +{ + hb_zip_iter_t () {} + hb_zip_iter_t (const A& a, const B& b) : a (a), b (b) {} + + typedef hb_pair_t __item_t__; + static constexpr bool is_random_access_iterator = + A::is_random_access_iterator && + B::is_random_access_iterator; + /* Note. The following categorization is only valid if A is strictly sorted, + * ie. does NOT have duplicates. Previously I tried to categorize sortedness + * more granularly, see commits: + * + * 513762849a683914fc266a17ddf38f133cccf072 + * 4d3cf2adb669c345cc43832d11689271995e160a + * + * However, that was not enough, since hb_sorted_array_t, hb_sorted_vector_t, + * SortedArrayOf, etc all needed to be updated to add more variants. At that + * point I saw it not worth the effort, and instead we now deem all sorted + * collections as essentially strictly-sorted for the purposes of zip. + * + * The above assumption is not as bad as it sounds. Our "sorted" comes with + * no guarantees. It's just a contract, put in place to help you remember, + * and think about, whether an iterator you receive is expected to be + * sorted or not. As such, it's not perfect by definition, and should not + * be treated so. The inaccuracy here just errs in the direction of being + * more permissive, so your code compiles instead of erring on the side of + * marking your zipped iterator unsorted in which case your code won't + * compile. + * + * This semantical limitation does NOT affect logic in any other place I + * know of as of this writing. + */ + static constexpr bool is_sorted_iterator = A::is_sorted_iterator; + + __item_t__ __item__ () const { return __item_t__ (*a, *b); } + __item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); } + bool __more__ () const { return bool (a) && bool (b); } + unsigned __len__ () const { return hb_min (a.len (), b.len ()); } + void __next__ () { ++a; ++b; } + void __forward__ (unsigned n) { a += n; b += n; } + void __prev__ () { --a; --b; } + void __rewind__ (unsigned n) { a -= n; b -= n; } + hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); } + /* Note, we should stop if ANY of the iters reaches end. As such two compare + * unequal if both items are unequal, NOT if either is unequal. */ + bool operator != (const hb_zip_iter_t& o) const + { return a != o.a && b != o.b; } + + private: + A a; + B b; +}; +struct +{ HB_PARTIALIZE(2); + template + hb_zip_iter_t, hb_iter_type> + operator () (A&& a, B&& b) const + { return hb_zip_iter_t, hb_iter_type> (hb_iter (a), hb_iter (b)); } +} +HB_FUNCOBJ (hb_zip); + +/* hb_apply() */ + +template +struct hb_apply_t +{ + hb_apply_t (Appl a) : a (a) {} + + template + void operator () (Iter it) + { + for (; it; ++it) + (void) hb_invoke (a, *it); + } + + private: + Appl a; }; +struct +{ + template hb_apply_t + operator () (Appl&& a) const + { return hb_apply_t (a); } + template hb_apply_t + operator () (Appl *a) const + { return hb_apply_t (*a); } +} +HB_FUNCOBJ (hb_apply); + +/* hb_range()/hb_iota()/hb_repeat() */ + +template +struct hb_range_iter_t : + hb_iter_t, T> +{ + hb_range_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {} + + typedef T __item_t__; + static constexpr bool is_random_access_iterator = true; + static constexpr bool is_sorted_iterator = true; + __item_t__ __item__ () const { return hb_ridentity (v); } + __item_t__ __item_at__ (unsigned j) const { return v + j * step; } + bool __more__ () const { return v != end_; } + unsigned __len__ () const { return !step ? UINT_MAX : (end_ - v) / step; } + void __next__ () { v += step; } + void __forward__ (unsigned n) { v += n * step; } + void __prev__ () { v -= step; } + void __rewind__ (unsigned n) { v -= n * step; } + hb_range_iter_t __end__ () const { return hb_range_iter_t (end_, end_, step); } + bool operator != (const hb_range_iter_t& o) const + { return v != o.v; } + + private: + static inline T end_for (T start, T end_, S step) + { + if (!step) + return end_; + auto res = (end_ - start) % step; + if (!res) + return end_; + end_ += step - res; + return end_; + } + + private: + T v; + T end_; + S step; +}; +struct +{ + template hb_range_iter_t + operator () (T end = (unsigned) -1) const + { return hb_range_iter_t (0, end, 1u); } + + template hb_range_iter_t + operator () (T start, T end, S step = 1u) const + { return hb_range_iter_t (start, end, step); } +} +HB_FUNCOBJ (hb_range); + +template +struct hb_iota_iter_t : + hb_iter_with_fallback_t, T> +{ + hb_iota_iter_t (T start, S step) : v (start), step (step) {} + + private: + + template + auto + inc (hb_type_identity s, hb_priority<1>) + -> hb_void_t (s), hb_declval ()))> + { v = hb_invoke (hb_forward (s), v); } + + void + inc (S s, hb_priority<0>) + { v += s; } + + public: + + typedef T __item_t__; + static constexpr bool is_random_access_iterator = true; + static constexpr bool is_sorted_iterator = true; + __item_t__ __item__ () const { return hb_ridentity (v); } + bool __more__ () const { return true; } + unsigned __len__ () const { return UINT_MAX; } + void __next__ () { inc (step, hb_prioritize); } + void __prev__ () { v -= step; } + hb_iota_iter_t __end__ () const { return *this; } + bool operator != (const hb_iota_iter_t& o) const { return true; } + + private: + T v; + S step; +}; +struct +{ + template hb_iota_iter_t + operator () (T start = 0u, S step = 1u) const + { return hb_iota_iter_t (start, step); } +} +HB_FUNCOBJ (hb_iota); -/* Functions operating on iterators or iteratables. */ +template +struct hb_repeat_iter_t : + hb_iter_t, T> +{ + hb_repeat_iter_t (T value) : v (value) {} + + typedef T __item_t__; + static constexpr bool is_random_access_iterator = true; + static constexpr bool is_sorted_iterator = true; + __item_t__ __item__ () const { return v; } + __item_t__ __item_at__ (unsigned j) const { return v; } + bool __more__ () const { return true; } + unsigned __len__ () const { return UINT_MAX; } + void __next__ () {} + void __forward__ (unsigned) {} + void __prev__ () {} + void __rewind__ (unsigned) {} + hb_repeat_iter_t __end__ () const { return *this; } + bool operator != (const hb_repeat_iter_t& o) const { return true; } + + private: + T v; +}; +struct +{ + template hb_repeat_iter_t + operator () (T value) const + { return hb_repeat_iter_t (value); } +} +HB_FUNCOBJ (hb_repeat); + +/* hb_enumerate()/hb_take() */ + +struct +{ + template + auto operator () (Iterable&& it, Index start = 0u) const HB_AUTO_RETURN + ( hb_zip (hb_iota (start), it) ) +} +HB_FUNCOBJ (hb_enumerate); + +struct +{ HB_PARTIALIZE(2); + template + auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN + ( hb_zip (hb_range (count), it) | hb_map (hb_second) ) + + /* Specialization arrays. */ + + template inline hb_array_t + operator () (hb_array_t array, unsigned count) const + { return array.sub_array (0, count); } + + template inline hb_sorted_array_t + operator () (hb_sorted_array_t array, unsigned count) const + { return array.sub_array (0, count); } +} +HB_FUNCOBJ (hb_take); + +struct +{ HB_PARTIALIZE(2); + template + auto operator () (Iter it, unsigned count) const HB_AUTO_RETURN + ( + + hb_iota (it, hb_add (count)) + | hb_map (hb_take (count)) + | hb_take ((hb_len (it) + count - 1) / count) + ) +} +HB_FUNCOBJ (hb_chop); + +/* hb_sink() */ + +template +struct hb_sink_t +{ + hb_sink_t (Sink s) : s (s) {} + + template + void operator () (Iter it) + { + for (; it; ++it) + s << *it; + } + + private: + Sink s; +}; +struct +{ + template hb_sink_t + operator () (Sink&& s) const + { return hb_sink_t (s); } + + template hb_sink_t + operator () (Sink *s) const + { return hb_sink_t (*s); } +} +HB_FUNCOBJ (hb_sink); + +/* hb-drain: hb_sink to void / blackhole / /dev/null. */ + +struct +{ + template + void operator () (Iter it) const + { + for (; it; ++it) + (void) *it; + } +} +HB_FUNCOBJ (hb_drain); + +/* hb_unzip(): unzip and sink to two sinks. */ + +template +struct hb_unzip_t +{ + hb_unzip_t (Sink1 s1, Sink2 s2) : s1 (s1), s2 (s2) {} + + template + void operator () (Iter it) + { + for (; it; ++it) + { + const auto &v = *it; + s1 << v.first; + s2 << v.second; + } + } + + private: + Sink1 s1; + Sink2 s2; +}; +struct +{ + template hb_unzip_t + operator () (Sink1&& s1, Sink2&& s2) const + { return hb_unzip_t (s1, s2); } + + template hb_unzip_t + operator () (Sink1 *s1, Sink2 *s2) const + { return hb_unzip_t (*s1, *s2); } +} +HB_FUNCOBJ (hb_unzip); + + +/* hb-all, hb-any, hb-none. */ + +struct +{ + template + bool operator () (Iterable&& c, + Pred&& p = hb_identity, + Proj&& f = hb_identity) const + { + for (auto it = hb_iter (c); it; ++it) + if (!hb_match (hb_forward (p), hb_get (hb_forward (f), *it))) + return false; + return true; + } +} +HB_FUNCOBJ (hb_all); +struct +{ + template + bool operator () (Iterable&& c, + Pred&& p = hb_identity, + Proj&& f = hb_identity) const + { + for (auto it = hb_iter (c); it; ++it) + if (hb_match (hb_forward (p), hb_get (hb_forward (f), *it))) + return true; + return false; + } +} +HB_FUNCOBJ (hb_any); +struct +{ + template + bool operator () (Iterable&& c, + Pred&& p = hb_identity, + Proj&& f = hb_identity) const + { + for (auto it = hb_iter (c); it; ++it) + if (hb_match (hb_forward (p), hb_get (hb_forward (f), *it))) + return false; + return true; + } +} +HB_FUNCOBJ (hb_none); + +/* + * Algorithms operating on iterators. + */ -template inline void -hb_fill (const C& c, const V &v) +template +inline void +hb_fill (C& c, const V &v) { - for (typename C::iter_t i (c); i; i++) - hb_assign (*i, v); + for (auto i = hb_iter (c); i; i++) + *i = v; } -template inline bool -hb_copy (hb_iter_t &id, hb_iter_t &is) +template +inline void +hb_copy (S&& is, D&& id) { - for (; id && is; ++id, ++is) - *id = *is; - return !is; + hb_iter (is) | hb_sink (id); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh index 43d70d7f221..42e54936410 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-kern.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-kern.hh @@ -52,8 +52,7 @@ struct hb_kern_machine_t OT::hb_ot_apply_context_t c (1, font, buffer); c.set_lookup_mask (kern_mask); c.set_lookup_props (OT::LookupFlag::IgnoreMarks); - OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input; - skippy_iter.init (&c); + auto &skippy_iter = c.iter_input; bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction); unsigned int count = buffer->len; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh index 2ae288494f4..0c820e7429f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh @@ -32,30 +32,15 @@ #include "hb.hh" #include "hb-blob.hh" -#include "hb-array.hh" -#include "hb-vector.hh" +#include "hb-dispatch.hh" +#include "hb-sanitize.hh" +#include "hb-serialize.hh" /* * Casts */ -/* Cast to struct T, reference to reference */ -template -static inline const Type& CastR(const TObject &X) -{ return reinterpret_cast (X); } -template -static inline Type& CastR(TObject &X) -{ return reinterpret_cast (X); } - -/* Cast to struct T, pointer to pointer */ -template -static inline const Type* CastP(const TObject *X) -{ return reinterpret_cast (X); } -template -static inline Type* CastP(TObject *X) -{ return reinterpret_cast (X); } - /* StructAtOffset(P,Ofs) returns the struct T& that is placed at memory * location pointed to by P plus Ofs bytes. */ template @@ -69,7 +54,7 @@ static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int of { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" - return * reinterpret_cast ((char *) P + offset); + return * reinterpret_cast ((const char *) P + offset); #pragma GCC diagnostic pop } template @@ -134,7 +119,7 @@ static inline Type& StructAfter(TObject &X) #define DEFINE_SIZE_ARRAY(size, array) \ DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \ - DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof ((array)[0])) \ + DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + (HB_VAR_ARRAY+0) * sizeof ((array)[0])) \ static constexpr unsigned null_size = (size); \ static constexpr unsigned min_size = (size) @@ -143,615 +128,6 @@ static inline Type& StructAfter(TObject &X) DEFINE_SIZE_ARRAY(size, array) -/* - * Dispatch - */ - -template -struct hb_dispatch_context_t -{ - static constexpr unsigned max_debug_depth = MaxDebugDepth; - typedef Return return_t; - template - bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; } - static return_t no_dispatch_return_value () { return Context::default_return_value (); } - static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; } -}; - - -/* - * Sanitize - * - * - * === Introduction === - * - * The sanitize machinery is at the core of our zero-cost font loading. We - * mmap() font file into memory and create a blob out of it. Font subtables - * are returned as a readonly sub-blob of the main font blob. These table - * blobs are then sanitized before use, to ensure invalid memory access does - * not happen. The toplevel sanitize API use is like, eg. to load the 'head' - * table: - * - * hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table (face); - * - * The blob then can be converted to a head table struct with: - * - * const head *head_table = head_blob->as (); - * - * What the reference_table does is, to call hb_face_reference_table() to load - * the table blob, sanitize it and return either the sanitized blob, or empty - * blob if sanitization failed. The blob->as() function returns the null - * object of its template type argument if the blob is empty. Otherwise, it - * just casts the blob contents to the desired type. - * - * Sanitizing a blob of data with a type T works as follows (with minor - * simplification): - * - * - Cast blob content to T*, call sanitize() method of it, - * - If sanitize succeeded, return blob. - * - Otherwise, if blob is not writable, try making it writable, - * or copy if cannot be made writable in-place, - * - Call sanitize() again. Return blob if sanitize succeeded. - * - Return empty blob otherwise. - * - * - * === The sanitize() contract === - * - * The sanitize() method of each object type shall return true if it's safe to - * call other methods of the object, and false otherwise. - * - * Note that what sanitize() checks for might align with what the specification - * describes as valid table data, but does not have to be. In particular, we - * do NOT want to be pedantic and concern ourselves with validity checks that - * are irrelevant to our use of the table. On the contrary, we want to be - * lenient with error handling and accept invalid data to the extent that it - * does not impose extra burden on us. - * - * Based on the sanitize contract, one can see that what we check for depends - * on how we use the data in other table methods. Ie. if other table methods - * assume that offsets do NOT point out of the table data block, then that's - * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way). On - * the other hand, if other methods do such checks themselves, then sanitize() - * does not have to bother with them (glyf/local work this way). The choice - * depends on the table structure and sanitize() performance. For example, to - * check glyf/loca offsets in sanitize() would cost O(num-glyphs). We try hard - * to avoid such costs during font loading. By postponing such checks to the - * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime - * cost to O(used-glyphs). As such, this is preferred. - * - * The same argument can be made re GSUB/GPOS/GDEF, but there, the table - * structure is so complicated that by checking all offsets at sanitize() time, - * we make the code much simpler in other methods, as offsets and referenced - * objects do not need to be validated at each use site. - */ - -/* This limits sanitizing time on really broken fonts. */ -#ifndef HB_SANITIZE_MAX_EDITS -#define HB_SANITIZE_MAX_EDITS 32 -#endif -#ifndef HB_SANITIZE_MAX_OPS_FACTOR -#define HB_SANITIZE_MAX_OPS_FACTOR 8 -#endif -#ifndef HB_SANITIZE_MAX_OPS_MIN -#define HB_SANITIZE_MAX_OPS_MIN 16384 -#endif -#ifndef HB_SANITIZE_MAX_OPS_MAX -#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF -#endif - -struct hb_sanitize_context_t : - hb_dispatch_context_t -{ - hb_sanitize_context_t () : - debug_depth (0), - start (nullptr), end (nullptr), - max_ops (0), - writable (false), edit_count (0), - blob (nullptr), - num_glyphs (65536), - num_glyphs_set (false) {} - - const char *get_name () { return "SANITIZE"; } - template - bool may_dispatch (const T *obj HB_UNUSED, const F *format) - { return format->sanitize (this); } - template - return_t dispatch (const T &obj) { return obj.sanitize (this); } - static return_t default_return_value () { return true; } - static return_t no_dispatch_return_value () { return false; } - bool stop_sublookup_iteration (const return_t r) const { return !r; } - - void init (hb_blob_t *b) - { - this->blob = hb_blob_reference (b); - this->writable = false; - } - - void set_num_glyphs (unsigned int num_glyphs_) - { - num_glyphs = num_glyphs_; - num_glyphs_set = true; - } - unsigned int get_num_glyphs () { return num_glyphs; } - - void set_max_ops (int max_ops_) { max_ops = max_ops_; } - - template - void set_object (const T *obj) - { - reset_object (); - - if (!obj) return; - - const char *obj_start = (const char *) obj; - if (unlikely (obj_start < this->start || this->end <= obj_start)) - this->start = this->end = nullptr; - else - { - this->start = obj_start; - this->end = obj_start + MIN (this->end - obj_start, obj->get_size ()); - } - } - - void reset_object () - { - this->start = this->blob->data; - this->end = this->start + this->blob->length; - assert (this->start <= this->end); /* Must not overflow. */ - } - - void start_processing () - { - reset_object (); - this->max_ops = MAX ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR, - (unsigned) HB_SANITIZE_MAX_OPS_MIN); - this->edit_count = 0; - this->debug_depth = 0; - - DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1, - "start [%p..%p] (%lu bytes)", - this->start, this->end, - (unsigned long) (this->end - this->start)); - } - - void end_processing () - { - DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1, - "end [%p..%p] %u edit requests", - this->start, this->end, this->edit_count); - - hb_blob_destroy (this->blob); - this->blob = nullptr; - this->start = this->end = nullptr; - } - - bool check_range (const void *base, - unsigned int len) const - { - const char *p = (const char *) base; - bool ok = this->start <= p && - p <= this->end && - (unsigned int) (this->end - p) >= len && - this->max_ops-- > 0; - - DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, - "check_range [%p..%p] (%d bytes) in [%p..%p] -> %s", - p, p + len, len, - this->start, this->end, - ok ? "OK" : "OUT-OF-RANGE"); - - return likely (ok); - } - - template - bool check_range (const T *base, - unsigned int a, - unsigned int b) const - { - return !hb_unsigned_mul_overflows (a, b) && - this->check_range (base, a * b); - } - - template - bool check_range (const T *base, - unsigned int a, - unsigned int b, - unsigned int c) const - { - return !hb_unsigned_mul_overflows (a, b) && - this->check_range (base, a * b, c); - } - - template - bool check_array (const T *base, unsigned int len) const - { - return this->check_range (base, len, hb_static_size (T)); - } - - template - bool check_array (const T *base, - unsigned int a, - unsigned int b) const - { - return this->check_range (base, a, b, hb_static_size (T)); - } - - template - bool check_struct (const Type *obj) const - { return likely (this->check_range (obj, obj->min_size)); } - - bool may_edit (const void *base, unsigned int len) - { - if (this->edit_count >= HB_SANITIZE_MAX_EDITS) - return false; - - const char *p = (const char *) base; - this->edit_count++; - - DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, - "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", - this->edit_count, - p, p + len, len, - this->start, this->end, - this->writable ? "GRANTED" : "DENIED"); - - return this->writable; - } - - template - bool try_set (const Type *obj, const ValueType &v) - { - if (this->may_edit (obj, hb_static_size (Type))) - { - hb_assign (* const_cast (obj), v); - return true; - } - return false; - } - - template - hb_blob_t *sanitize_blob (hb_blob_t *blob) - { - bool sane; - - init (blob); - - retry: - DEBUG_MSG_FUNC (SANITIZE, start, "start"); - - start_processing (); - - if (unlikely (!start)) - { - end_processing (); - return blob; - } - - Type *t = CastP (const_cast (start)); - - sane = t->sanitize (this); - if (sane) - { - if (edit_count) - { - DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count); - - /* sanitize again to ensure no toe-stepping */ - edit_count = 0; - sane = t->sanitize (this); - if (edit_count) { - DEBUG_MSG_FUNC (SANITIZE, start, "requested %d edits in second round; FAILLING", edit_count); - sane = false; - } - } - } - else - { - if (edit_count && !writable) { - start = hb_blob_get_data_writable (blob, nullptr); - end = start + blob->length; - - if (start) - { - writable = true; - /* ok, we made it writable by relocating. try again */ - DEBUG_MSG_FUNC (SANITIZE, start, "retry"); - goto retry; - } - } - } - - end_processing (); - - DEBUG_MSG_FUNC (SANITIZE, start, sane ? "PASSED" : "FAILED"); - if (sane) - { - hb_blob_make_immutable (blob); - return blob; - } - else - { - hb_blob_destroy (blob); - return hb_blob_get_empty (); - } - } - - template - hb_blob_t *reference_table (const hb_face_t *face, hb_tag_t tableTag = Type::tableTag) - { - if (!num_glyphs_set) - set_num_glyphs (hb_face_get_glyph_count (face)); - return sanitize_blob (hb_face_reference_table (face, tableTag)); - } - - mutable unsigned int debug_depth; - const char *start, *end; - mutable int max_ops; - private: - bool writable; - unsigned int edit_count; - hb_blob_t *blob; - unsigned int num_glyphs; - bool num_glyphs_set; -}; - -struct hb_sanitize_with_object_t -{ - template - hb_sanitize_with_object_t (hb_sanitize_context_t *c, - const T& obj) : c (c) - { c->set_object (obj); } - ~hb_sanitize_with_object_t () - { c->reset_object (); } - - private: - hb_sanitize_context_t *c; -}; - - -/* - * Serialize - */ - -struct hb_serialize_context_t -{ - hb_serialize_context_t (void *start_, unsigned int size) - { - this->start = (char *) start_; - this->end = this->start + size; - reset (); - } - - bool in_error () const { return !this->successful; } - - void reset () - { - this->successful = true; - this->head = this->start; - this->debug_depth = 0; - } - - bool propagate_error (bool e) - { return this->successful = this->successful && e; } - template bool propagate_error (const T &obj) - { return this->successful = this->successful && !obj.in_error (); } - template bool propagate_error (const T *obj) - { return this->successful = this->successful && !obj->in_error (); } - template bool propagate_error (T1 &o1, T2 &o2) - { return propagate_error (o1) && propagate_error (o2); } - template bool propagate_error (T1 *o1, T2 *o2) - { return propagate_error (o1) && propagate_error (o2); } - template - bool propagate_error (T1 &o1, T2 &o2, T3 &o3) - { return propagate_error (o1) && propagate_error (o2, o3); } - template - bool propagate_error (T1 *o1, T2 *o2, T3 *o3) - { return propagate_error (o1) && propagate_error (o2, o3); } - - /* To be called around main operation. */ - template - Type *start_serialize () - { - DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1, - "start [%p..%p] (%lu bytes)", - this->start, this->end, - (unsigned long) (this->end - this->start)); - - return start_embed (); - } - void end_serialize () - { - DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1, - "end [%p..%p] serialized %d bytes; %s", - this->start, this->end, - (int) (this->head - this->start), - this->successful ? "successful" : "UNSUCCESSFUL"); - } - - unsigned int length () const { return this->head - this->start; } - - void align (unsigned int alignment) - { - unsigned int l = length () % alignment; - if (l) - allocate_size (alignment - l); - } - - template - Type *start_embed (const Type *_ HB_UNUSED = nullptr) const - { - Type *ret = reinterpret_cast (this->head); - return ret; - } - - template - Type *allocate_size (unsigned int size) - { - if (unlikely (!this->successful || this->end - this->head < ptrdiff_t (size))) { - this->successful = false; - return nullptr; - } - memset (this->head, 0, size); - char *ret = this->head; - this->head += size; - return reinterpret_cast (ret); - } - - template - Type *allocate_min () - { - return this->allocate_size (Type::min_size); - } - - template - Type *embed (const Type &obj) - { - unsigned int size = obj.get_size (); - Type *ret = this->allocate_size (size); - if (unlikely (!ret)) return nullptr; - memcpy (ret, &obj, size); - return ret; - } - template - hb_serialize_context_t &operator << (const Type &obj) { embed (obj); return *this; } - - template - Type *extend_size (Type &obj, unsigned int size) - { - assert (this->start <= (char *) &obj); - assert ((char *) &obj <= this->head); - assert ((char *) &obj + size >= this->head); - if (unlikely (!this->allocate_size (((char *) &obj) + size - this->head))) return nullptr; - return reinterpret_cast (&obj); - } - - template - Type *extend_min (Type &obj) { return extend_size (obj, obj.min_size); } - - template - Type *extend (Type &obj) { return extend_size (obj, obj.get_size ()); } - - /* Output routines. */ - template - Type *copy () const - { - assert (this->successful); - unsigned int len = this->head - this->start; - void *p = malloc (len); - if (p) - memcpy (p, this->start, len); - return reinterpret_cast (p); - } - hb_bytes_t copy_bytes () const - { - assert (this->successful); - unsigned int len = this->head - this->start; - void *p = malloc (len); - if (p) - memcpy (p, this->start, len); - else - return hb_bytes_t (); - return hb_bytes_t ((char *) p, len); - } - hb_blob_t *copy_blob () const - { - assert (this->successful); - return hb_blob_create (this->start, - this->head - this->start, - HB_MEMORY_MODE_DUPLICATE, - nullptr, nullptr); - } - - public: - unsigned int debug_depth; - char *start, *end, *head; - bool successful; -}; - - - -/* - * Big-endian integers. - */ - -template struct BEInt; - -template -struct BEInt -{ - public: - void set (Type V) { v = V; } - operator Type () const { return v; } - private: uint8_t v; -}; -template -struct BEInt -{ - public: - void set (Type V) - { - v[0] = (V >> 8) & 0xFF; - v[1] = (V ) & 0xFF; - } - operator Type () const - { -#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ - defined(__BYTE_ORDER) && \ - (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) - /* Spoon-feed the compiler a big-endian integer with alignment 1. - * https://github.com/harfbuzz/harfbuzz/pull/1398 */ - struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; -#if __BYTE_ORDER == __LITTLE_ENDIAN - return __builtin_bswap16 (((packed_uint16_t *) this)->v); -#else /* __BYTE_ORDER == __BIG_ENDIAN */ - return ((packed_uint16_t *) this)->v; -#endif -#endif - return (v[0] << 8) - + (v[1] ); - } - private: uint8_t v[2]; -}; -template -struct BEInt -{ - public: - void set (Type V) - { - v[0] = (V >> 16) & 0xFF; - v[1] = (V >> 8) & 0xFF; - v[2] = (V ) & 0xFF; - } - operator Type () const - { - return (v[0] << 16) - + (v[1] << 8) - + (v[2] ); - } - private: uint8_t v[3]; -}; -template -struct BEInt -{ - public: - typedef Type type; - void set (Type V) - { - v[0] = (V >> 24) & 0xFF; - v[1] = (V >> 16) & 0xFF; - v[2] = (V >> 8) & 0xFF; - v[3] = (V ) & 0xFF; - } - operator Type () const - { - return (v[0] << 24) - + (v[1] << 16) - + (v[2] << 8) - + (v[3] ); - } - private: uint8_t v[4]; -}; - /* * Lazy loaders. @@ -814,7 +190,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t const Returned * operator -> () const { return get (); } const Returned & operator * () const { return *get (); } - explicit_operator bool () const + explicit operator bool () const { return get_stored () != Funcs::get_null (); } template operator const C * () const { return get (); } @@ -858,7 +234,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t static Returned* convert (Stored *p) { return p; } /* By default null/init/fini the object. */ - static const Stored* get_null () { return &Null(Stored); } + static const Stored* get_null () { return &Null (Stored); } static Stored *create (Data *data) { Stored *p = (Stored *) calloc (1, sizeof (Stored)); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-map.cc index 3fccfa0fa01..114efcb3d75 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-map.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-map.cc @@ -69,7 +69,7 @@ hb_map_create () hb_map_t * hb_map_get_empty () { - return const_cast (&Null(hb_map_t)); + return const_cast (&Null (hb_map_t)); } /** diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-map.hh index c04a8dff966..a5c997c32e8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-map.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-map.hh @@ -30,31 +30,36 @@ #include "hb.hh" -template -inline uint32_t Hash (const T &v) -{ - /* Knuth's multiplicative method: */ - return (uint32_t) v * 2654435761u; -} - - /* - * hb_map_t + * hb_hashmap_t */ -struct hb_map_t +template +struct hb_hashmap_t { - HB_NO_COPY_ASSIGN (hb_map_t); - hb_map_t () { init (); } - ~hb_map_t () { fini (); } + HB_DELETE_COPY_ASSIGN (hb_hashmap_t); + hb_hashmap_t () { init (); } + ~hb_hashmap_t () { fini (); } + + static_assert (hb_is_integral (K) || hb_is_pointer (K), ""); + static_assert (hb_is_integral (V) || hb_is_pointer (V), ""); struct item_t { - hb_codepoint_t key; - hb_codepoint_t value; - - bool is_unused () const { return key == INVALID; } - bool is_tombstone () const { return key != INVALID && value == INVALID; } + K key; + V value; + uint32_t hash; + + void clear () { key = kINVALID; value = vINVALID; hash = 0; } + + bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); } + bool operator == (const item_t &o) { return *this == o.key; } + bool is_unused () const { return key == kINVALID; } + bool is_tombstone () const { return key != kINVALID && value == vINVALID; } + bool is_real () const { return key != kINVALID && value != vINVALID; } + hb_pair_t get_pair() const { return hb_pair_t (key, value); } }; hb_object_header_t header; @@ -82,14 +87,22 @@ struct hb_map_t { free (items); items = nullptr; + population = occupancy = 0; } void fini () { - population = occupancy = 0; hb_object_fini (this); fini_shallow (); } + void reset () + { + if (unlikely (hb_object_is_immutable (this))) + return; + successful = true; + clear (); + } + bool in_error () const { return !successful; } bool resize () @@ -104,7 +117,8 @@ struct hb_map_t successful = false; return false; } - memset (new_items, 0xFF, (size_t) new_size * sizeof (item_t)); + for (auto &_ : hb_iter (new_items, new_size)) + _.clear (); unsigned int old_size = mask + 1; item_t *old_items = items; @@ -118,22 +132,96 @@ struct hb_map_t /* Insert back old items. */ if (old_items) for (unsigned int i = 0; i < old_size; i++) - if (old_items[i].key != INVALID && old_items[i].value != INVALID) - set (old_items[i].key, old_items[i].value); + if (old_items[i].is_real ()) + set_with_hash (old_items[i].key, + old_items[i].hash, + old_items[i].value); free (old_items); return true; } - void set (hb_codepoint_t key, hb_codepoint_t value) + void set (K key, V value) + { + set_with_hash (key, hb_hash (key), value); + } + + V get (K key) const + { + if (unlikely (!items)) return vINVALID; + unsigned int i = bucket_for (key); + return items[i].is_real () && items[i] == key ? items[i].value : vINVALID; + } + + void del (K key) { set (key, vINVALID); } + + /* Has interface. */ + static constexpr V SENTINEL = vINVALID; + typedef V value_t; + value_t operator [] (K k) const { return get (k); } + bool has (K k, V *vp = nullptr) const + { + V v = (*this)[k]; + if (vp) *vp = v; + return v != SENTINEL; + } + /* Projection. */ + V operator () (K k) const { return get (k); } + + void clear () + { + if (unlikely (hb_object_is_immutable (this))) + return; + if (items) + for (auto &_ : hb_iter (items, mask + 1)) + _.clear (); + + population = occupancy = 0; + } + + bool is_empty () const { return population == 0; } + + unsigned int get_population () const { return population; } + + /* + * Iterator + */ + auto iter () const HB_AUTO_RETURN + ( + + hb_array (items, mask ? mask + 1 : 0) + | hb_filter (&item_t::is_real) + | hb_map (&item_t::get_pair) + ) + auto keys () const HB_AUTO_RETURN + ( + + hb_array (items, mask ? mask + 1 : 0) + | hb_filter (&item_t::is_real) + | hb_map (&item_t::key) + | hb_map (hb_ridentity) + ) + auto values () const HB_AUTO_RETURN + ( + + hb_array (items, mask ? mask + 1 : 0) + | hb_filter (&item_t::is_real) + | hb_map (&item_t::value) + | hb_map (hb_ridentity) + ) + + /* Sink interface. */ + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (v.first, v.second); return *this; } + + protected: + + void set_with_hash (K key, uint32_t hash, V value) { if (unlikely (!successful)) return; - if (unlikely (key == INVALID)) return; + if (unlikely (key == kINVALID)) return; if ((occupancy + occupancy / 2) >= mask && !resize ()) return; - unsigned int i = bucket_for (key); + unsigned int i = bucket_for_hash (key, hash); - if (value == INVALID && items[i].key != key) + if (value == vINVALID && items[i].key != key) return; /* Trying to delete non-existent key. */ if (!items[i].is_unused ()) @@ -145,55 +233,32 @@ struct hb_map_t items[i].key = key; items[i].value = value; + items[i].hash = hash; occupancy++; if (!items[i].is_tombstone ()) population++; - - } - hb_codepoint_t get (hb_codepoint_t key) const - { - if (unlikely (!items)) return INVALID; - unsigned int i = bucket_for (key); - return items[i].key == key ? items[i].value : INVALID; } - void del (hb_codepoint_t key) { set (key, INVALID); } - - bool has (hb_codepoint_t key) const - { return get (key) != INVALID; } - - hb_codepoint_t operator [] (unsigned int key) const - { return get (key); } - - static constexpr hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID; - - void clear () + unsigned int bucket_for (K key) const { - memset (items, 0xFF, ((size_t) mask + 1) * sizeof (item_t)); - population = occupancy = 0; + return bucket_for_hash (key, hb_hash (key)); } - bool is_empty () const { return population == 0; } - - unsigned int get_population () const { return population; } - - protected: - - unsigned int bucket_for (hb_codepoint_t key) const + unsigned int bucket_for_hash (K key, uint32_t hash) const { - unsigned int i = Hash (key) % prime; + unsigned int i = hash % prime; unsigned int step = 0; - unsigned int tombstone = INVALID; + unsigned int tombstone = (unsigned) -1; while (!items[i].is_unused ()) { - if (items[i].key == key) + if (items[i].hash == hash && items[i] == key) return i; - if (tombstone == INVALID && items[i].is_tombstone ()) + if (tombstone == (unsigned) -1 && items[i].is_tombstone ()) tombstone = i; i = (i + ++step) & mask; } - return tombstone == INVALID ? i : tombstone; + return tombstone == (unsigned) -1 ? i : tombstone; } static unsigned int prime_for (unsigned int shift) @@ -248,5 +313,14 @@ struct hb_map_t } }; +/* + * hb_map_t + */ + +struct hb_map_t : hb_hashmap_t {}; + #endif /* HB_MAP_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-meta.hh b/src/java.desktop/share/native/libharfbuzz/hb-meta.hh new file mode 100644 index 00000000000..ea64416f0d2 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-meta.hh @@ -0,0 +1,410 @@ +/* + * Copyright © 2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_META_HH +#define HB_META_HH + +#include "hb.hh" + + +/* + * C++ template meta-programming & fundamentals used with them. + */ + +/* Void! For when we need a expression-type of void. */ +struct hb_empty_t {}; + +/* https://en.cppreference.com/w/cpp/types/void_t */ +template struct _hb_void_t { typedef void type; }; +template using hb_void_t = typename _hb_void_t::type; + +template struct _hb_head_t { typedef Head type; }; +template using hb_head_t = typename _hb_head_t::type; + +template struct hb_integral_constant { static constexpr T value = v; }; +template using hb_bool_constant = hb_integral_constant; +using hb_true_type = hb_bool_constant; +using hb_false_type = hb_bool_constant; + + +/* Basic type SFINAE. */ + +template struct hb_enable_if {}; +template struct hb_enable_if { typedef T type; }; +#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type* = nullptr +/* Concepts/Requires alias: */ +#define hb_requires(Cond) hb_enable_if((Cond)) + +template struct hb_is_same : hb_false_type {}; +template struct hb_is_same : hb_true_type {}; +#define hb_is_same(T, T2) hb_is_same::value + +/* Function overloading SFINAE and priority. */ + +#define HB_RETURN(Ret, E) -> hb_head_t { return (E); } +#define HB_AUTO_RETURN(E) -> decltype ((E)) { return (E); } +#define HB_VOID_RETURN(E) -> hb_void_t { (E); } + +template struct hb_priority : hb_priority {}; +template <> struct hb_priority<0> {}; +#define hb_prioritize hb_priority<16> () + +#define HB_FUNCOBJ(x) static_const x HB_UNUSED + + +template struct hb_type_identity_t { typedef T type; }; +template using hb_type_identity = typename hb_type_identity_t::type; + +struct +{ + template constexpr T* + operator () (T& arg) const + { +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-align" + /* https://en.cppreference.com/w/cpp/memory/addressof */ + return reinterpret_cast ( + &const_cast ( + reinterpret_cast (arg))); +#pragma GCC diagnostic pop + } +} +HB_FUNCOBJ (hb_addressof); + +template static inline T hb_declval (); +#define hb_declval(T) (hb_declval ()) + +template struct hb_match_const : hb_type_identity_t, hb_bool_constant{}; +template struct hb_match_const : hb_type_identity_t, hb_bool_constant {}; +template using hb_remove_const = typename hb_match_const::type; +template using hb_add_const = const T; +#define hb_is_const(T) hb_match_const::value +template struct hb_match_reference : hb_type_identity_t, hb_bool_constant{}; +template struct hb_match_reference : hb_type_identity_t, hb_bool_constant {}; +template struct hb_match_reference : hb_type_identity_t, hb_bool_constant {}; +template using hb_remove_reference = typename hb_match_reference::type; +template auto _hb_try_add_lvalue_reference (hb_priority<1>) -> hb_type_identity; +template auto _hb_try_add_lvalue_reference (hb_priority<0>) -> hb_type_identity; +template using hb_add_lvalue_reference = decltype (_hb_try_add_lvalue_reference (hb_prioritize)); +template auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity; +template auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity; +template using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference (hb_prioritize)); +#define hb_is_reference(T) hb_match_reference::value +template struct hb_match_pointer : hb_type_identity_t, hb_bool_constant{}; +template struct hb_match_pointer : hb_type_identity_t, hb_bool_constant {}; +template using hb_remove_pointer = typename hb_match_pointer::type; +template auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity*>; +template auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity; +template using hb_add_pointer = decltype (_hb_try_add_pointer (hb_prioritize)); +#define hb_is_pointer(T) hb_match_pointer::value + + +/* TODO Add feature-parity to std::decay. */ +template using hb_decay = hb_remove_const>; + + +template +struct _hb_conditional { typedef T type; }; +template +struct _hb_conditional { typedef F type; }; +template +using hb_conditional = typename _hb_conditional::type; + + +template +struct hb_is_convertible +{ + private: + static constexpr bool from_void = hb_is_same (void, hb_decay); + static constexpr bool to_void = hb_is_same (void, hb_decay ); + static constexpr bool either_void = from_void || to_void; + static constexpr bool both_void = from_void && to_void; + + static hb_true_type impl2 (hb_conditional); + + template + static auto impl (hb_priority<1>) -> decltype (impl2 (hb_declval (T))); + template + static hb_false_type impl (hb_priority<0>); + public: + static constexpr bool value = both_void || + (!either_void && + decltype (impl> (hb_prioritize))::value); +}; +#define hb_is_convertible(From,To) hb_is_convertible::value + +template +using hb_is_base_of = hb_is_convertible *, hb_decay *>; +#define hb_is_base_of(Base,Derived) hb_is_base_of::value + +template +using hb_is_cr_convertible = hb_bool_constant< + hb_is_same (hb_decay, hb_decay) && + (!hb_is_const (From) || hb_is_const (To)) && + (!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To)) +>; +#define hb_is_cr_convertible(From,To) hb_is_cr_convertible::value + +/* std::move and std::forward */ + +template +static constexpr hb_remove_reference&& hb_move (T&& t) { return (hb_remove_reference&&) (t); } + +template +static constexpr T&& hb_forward (hb_remove_reference& t) { return (T&&) t; } +template +static constexpr T&& hb_forward (hb_remove_reference&& t) { return (T&&) t; } + +struct +{ + template constexpr auto + operator () (T&& v) const HB_AUTO_RETURN (hb_forward (v)) + + template constexpr auto + operator () (T *v) const HB_AUTO_RETURN (*v) +} +HB_FUNCOBJ (hb_deref); + +struct +{ + template constexpr auto + operator () (T&& v) const HB_AUTO_RETURN (hb_forward (v)) + + template constexpr auto + operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v)) +} +HB_FUNCOBJ (hb_ref); + +template +struct hb_reference_wrapper +{ + hb_reference_wrapper (T v) : v (v) {} + bool operator == (const hb_reference_wrapper& o) const { return v == o.v; } + bool operator != (const hb_reference_wrapper& o) const { return v != o.v; } + operator T () const { return v; } + T get () const { return v; } + T v; +}; +template +struct hb_reference_wrapper +{ + hb_reference_wrapper (T& v) : v (hb_addressof (v)) {} + bool operator == (const hb_reference_wrapper& o) const { return v == o.v; } + bool operator != (const hb_reference_wrapper& o) const { return v != o.v; } + operator T& () const { return *v; } + T& get () const { return *v; } + T* v; +}; + + +template +using hb_is_integral = hb_bool_constant< + hb_is_same (hb_decay, char) || + hb_is_same (hb_decay, signed char) || + hb_is_same (hb_decay, unsigned char) || + hb_is_same (hb_decay, signed int) || + hb_is_same (hb_decay, unsigned int) || + hb_is_same (hb_decay, signed short) || + hb_is_same (hb_decay, unsigned short) || + hb_is_same (hb_decay, signed long) || + hb_is_same (hb_decay, unsigned long) || + hb_is_same (hb_decay, signed long long) || + hb_is_same (hb_decay, unsigned long long) || + false +>; +#define hb_is_integral(T) hb_is_integral::value +template +using hb_is_floating_point = hb_bool_constant< + hb_is_same (hb_decay, float) || + hb_is_same (hb_decay, double) || + hb_is_same (hb_decay, long double) || + false +>; +#define hb_is_floating_point(T) hb_is_floating_point::value +template +using hb_is_arithmetic = hb_bool_constant< + hb_is_integral (T) || + hb_is_floating_point (T) || + false +>; +#define hb_is_arithmetic(T) hb_is_arithmetic::value + + +template +using hb_is_signed = hb_conditional, + hb_false_type>; +#define hb_is_signed(T) hb_is_signed::value +template +using hb_is_unsigned = hb_conditional, + hb_false_type>; +#define hb_is_unsigned(T) hb_is_unsigned::value + +template struct hb_int_min; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +template <> struct hb_int_min : hb_integral_constant {}; +#define hb_int_min(T) hb_int_min::value +template struct hb_int_max; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +template <> struct hb_int_max : hb_integral_constant {}; +#define hb_int_max(T) hb_int_max::value + + + +template +struct _hb_is_destructible : hb_false_type {}; +template +struct _hb_is_destructible> : hb_true_type {}; +template +using hb_is_destructible = _hb_is_destructible; +#define hb_is_destructible(T) hb_is_destructible::value + +template +struct _hb_is_constructible : hb_false_type {}; +template +struct _hb_is_constructible, Ts...> : hb_true_type {}; +template +using hb_is_constructible = _hb_is_constructible; +#define hb_is_constructible(...) hb_is_constructible<__VA_ARGS__>::value + +template +using hb_is_default_constructible = hb_is_constructible; +#define hb_is_default_constructible(T) hb_is_default_constructible::value + +template +using hb_is_copy_constructible = hb_is_constructible>>; +#define hb_is_copy_constructible(T) hb_is_copy_constructible::value + +template +using hb_is_move_constructible = hb_is_constructible>>; +#define hb_is_move_constructible(T) hb_is_move_constructible::value + +template +struct _hb_is_assignable : hb_false_type {}; +template +struct _hb_is_assignable> : hb_true_type {}; +template +using hb_is_assignable = _hb_is_assignable; +#define hb_is_assignable(T,U) hb_is_assignable::value + +template +using hb_is_copy_assignable = hb_is_assignable, + hb_add_lvalue_reference>>; +#define hb_is_copy_assignable(T) hb_is_copy_assignable::value + +template +using hb_is_move_assignable = hb_is_assignable, + hb_add_rvalue_reference>; +#define hb_is_move_assignable(T) hb_is_move_assignable::value + +/* Trivial versions. */ + +template union hb_trivial { T value; }; + +template +using hb_is_trivially_destructible= hb_is_destructible>; +#define hb_is_trivially_destructible(T) hb_is_trivially_destructible::value + +/* Don't know how to do the following. */ +//template +//using hb_is_trivially_constructible= hb_is_constructible, hb_trivial...>; +//#define hb_is_trivially_constructible(...) hb_is_trivially_constructible<__VA_ARGS__>::value + +template +using hb_is_trivially_default_constructible= hb_is_default_constructible>; +#define hb_is_trivially_default_constructible(T) hb_is_trivially_default_constructible::value + +template +using hb_is_trivially_copy_constructible= hb_is_copy_constructible>; +#define hb_is_trivially_copy_constructible(T) hb_is_trivially_copy_constructible::value + +template +using hb_is_trivially_move_constructible= hb_is_move_constructible>; +#define hb_is_trivially_move_constructible(T) hb_is_trivially_move_constructible::value + +/* Don't know how to do the following. */ +//template +//using hb_is_trivially_assignable= hb_is_assignable, hb_trivial>; +//#define hb_is_trivially_assignable(T,U) hb_is_trivially_assignable::value + +template +using hb_is_trivially_copy_assignable= hb_is_copy_assignable>; +#define hb_is_trivially_copy_assignable(T) hb_is_trivially_copy_assignable::value + +template +using hb_is_trivially_move_assignable= hb_is_move_assignable>; +#define hb_is_trivially_move_assignable(T) hb_is_trivially_move_assignable::value + +template +using hb_is_trivially_copyable= hb_bool_constant< + hb_is_trivially_destructible (T) && + (!hb_is_move_assignable (T) || hb_is_trivially_move_assignable (T)) && + (!hb_is_move_constructible (T) || hb_is_trivially_move_constructible (T)) && + (!hb_is_copy_assignable (T) || hb_is_trivially_copy_assignable (T)) && + (!hb_is_copy_constructible (T) || hb_is_trivially_copy_constructible (T)) && + true +>; +#define hb_is_trivially_copyable(T) hb_is_trivially_copyable::value + +template +using hb_is_trivial= hb_bool_constant< + hb_is_trivially_copyable (T) && + hb_is_trivially_default_constructible (T) +>; +#define hb_is_trivial(T) hb_is_trivial::value + +/* hb_unwrap_type (T) + * If T has no T::type, returns T. Otherwise calls itself on T::type recursively. + */ + +template +struct _hb_unwrap_type : hb_type_identity_t {}; +template +struct _hb_unwrap_type> : _hb_unwrap_type {}; +template +using hb_unwrap_type = _hb_unwrap_type; +#define hb_unwrap_type(T) typename hb_unwrap_type::type + +#endif /* HB_META_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh b/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh index 1582b40cb04..f2d2962b713 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh @@ -48,12 +48,22 @@ /* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */ +#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__)) + +#include +typedef pthread_mutex_t hb_mutex_impl_t; +#define HB_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER +#define hb_mutex_impl_init(M) pthread_mutex_init (M, nullptr) +#define hb_mutex_impl_lock(M) pthread_mutex_lock (M) +#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M) +#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M) + + #elif !defined(HB_NO_MT) && defined(_WIN32) -#include typedef CRITICAL_SECTION hb_mutex_impl_t; #define HB_MUTEX_IMPL_INIT {0} -#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0) #else #define hb_mutex_impl_init(M) InitializeCriticalSection (M) @@ -63,17 +73,6 @@ typedef CRITICAL_SECTION hb_mutex_impl_t; #define hb_mutex_impl_finish(M) DeleteCriticalSection (M) -#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__)) - -#include -typedef pthread_mutex_t hb_mutex_impl_t; -#define HB_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER -#define hb_mutex_impl_init(M) pthread_mutex_init (M, nullptr) -#define hb_mutex_impl_lock(M) pthread_mutex_lock (M) -#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M) -#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M) - - #elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES) #if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD) @@ -92,25 +91,7 @@ typedef volatile int hb_mutex_impl_t; #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END -#elif !defined(HB_NO_MT) - -#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD) -# include -# define HB_SCHED_YIELD() sched_yield () -#else -# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END -#endif - -#define HB_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */ -typedef volatile int hb_mutex_impl_t; -#define HB_MUTEX_IMPL_INIT 0 -#define hb_mutex_impl_init(M) *(M) = 0 -#define hb_mutex_impl_lock(M) HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END -#define hb_mutex_impl_unlock(M) (*(M))--; -#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END - - -#else /* HB_NO_MT */ +#elif defined(HB_NO_MT) typedef int hb_mutex_impl_t; #define HB_MUTEX_IMPL_INIT 0 @@ -120,6 +101,11 @@ typedef int hb_mutex_impl_t; #define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END +#else + +#error "Could not find any system to define mutex macros." +#error "Check hb-mutex.hh for possible resolutions." + #endif @@ -127,8 +113,6 @@ typedef int hb_mutex_impl_t; struct hb_mutex_t { - /* TODO Add tracing. */ - hb_mutex_impl_t m; void init () { hb_mutex_impl_init (&m); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-null.hh b/src/java.desktop/share/native/libharfbuzz/hb-null.hh index 8a0e2d7dd05..d2bc3322e53 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-null.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-null.hh @@ -28,6 +28,7 @@ #define HB_NULL_HH #include "hb.hh" +#include "hb-meta.hh" /* @@ -36,7 +37,7 @@ /* Global nul-content Null pool. Enlarge as necessary. */ -#define HB_NULL_POOL_SIZE 9880 +#define HB_NULL_POOL_SIZE 384 /* Use SFINAE to sniff whether T has min_size; in which case return T::null_size, * otherwise return sizeof(T). */ @@ -45,18 +46,13 @@ * https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol */ -template struct _hb_bool_type {}; - -template -struct _hb_null_size -{ enum { value = sizeof (T) }; }; +template +struct _hb_null_size : hb_integral_constant {}; template -struct _hb_null_size > -{ enum { value = T::null_size }; }; +struct _hb_null_size> : hb_integral_constant {}; template -struct hb_null_size -{ enum { value = _hb_null_size >::value }; }; +using hb_null_size = _hb_null_size; #define hb_null_size(T) hb_null_size::value /* These doesn't belong here, but since is copy/paste from above, put it here. */ @@ -64,56 +60,36 @@ struct hb_null_size /* hb_static_size (T) * Returns T::static_size if T::min_size is defined, or sizeof (T) otherwise. */ -template -struct _hb_static_size -{ enum { value = sizeof (T) }; }; +template +struct _hb_static_size : hb_integral_constant {}; template -struct _hb_static_size > -{ enum { value = T::static_size }; }; - +struct _hb_static_size> : hb_integral_constant {}; template -struct hb_static_size -{ enum { value = _hb_static_size >::value }; }; +using hb_static_size = _hb_static_size; #define hb_static_size(T) hb_static_size::value -/* hb_assign (obj, value) - * Calls obj.set (value) if obj.min_size is defined and value has different type - * from obj, or obj = v otherwise. */ - -template -struct _hb_assign -{ static inline void value (T &o, const V v) { o = v; } }; -template -struct _hb_assign > -{ static inline void value (T &o, const V v) { o.set (v); } }; -template -struct _hb_assign > -{ static inline void value (T &o, const T v) { o = v; } }; - -template -static inline void hb_assign (T &o, const V v) -{ _hb_assign >::value (o, v); } - - /* * Null() */ extern HB_INTERNAL -hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)]; +uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)]; /* Generic nul-content Null objects. */ template -static inline Type const & Null () { - static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); - return *reinterpret_cast (_hb_NullPool); -} +struct Null { + static Type const & get_null () + { + static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); + return *reinterpret_cast (_hb_NullPool); + } +}; template struct NullHelper { - typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type; - static const Type & get_null () { return Null (); } + typedef hb_remove_const> Type; + static const Type & get_null () { return Null::get_null (); } }; #define Null(Type) NullHelper::get_null () @@ -122,11 +98,13 @@ struct NullHelper } /* Close namespace. */ \ extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \ template <> \ - /*static*/ inline const Namespace::Type& Null () { \ - return *reinterpret_cast (_hb_Null_##Namespace##_##Type); \ - } \ + struct Null { \ + static Namespace::Type const & get_null () { \ + return *reinterpret_cast (_hb_Null_##Namespace##_##Type); \ + } \ + }; \ namespace Namespace { \ - static_assert (true, "Just so we take semicolon after.") + static_assert (true, "") /* Require semicolon after. */ #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \ const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size] @@ -134,10 +112,12 @@ struct NullHelper #define DECLARE_NULL_INSTANCE(Type) \ extern HB_INTERNAL const Type _hb_Null_##Type; \ template <> \ - /*static*/ inline const Type& Null () { \ - return _hb_Null_##Type; \ - } \ -static_assert (true, "Just so we take semicolon after.") + struct Null { \ + static Type const & get_null () { \ + return _hb_Null_##Type; \ + } \ + }; \ + static_assert (true, "") /* Require semicolon after. */ #define DEFINE_NULL_INSTANCE(Type) \ const Type _hb_Null_##Type @@ -148,31 +128,31 @@ static_assert (true, "Just so we take semicolon after.") * causing bad memory access. So, races there are not actually introducing incorrectness * in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */ extern HB_INTERNAL -/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)]; +/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)]; /* CRAP pool: Common Region for Access Protection. */ template static inline Type& Crap () { static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE."); Type *obj = reinterpret_cast (_hb_CrapPool); - memcpy (obj, &Null(Type), sizeof (*obj)); + memcpy (obj, &Null (Type), sizeof (*obj)); return *obj; } template struct CrapHelper { - typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type; + typedef hb_remove_const> Type; static Type & get_crap () { return Crap (); } }; #define Crap(Type) CrapHelper::get_crap () template struct CrapOrNullHelper { - static Type & get () { return Crap(Type); } + static Type & get () { return Crap (Type); } }; template struct CrapOrNullHelper { - static const Type & get () { return Null(Type); } + static const Type & get () { return Null (Type); } }; #define CrapOrNull(Type) CrapOrNullHelper::get () @@ -184,7 +164,7 @@ struct CrapOrNullHelper { template struct hb_nonnull_ptr_t { - typedef typename hb_remove_pointer (P) T; + typedef hb_remove_pointer

    T; hb_nonnull_ptr_t (T *v_ = nullptr) : v (v_) {} T * operator = (T *v_) { return v = v_; } @@ -194,7 +174,7 @@ struct hb_nonnull_ptr_t /* Only auto-cast to const types. */ template operator const C * () const { return get (); } operator const char * () const { return (const char *) get (); } - T * get () const { return v ? v : const_cast (&Null(T)); } + T * get () const { return v ? v : const_cast (&Null (T)); } T * get_raw () const { return v; } T *v; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh new file mode 100644 index 00000000000..9d2867e4835 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh @@ -0,0 +1,237 @@ + +#line 1 "hb-number-parser.rl" +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ + +#ifndef HB_NUMBER_PARSER_HH +#define HB_NUMBER_PARSER_HH + +#include "hb.hh" + + +#line 35 "hb-number-parser.hh" +static const unsigned char _double_parser_trans_keys[] = { + 0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, + 46u, 101u, 0 +}; + +static const char _double_parser_key_spans[] = { + 0, 15, 12, 10, 15, 10, 54, 10, + 56 +}; + +static const unsigned char _double_parser_index_offsets[] = { + 0, 0, 16, 29, 40, 56, 67, 122, + 133 +}; + +static const char _double_parser_indicies[] = { + 0, 1, 2, 3, 1, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 1, 3, 1, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 1, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 1, 6, 1, 7, 1, 1, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 1, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 1, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 9, 1, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 1, 3, 1, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 9, 1, 0 +}; + +static const char _double_parser_trans_targs[] = { + 2, 0, 2, 3, 8, 6, 5, 5, + 7, 4 +}; + +static const char _double_parser_trans_actions[] = { + 0, 0, 1, 0, 2, 3, 0, 4, + 5, 0 +}; + +static const int double_parser_start = 1; +static const int double_parser_first_final = 6; +static const int double_parser_error = 0; + +static const int double_parser_en_main = 1; + + +#line 68 "hb-number-parser.rl" + + +/* Works only for n < 512 */ +static inline double +_pow10 (unsigned exponent) +{ + static const double _powers_of_10[] = + { + 1.0e+256, + 1.0e+128, + 1.0e+64, + 1.0e+32, + 1.0e+16, + 1.0e+8, + 10000., + 100., + 10. + }; + unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1); + double result = 1; + for (const double *power = _powers_of_10; mask; ++power, mask >>= 1) + if (exponent & mask) result *= *power; + return result; +} + +/* a variant of strtod that also gets end of buffer in its second argument */ +static inline double +strtod_rl (const char *p, const char **end_ptr /* IN/OUT */) +{ + double value = 0; + double frac = 0; + double frac_count = 0; + unsigned exp = 0; + bool neg = false, exp_neg = false, exp_overflow = false; + const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */ + const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */ + + const char *pe = *end_ptr; + while (p < pe && ISSPACE (*p)) + p++; + + int cs; + +#line 139 "hb-number-parser.hh" + { + cs = double_parser_start; + } + +#line 144 "hb-number-parser.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _double_parser_trans_keys + (cs<<1); + _inds = _double_parser_indicies + _double_parser_index_offsets[cs]; + + _slen = _double_parser_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _double_parser_trans_targs[_trans]; + + if ( _double_parser_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _double_parser_trans_actions[_trans] ) { + case 1: +#line 37 "hb-number-parser.rl" + { neg = true; } + break; + case 4: +#line 38 "hb-number-parser.rl" + { exp_neg = true; } + break; + case 2: +#line 40 "hb-number-parser.rl" + { + value = value * 10. + ((*p) - '0'); +} + break; + case 3: +#line 43 "hb-number-parser.rl" + { + if (likely (frac <= MAX_FRACT / 10)) + { + frac = frac * 10. + ((*p) - '0'); + ++frac_count; + } +} + break; + case 5: +#line 50 "hb-number-parser.rl" + { + if (likely (exp * 10 + ((*p) - '0') <= MAX_EXP)) + exp = exp * 10 + ((*p) - '0'); + else + exp_overflow = true; +} + break; +#line 202 "hb-number-parser.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +#line 113 "hb-number-parser.rl" + + + *end_ptr = p; + + if (frac_count) value += frac / _pow10 (frac_count); + if (neg) value *= -1.; + + if (unlikely (exp_overflow)) + { + if (value == 0) return value; + if (exp_neg) return neg ? -DBL_MIN : DBL_MIN; + else return neg ? -DBL_MAX : DBL_MAX; + } + + if (exp) + { + if (exp_neg) value /= _pow10 (exp); + else value *= _pow10 (exp); + } + + return value; +} + +#endif /* HB_NUMBER_PARSER_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number.cc b/src/java.desktop/share/native/libharfbuzz/hb-number.cc new file mode 100644 index 00000000000..f4ce693d8ed --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-number.cc @@ -0,0 +1,80 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ + +#include "hb.hh" +#include "hb-machinery.hh" +#include "hb-number.hh" +#include "hb-number-parser.hh" + +template +static bool +_parse_number (const char **pp, const char *end, T *pv, + bool whole_buffer, Func f) +{ + char buf[32]; + unsigned len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned) (end - *pp)); + strncpy (buf, *pp, len); + buf[len] = '\0'; + + char *p = buf; + char *pend = p; + + errno = 0; + *pv = f (p, &pend); + if (unlikely (errno || p == pend || + /* Check if consumed whole buffer if is requested */ + (whole_buffer && pend - p != end - *pp))) + return false; + + *pp += pend - p; + return true; +} + +bool +hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer) +{ + return _parse_number (pp, end, pv, whole_buffer, + [] (const char *p, char **end) + { return strtol (p, end, 10); }); +} + +bool +hb_parse_uint (const char **pp, const char *end, unsigned *pv, + bool whole_buffer, int base) +{ + return _parse_number (pp, end, pv, whole_buffer, + [base] (const char *p, char **end) + { return strtoul (p, end, base); }); +} + +bool +hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer) +{ + const char *pend = end; + *pv = strtod_rl (*pp, &pend); + if (unlikely (*pp == pend)) return false; + *pp = pend; + return !whole_buffer || end == pend; +} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number.hh b/src/java.desktop/share/native/libharfbuzz/hb-number.hh new file mode 100644 index 00000000000..47d902cf3e7 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-number.hh @@ -0,0 +1,41 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + */ + +#ifndef HB_NUMBER_HH +#define HB_NUMBER_HH + +HB_INTERNAL bool +hb_parse_int (const char **pp, const char *end, int *pv, + bool whole_buffer = false); + +HB_INTERNAL bool +hb_parse_uint (const char **pp, const char *end, unsigned int *pv, + bool whole_buffer = false, int base = 10); + +HB_INTERNAL bool +hb_parse_double (const char **pp, const char *end, double *pv, + bool whole_buffer = false); + +#endif /* HB_NUMBER_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-object.hh b/src/java.desktop/share/native/libharfbuzz/hb-object.hh index 1d7b6bf4f0b..f01508ed40b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-object.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-object.hh @@ -168,8 +168,8 @@ struct hb_user_data_array_t void *data; hb_destroy_func_t destroy; - bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; } - bool operator == (hb_user_data_item_t &other) const { return key == other.key; } + bool operator == (const hb_user_data_key_t *other_key) const { return key == other_key; } + bool operator == (const hb_user_data_item_t &other) const { return key == other.key; } void fini () { if (destroy) destroy (data); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh index 72b203041d6..95a8f75ff20 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh @@ -56,7 +56,7 @@ typedef struct TableRecord { int cmp (Tag t) const { return -t.cmp (tag); } - static int cmp (const void *pa, const void *pb) + HB_INTERNAL static int cmp (const void *pa, const void *pb) { const TableRecord *a = (const TableRecord *) pa; const TableRecord *b = (const TableRecord *) pb; @@ -86,27 +86,22 @@ typedef struct OffsetTable const TableRecord& get_table (unsigned int i) const { return tables[i]; } unsigned int get_table_tags (unsigned int start_offset, - unsigned int *table_count, /* IN/OUT */ - hb_tag_t *table_tags /* OUT */) const + unsigned int *table_count, /* IN/OUT */ + hb_tag_t *table_tags /* OUT */) const { if (table_count) { - if (start_offset >= tables.len) - *table_count = 0; - else - *table_count = MIN (*table_count, tables.len - start_offset); - - const TableRecord *sub_tables = tables.arrayZ + start_offset; - unsigned int count = *table_count; - for (unsigned int i = 0; i < count; i++) - table_tags[i] = sub_tables[i].tag; + + tables.sub_array (start_offset, table_count) + | hb_map (&TableRecord::tag) + | hb_sink (hb_array (table_tags, *table_count)) + ; } return tables.len; } bool find_table_index (hb_tag_t tag, unsigned int *table_index) const { Tag t; - t.set (tag); + t = tag; return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); } const TableRecord& get_table_by_tag (hb_tag_t tag) const @@ -127,7 +122,7 @@ typedef struct OffsetTable /* Alloc 12 for the OTHeader. */ if (unlikely (!c->extend_min (*this))) return_trace (false); /* Write sfntVersion (bytes 0..3). */ - sfnt_version.set (sfnt_tag); + sfnt_version = sfnt_tag; /* Take space for numTables, searchRange, entrySelector, RangeShift * and the TableRecords themselves. */ if (unlikely (!tables.serialize (c, items.length))) return_trace (false); @@ -140,15 +135,16 @@ typedef struct OffsetTable { TableRecord &rec = tables.arrayZ[i]; hb_blob_t *blob = items[i].blob; - rec.tag.set (items[i].tag); - rec.length.set (hb_blob_get_length (blob)); + rec.tag = items[i].tag; + rec.length = blob->length; rec.offset.serialize (c, this); /* Allocate room for the table and copy it. */ char *start = (char *) c->allocate_size (rec.length); - if (unlikely (!start)) {return false;} + if (unlikely (!start)) return false; - memcpy (start, hb_blob_get_data (blob, nullptr), rec.length); + if (likely (rec.length)) + memcpy (start, blob->data, rec.length); /* 4-byte alignment. */ c->align (4); @@ -159,7 +155,7 @@ typedef struct OffsetTable { head *h = (head *) start; checksum_adjustment = &h->checkSumAdjustment; - checksum_adjustment->set (0); + *checksum_adjustment = 0; } rec.checkSum.set_for_data (start, end - start); @@ -177,10 +173,10 @@ typedef struct OffsetTable for (unsigned int i = 0; i < items.length; i++) { TableRecord &rec = tables.arrayZ[i]; - checksum.set (checksum + rec.checkSum); + checksum = checksum + rec.checkSum; } - checksum_adjustment->set (0xB1B0AFBAu - checksum); + *checksum_adjustment = 0xB1B0AFBAu - checksum; } return_trace (true); @@ -222,7 +218,7 @@ struct TTCHeaderVersion1 Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */ FixedVersion<>version; /* Version of the TTC Header (1.0), * 0x00010000u */ - LArrayOf > + LArrayOf> table; /* Array of offsets to the OffsetTable for each font * from the beginning of the file */ public: @@ -248,7 +244,7 @@ struct TTCHeader switch (u.header.version.major) { case 2: /* version 2 is compatible with version 1 */ case 1: return u.version1.get_face (i); - default:return Null(OpenTypeFontFace); + default:return Null (OpenTypeFontFace); } } @@ -283,10 +279,10 @@ struct TTCHeader struct ResourceRecord { const OpenTypeFontFace & get_face (const void *data_base) const - { return CastR ((data_base+offset).arrayZ); } + { return * reinterpret_cast ((data_base+offset).arrayZ); } bool sanitize (hb_sanitize_context_t *c, - const void *data_base) const + const void *data_base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && @@ -334,7 +330,7 @@ struct ResourceTypeRecord protected: Tag tag; /* Resource type. */ HBUINT16 resCountM1; /* Number of resources minus 1. */ - NNOffsetTo > + NNOffsetTo> resourcesZ; /* Offset from beginning of resource type list * to reference item list for this type. */ public: @@ -390,7 +386,7 @@ struct ResourceMap HBUINT32 reserved1; /* Reserved for handle to next resource map */ HBUINT16 resreved2; /* Reserved for file reference number */ HBUINT16 attrs; /* Resource fork attribute */ - NNOffsetTo > + NNOffsetTo> typeList; /* Offset from beginning of map to * resource type list */ Offset16 nameList; /* Offset from beginning of map to @@ -422,7 +418,7 @@ struct ResourceForkHeader } protected: - LNNOffsetTo > + LNNOffsetTo> data; /* Offset from beginning of resource fork * to resource data */ LNNOffsetTo @@ -477,7 +473,7 @@ struct OpenTypeFontFile case TrueTypeTag: return u.fontFace; case TTCTag: return u.ttcHeader.get_face (i); case DFontTag: return u.rfHeader.get_face (i, base_offset); - default: return Null(OpenTypeFontFace); + default: return Null (OpenTypeFontFace); } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh index 596099305c1..624194651d3 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh @@ -52,22 +52,34 @@ namespace OT { * Int types */ -template struct hb_signedness_int; -template <> struct hb_signedness_int { typedef unsigned int value; }; -template <> struct hb_signedness_int { typedef signed int value; }; - /* Integer types in big-endian order and no alignment requirement */ template struct IntType { typedef Type type; - typedef typename hb_signedness_int::value>::value wide_type; + typedef hb_conditional wide_type; - void set (wide_type i) { v.set (i); } + IntType& operator = (wide_type i) { v = i; return *this; } operator wide_type () const { return v; } - bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } - bool operator != (const IntType &o) const { return !(*this == o); } - static int cmp (const IntType *a, const IntType *b) { return b->cmp (*a); } + bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; } + bool operator != (const IntType &o) const { return !(*this == o); } + + IntType& operator += (unsigned count) { *this = *this + count; return *this; } + IntType& operator -= (unsigned count) { *this = *this - count; return *this; } + IntType& operator ++ () { *this += 1; return *this; } + IntType& operator -- () { *this -= 1; return *this; } + IntType operator ++ (int) { IntType c (*this); ++*this; return c; } + IntType operator -- (int) { IntType c (*this); --*this; return c; } + + HB_INTERNAL static int cmp (const IntType *a, const IntType *b) + { return b->cmp (*a); } + HB_INTERNAL static int cmp (const void *a, const void *b) + { + IntType *pa = (IntType *) a; + IntType *pb = (IntType *) b; + + return pb->cmp (*pa); + } template int cmp (Type2 a) const { @@ -110,19 +122,21 @@ typedef HBUINT16 UFWORD; /* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ struct F2DOT14 : HBINT16 { + F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; } // 16384 means 1<<14 float to_float () const { return ((int32_t) v) / 16384.f; } - void set_float (float f) { v.set (round (f * 16384.f)); } + void set_float (float f) { v = roundf (f * 16384.f); } public: DEFINE_SIZE_STATIC (2); }; /* 32-bit signed fixed-point number (16.16). */ -struct Fixed : HBINT32 +struct HBFixed : HBINT32 { + HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; } // 65536 means 1<<16 float to_float () const { return ((int32_t) v) / 65536.f; } - void set_float (float f) { v.set (round (f * 65536.f)); } + void set_float (float f) { v = roundf (f * 65536.f); } public: DEFINE_SIZE_STATIC (4); }; @@ -147,6 +161,7 @@ struct LONGDATETIME * system, feature, or baseline */ struct Tag : HBUINT32 { + Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; } /* What the char* converters return is NOT nul-terminated. Print using "%.4s" */ operator const char* () const { return reinterpret_cast (&this->v); } operator char* () { return reinterpret_cast (&this->v); } @@ -155,11 +170,15 @@ struct Tag : HBUINT32 }; /* Glyph index number, same as uint16 (length = 16 bits) */ -typedef HBUINT16 GlyphID; +struct HBGlyphID : HBUINT16 +{ + HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } +}; /* Script/language-system/feature index */ struct Index : HBUINT16 { static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu; + Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } }; DECLARE_NULL_NAMESPACE_BYTES (OT, Index); @@ -169,6 +188,8 @@ typedef Index NameID; template struct Offset : Type { + Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; } + typedef Type type; bool is_null () const { return has_null && 0 == *this; } @@ -176,7 +197,7 @@ struct Offset : Type void *serialize (hb_serialize_context_t *c, const void *base) { void *t = c->start_embed (); - this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */ + c->check_assign (*this, (unsigned) ((char *) t - (char *) base)); return t; } @@ -191,6 +212,8 @@ typedef Offset Offset32; /* CheckSum */ struct CheckSum : HBUINT32 { + CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } + /* This is reference implementation from the spec. */ static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length) { @@ -205,7 +228,7 @@ struct CheckSum : HBUINT32 /* Note: data should be 4byte aligned and have 4byte padding at the end. */ void set_for_data (const void *data, unsigned int length) - { set (CalcTableChecksum ((const HBUINT32 *) data, length)); } + { *this = CalcTableChecksum ((const HBUINT32 *) data, length); } public: DEFINE_SIZE_STATIC (4); @@ -248,13 +271,18 @@ struct _hb_has_null template struct _hb_has_null { - static const Type *get_null () { return &Null(Type); } - static Type *get_crap () { return &Crap(Type); } + static const Type *get_null () { return &Null (Type); } + static Type *get_crap () { return &Crap (Type); } }; template struct OffsetTo : Offset { + HB_DELETE_COPY_ASSIGN (OffsetTo); + OffsetTo () = default; + + OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; } + const Type& operator () (const void *base) const { if (unlikely (this->is_null ())) return *_hb_has_null::get_null (); @@ -266,24 +294,73 @@ struct OffsetTo : Offset return StructAtOffset (base, *this); } + template + friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); } + template + friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); } + template + friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); } + template + friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); } + Type& serialize (hb_serialize_context_t *c, const void *base) { return * (Type *) Offset::serialize (c, base); } - template - void serialize_subset (hb_subset_context_t *c, const T &src, const void *base) + template + bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src, + const void *src_base, Ts&&... ds) { - if (&src == &Null (T)) - { - this->set (0); - return; - } - serialize (c->serializer, base); - if (!src.subset (c)) - this->set (0); + *this = 0; + if (src.is_null ()) + return false; + + auto *s = c->serializer; + + s->push (); + + bool ret = c->dispatch (src_base+src, hb_forward (ds)...); + + if (ret || !has_null) + s->add_link (*this, s->pop_pack ()); + else + s->pop_discard (); + + return ret; + } + + /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */ + /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029 + * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&... + */ + template + bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, + const void *src_base, unsigned dst_bias, + hb_serialize_context_t::whence_t whence, + Ts&&... ds) + { + *this = 0; + if (src.is_null ()) + return false; + + c->push (); + + bool ret = c->copy (src_base+src, hb_forward (ds)...); + + c->add_link (*this, c->pop_pack (), whence, dst_bias); + + return ret; } + bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src, + const void *src_base, unsigned dst_bias = 0) + { return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); } + bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -293,39 +370,13 @@ struct OffsetTo : Offset return_trace (true); } - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - return_trace (sanitize_shallow (c, base) && - (this->is_null () || - StructAtOffset (base, *this).sanitize (c) || - neuter (c))); - } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const - { - TRACE_SANITIZE (this); - return_trace (sanitize_shallow (c, base) && - (this->is_null () || - StructAtOffset (base, *this).sanitize (c, d1) || - neuter (c))); - } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const - { - TRACE_SANITIZE (this); - return_trace (sanitize_shallow (c, base) && - (this->is_null () || - StructAtOffset (base, *this).sanitize (c, d1, d2) || - neuter (c))); - } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const + template + bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const { TRACE_SANITIZE (this); return_trace (sanitize_shallow (c, base) && (this->is_null () || - StructAtOffset (base, *this).sanitize (c, d1, d2, d3) || + c->dispatch (StructAtOffset (base, *this), hb_forward (ds)...) || neuter (c))); } @@ -338,14 +389,12 @@ struct OffsetTo : Offset DEFINE_SIZE_STATIC (sizeof (OffsetType)); }; /* Partial specializations. */ -template struct LOffsetTo : OffsetTo {}; -template struct NNOffsetTo : OffsetTo {}; -template struct LNNOffsetTo : OffsetTo {}; - -template -static inline const Type& operator + (const Base &base, const OffsetTo &offset) { return offset (base); } -template -static inline Type& operator + (Base &base, OffsetTo &offset) { return offset (base); } +template +using LOffsetTo = OffsetTo; +template +using NNOffsetTo = OffsetTo; +template +using LNNOffsetTo = LOffsetTo; /* @@ -358,7 +407,7 @@ struct UnsizedArrayOf typedef Type item_t; static constexpr unsigned item_size = hb_static_size (Type); - HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type); + HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf); const Type& operator [] (int i_) const { @@ -384,7 +433,7 @@ struct UnsizedArrayOf { return hb_array (arrayZ, len); } hb_array_t as_array (unsigned int len) const { return hb_array (arrayZ, len); } - operator hb_array_t () { return as_array (); } + operator hb_array_t< Type> () { return as_array (); } operator hb_array_t () const { return as_array (); } template @@ -393,42 +442,49 @@ struct UnsizedArrayOf template const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const { return *as_array (len).lsearch (x, ¬_found); } + template + bool lfind (unsigned int len, const T &x, unsigned *pos = nullptr) const + { return as_array (len).lfind (x, pos); } void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) { as_array (len).qsort (start, end); } - bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + bool serialize (hb_serialize_context_t *c, unsigned int items_len) { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - - /* Note: for structs that do not reference other structs, - * we do not need to call their sanitize() as we already did - * a bound check on the aggregate array size. We just include - * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not - * reference other structs via offsets. - */ - (void) (false && arrayZ[0].sanitize (c)); - + TRACE_SERIALIZE (this); + if (unlikely (!c->extend (*this, items_len))) return_trace (false); return_trace (true); } - bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const + template + bool serialize (hb_serialize_context_t *c, Iterator items) { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c, count))) return_trace (false); - for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base))) - return_trace (false); + TRACE_SERIALIZE (this); + unsigned count = items.len (); + if (unlikely (!serialize (c, count))) return_trace (false); + /* TODO Umm. Just exhaust the iterator instead? Being extra + * cautious right now.. */ + for (unsigned i = 0; i < count; i++, ++items) + arrayZ[i] = *items; return_trace (true); } - template - bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const + + UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const + { + TRACE_SERIALIZE (this); + auto *out = c->start_embed (this); + if (unlikely (!as_array (count).copy (c))) return_trace (nullptr); + return_trace (out); + } + + template + bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c, count))) return_trace (false); + if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) + if (unlikely (!c->dispatch (arrayZ[i], hb_forward (ds)...))) return_trace (false); return_trace (true); } @@ -440,14 +496,14 @@ struct UnsizedArrayOf } public: - Type arrayZ[VAR]; + Type arrayZ[HB_VAR_ARRAY]; public: DEFINE_SIZE_UNBOUNDED (0); }; /* Unsized array of offset's */ template -struct UnsizedOffsetArrayOf : UnsizedArrayOf > {}; +using UnsizedOffsetArrayOf = UnsizedArrayOf>; /* Unsized array of offsets relative to the beginning of the array itself. */ template @@ -468,17 +524,12 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf return this+*p; } - - bool sanitize (hb_sanitize_context_t *c, unsigned int count) const - { - TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf::sanitize (c, count, this))); - } - template - bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const + template + bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const { TRACE_SANITIZE (this); - return_trace ((UnsizedOffsetArrayOf::sanitize (c, count, this, user_data))); + return_trace ((UnsizedOffsetArrayOf + ::sanitize (c, count, this, hb_forward (ds)...))); } }; @@ -501,8 +552,8 @@ struct SortedUnsizedArrayOf : UnsizedArrayOf { return *as_array (len).bsearch (x, ¬_found); } template bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr, - hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, - unsigned int to_store = (unsigned int) -1) const + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const { return as_array (len).bfind (x, i, not_found, to_store); } }; @@ -514,7 +565,7 @@ struct ArrayOf typedef Type item_t; static constexpr unsigned item_size = hb_static_size (Type); - HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType); + HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf); const Type& operator [] (int i_) const { @@ -532,74 +583,83 @@ struct ArrayOf unsigned int get_size () const { return len.static_size + len * Type::static_size; } - hb_array_t as_array () - { return hb_array (arrayZ, len); } - hb_array_t as_array () const - { return hb_array (arrayZ, len); } - operator hb_array_t (void) { return as_array (); } - operator hb_array_t (void) const { return as_array (); } + explicit operator bool () const { return len; } + + void pop () { len--; } + + hb_array_t< Type> as_array () { return hb_array (arrayZ, len); } + hb_array_t as_array () const { return hb_array (arrayZ, len); } + + /* Iterator. */ + typedef hb_array_t iter_t; + typedef hb_array_t< Type> writer_t; + iter_t iter () const { return as_array (); } + writer_t writer () { return as_array (); } + operator iter_t () const { return iter (); } + operator writer_t () { return writer (); } hb_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + hb_success_t serialize (hb_serialize_context_t *c, unsigned items_len) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - len.set (items_len); /* TODO(serialize) Overflow? */ + c->check_assign (len, items_len); if (unlikely (!c->extend (*this))) return_trace (false); return_trace (true); } - template - bool serialize (hb_serialize_context_t *c, hb_array_t items) + template + hb_success_t serialize (hb_serialize_context_t *c, Iterator items) { TRACE_SERIALIZE (this); - if (unlikely (!serialize (c, items.length))) return_trace (false); - for (unsigned int i = 0; i < items.length; i++) - hb_assign (arrayZ[i], items[i]); + unsigned count = items.len (); + if (unlikely (!serialize (c, count))) return_trace (false); + /* TODO Umm. Just exhaust the iterator instead? Being extra + * cautious right now.. */ + for (unsigned i = 0; i < count; i++, ++items) + arrayZ[i] = *items; return_trace (true); } - bool sanitize (hb_sanitize_context_t *c) const + Type* serialize_append (hb_serialize_context_t *c) { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - - /* Note: for structs that do not reference other structs, - * we do not need to call their sanitize() as we already did - * a bound check on the aggregate array size. We just include - * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not - * reference other structs via offsets. - */ - (void) (false && arrayZ[0].sanitize (c)); - - return_trace (true); + TRACE_SERIALIZE (this); + len++; + if (unlikely (!len || !c->extend (*this))) + { + len--; + return_trace (nullptr); + } + return_trace (&arrayZ[len - 1]); } - bool sanitize (hb_sanitize_context_t *c, const void *base) const + + ArrayOf* copy (hb_serialize_context_t *c) const { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base))) - return_trace (false); - return_trace (true); + TRACE_SERIALIZE (this); + auto *out = c->start_embed (this); + if (unlikely (!c->extend_min (out))) return_trace (nullptr); + c->check_assign (out->len, len); + if (unlikely (!as_array ().copy (c))) return_trace (nullptr); + return_trace (out); } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const + + template + bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); + if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); unsigned int count = len; for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) + if (unlikely (!c->dispatch (arrayZ[i], hb_forward (ds)...))) return_trace (false); return_trace (true); } @@ -610,6 +670,9 @@ struct ArrayOf template const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const { return *as_array ().lsearch (x, ¬_found); } + template + bool lfind (const T &x, unsigned *pos = nullptr) const + { return as_array ().lfind (x, pos); } void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) { as_array ().qsort (start, end); } @@ -622,20 +685,21 @@ struct ArrayOf public: LenType len; - Type arrayZ[VAR]; + Type arrayZ[HB_VAR_ARRAY]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; -template struct LArrayOf : ArrayOf {}; -typedef ArrayOf PString; +template +using LArrayOf = ArrayOf; +using PString = ArrayOf; /* Array of Offset's */ template -struct OffsetArrayOf : ArrayOf > {}; +using OffsetArrayOf = ArrayOf>; template -struct LOffsetArrayOf : ArrayOf > {}; +using LOffsetArrayOf = ArrayOf>; template -struct LOffsetLArrayOf : ArrayOf, HBUINT32> {}; +using LOffsetLArrayOf = ArrayOf, HBUINT32>; /* Array of offsets relative to the beginning of the array itself. */ template @@ -661,20 +725,15 @@ struct OffsetListOf : OffsetArrayOf if (unlikely (!out)) return_trace (false); unsigned int count = this->len; for (unsigned int i = 0; i < count; i++) - out->arrayZ[i].serialize_subset (c, (*this)[i], out); + out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out); return_trace (true); } - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (OffsetArrayOf::sanitize (c, this)); - } - template - bool sanitize (hb_sanitize_context_t *c, T user_data) const + template + bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); - return_trace (OffsetArrayOf::sanitize (c, this, user_data)); + return_trace (OffsetArrayOf::sanitize (c, this, hb_forward (ds)...)); } }; @@ -684,7 +743,7 @@ struct HeadlessArrayOf { static constexpr unsigned item_size = Type::static_size; - HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType); + HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf); const Type& operator [] (int i_) const { @@ -699,34 +758,53 @@ struct HeadlessArrayOf return arrayZ[i-1]; } unsigned int get_size () const - { return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; } + { return lenP1.static_size + get_length () * Type::static_size; } - bool serialize (hb_serialize_context_t *c, - hb_array_t items) + unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; } + + hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); } + hb_array_t as_array () const { return hb_array (arrayZ, get_length ()); } + + /* Iterator. */ + typedef hb_array_t iter_t; + typedef hb_array_t< Type> writer_t; + iter_t iter () const { return as_array (); } + writer_t writer () { return as_array (); } + operator iter_t () const { return iter (); } + operator writer_t () { return writer (); } + + bool serialize (hb_serialize_context_t *c, unsigned int items_len) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - lenP1.set (items.length + 1); /* TODO(serialize) Overflow? */ + c->check_assign (lenP1, items_len + 1); if (unlikely (!c->extend (*this))) return_trace (false); - for (unsigned int i = 0; i < items.length; i++) - arrayZ[i] = items[i]; + return_trace (true); + } + template + bool serialize (hb_serialize_context_t *c, Iterator items) + { + TRACE_SERIALIZE (this); + unsigned count = items.len (); + if (unlikely (!serialize (c, count))) return_trace (false); + /* TODO Umm. Just exhaust the iterator instead? Being extra + * cautious right now.. */ + for (unsigned i = 0; i < count; i++, ++items) + arrayZ[i] = *items; return_trace (true); } - bool sanitize (hb_sanitize_context_t *c) const + template + bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); - - /* Note: for structs that do not reference other structs, - * we do not need to call their sanitize() as we already did - * a bound check on the aggregate array size. We just include - * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not - * reference other structs via offsets. - */ - (void) (false && arrayZ[0].sanitize (c)); - + if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); + unsigned int count = get_length (); + for (unsigned int i = 0; i < count; i++) + if (unlikely (!c->dispatch (arrayZ[i], hb_forward (ds)...))) + return_trace (false); return_trace (true); } @@ -740,7 +818,7 @@ struct HeadlessArrayOf public: LenType lenP1; - Type arrayZ[VAR]; + Type arrayZ[HB_VAR_ARRAY]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; @@ -749,7 +827,7 @@ struct HeadlessArrayOf template struct ArrayOfM1 { - HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOfM1, Type, LenType); + HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1); const Type& operator [] (int i_) const { @@ -766,14 +844,14 @@ struct ArrayOfM1 unsigned int get_size () const { return lenM1.static_size + (lenM1 + 1) * Type::static_size; } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const + template + bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); unsigned int count = lenM1 + 1; for (unsigned int i = 0; i < count; i++) - if (unlikely (!arrayZ[i].sanitize (c, base, user_data))) + if (unlikely (!c->dispatch (arrayZ[i], hb_forward (ds)...))) return_trace (false); return_trace (true); } @@ -788,7 +866,7 @@ struct ArrayOfM1 public: LenType lenM1; - Type arrayZ[VAR]; + Type arrayZ[HB_VAR_ARRAY]; public: DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ); }; @@ -797,21 +875,40 @@ struct ArrayOfM1 template struct SortedArrayOf : ArrayOf { - hb_sorted_array_t as_array () - { return hb_sorted_array (this->arrayZ, this->len); } - hb_sorted_array_t as_array () const - { return hb_sorted_array (this->arrayZ, this->len); } - operator hb_sorted_array_t () { return as_array (); } - operator hb_sorted_array_t () const { return as_array (); } + hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); } + hb_sorted_array_t as_array () const { return hb_sorted_array (this->arrayZ, this->len); } + + /* Iterator. */ + typedef hb_sorted_array_t iter_t; + typedef hb_sorted_array_t< Type> writer_t; + iter_t iter () const { return as_array (); } + writer_t writer () { return as_array (); } + operator iter_t () const { return iter (); } + operator writer_t () { return writer (); } + + hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) const + { return as_array ().sub_array (start_offset, count); } + hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const + { return as_array ().sub_array (start_offset, count); } + hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) + { return as_array ().sub_array (start_offset, count); } + hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) + { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count);} - hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count);} - hb_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count);} - hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count);} + bool serialize (hb_serialize_context_t *c, unsigned int items_len) + { + TRACE_SERIALIZE (this); + bool ret = ArrayOf::serialize (c, items_len); + return_trace (ret); + } + template + bool serialize (hb_serialize_context_t *c, Iterator items) + { + TRACE_SERIALIZE (this); + bool ret = ArrayOf::serialize (c, items); + return_trace (ret); + } template Type &bsearch (const T &x, Type ¬_found = Crap (Type)) @@ -821,8 +918,8 @@ struct SortedArrayOf : ArrayOf { return *as_array ().bsearch (x, ¬_found); } template bool bfind (const T &x, unsigned int *i = nullptr, - hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, - unsigned int to_store = (unsigned int) -1) const + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const { return as_array ().bfind (x, i, not_found, to_store); } }; @@ -841,15 +938,16 @@ struct BinSearchHeader return_trace (c->check_struct (this)); } - void set (unsigned int v) + BinSearchHeader& operator = (unsigned int v) { - len.set (v); + len = v; assert (len == v); - entrySelector.set (MAX (1u, hb_bit_storage (v)) - 1); - searchRange.set (16 * (1u << entrySelector)); - rangeShift.set (v * 16 > searchRange - ? 16 * v - searchRange - : 0); + entrySelector = hb_max (1u, hb_bit_storage (v)) - 1; + searchRange = 16 * (1u << entrySelector); + rangeShift = v * 16 > searchRange + ? 16 * v - searchRange + : 0; + return *this; } protected: @@ -863,7 +961,7 @@ struct BinSearchHeader }; template -struct BinSearchArrayOf : SortedArrayOf > {}; +using BinSearchArrayOf = SortedArrayOf>; struct VarSizedBinSearchHeader @@ -893,7 +991,7 @@ struct VarSizedBinSearchArrayOf { static constexpr unsigned item_size = Type::static_size; - HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type); + HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf); bool last_is_terminator () const { @@ -928,40 +1026,15 @@ struct VarSizedBinSearchArrayOf unsigned int get_size () const { return header.static_size + header.nUnits * header.unitSize; } - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - - /* Note: for structs that do not reference other structs, - * we do not need to call their sanitize() as we already did - * a bound check on the aggregate array size. We just include - * a small unreachable expression to make sure the structs - * pointed to do have a simple sanitize(), ie. they do not - * reference other structs via offsets. - */ - (void) (false && StructAtOffset (&bytesZ, 0).sanitize (c)); - - return_trace (true); - } - bool sanitize (hb_sanitize_context_t *c, const void *base) const + template + bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); if (unlikely (!sanitize_shallow (c))) return_trace (false); + if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true); unsigned int count = get_length (); for (unsigned int i = 0; i < count; i++) - if (unlikely (!(*this)[i].sanitize (c, base))) - return_trace (false); - return_trace (true); - } - template - bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const - { - TRACE_SANITIZE (this); - if (unlikely (!sanitize_shallow (c))) return_trace (false); - unsigned int count = get_length (); - for (unsigned int i = 0; i < count; i++) - if (unlikely (!(*this)[i].sanitize (c, base, user_data))) + if (unlikely (!(*this)[i].sanitize (c, hb_forward (ds)...))) return_trace (false); return_trace (true); } @@ -969,18 +1042,15 @@ struct VarSizedBinSearchArrayOf template const Type *bsearch (const T &key) const { - unsigned int size = header.unitSize; - int min = 0, max = (int) get_length () - 1; - while (min <= max) - { - int mid = ((unsigned int) min + (unsigned int) max) / 2; - const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size)); - int c = p->cmp (key); - if (c < 0) max = mid - 1; - else if (c > 0) min = mid + 1; - else return p; - } - return nullptr; + unsigned pos; + return hb_bsearch_impl (&pos, + key, + (const void *) bytesZ, + get_length (), + header.unitSize, + _hb_cmp_method) + ? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize)) + : nullptr; } private: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh index d278e03d930..28073724efc 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh @@ -27,6 +27,7 @@ #define HB_OT_CFF_COMMON_HH #include "hb-open-type.hh" +#include "hb-bimap.hh" #include "hb-ot-layout-common.hh" #include "hb-cff-interp-dict-common.hh" #include "hb-subset-plan.hh" @@ -37,16 +38,19 @@ using namespace OT; #define CFF_UNDEF_CODE 0xFFFFFFFF +using objidx_t = hb_serialize_context_t::objidx_t; +using whence_t = hb_serialize_context_t::whence_t; + /* utility macro */ template -static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset) -{ return offset? (* reinterpret_cast ((const char *) P + offset)): Null(Type); } +static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset) +{ return offset ? StructAtOffset (P, offset) : Null (Type); } -inline unsigned int calcOffSize(unsigned int dataSize) +inline unsigned int calcOffSize (unsigned int dataSize) { unsigned int size = 1; unsigned int offset = dataSize + 1; - while ((offset & ~0xFF) != 0) + while (offset & ~0xFF) { size++; offset >>= 8; @@ -57,8 +61,8 @@ inline unsigned int calcOffSize(unsigned int dataSize) struct code_pair_t { - hb_codepoint_t code; - hb_codepoint_t glyph; + hb_codepoint_t code; + hb_codepoint_t glyph; }; typedef hb_vector_t str_buff_t; @@ -82,27 +86,20 @@ struct str_buff_vec_t : hb_vector_t template struct CFFIndex { - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */ - (c->check_struct (this) && offSize >= 1 && offSize <= 4 && - c->check_array (offsets, offSize, count + 1) && - c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1)))); - } - static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count) { return offSize * (count + 1); } unsigned int offset_array_size () const { return calculate_offset_array_size (offSize, count); } - static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize) + CFFIndex *copy (hb_serialize_context_t *c) const { - if (count == 0) - return COUNT::static_size; - else - return min_size + calculate_offset_array_size (offSize, count) + dataSize; + TRACE_SERIALIZE (this); + unsigned int size = get_size (); + CFFIndex *out = c->allocate_size (size); + if (likely (out)) + memcpy (out, this, size); + return_trace (out); } bool serialize (hb_serialize_context_t *c, const CFFIndex &src) @@ -110,7 +107,7 @@ struct CFFIndex TRACE_SERIALIZE (this); unsigned int size = src.get_size (); CFFIndex *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } @@ -123,16 +120,16 @@ struct CFFIndex if (byteArray.length == 0) { COUNT *dest = c->allocate_min (); - if (unlikely (dest == nullptr)) return_trace (false); - dest->set (0); + if (unlikely (!dest)) return_trace (false); + *dest = 0; } else { /* serialize CFFIndex header */ if (unlikely (!c->extend_min (*this))) return_trace (false); - this->count.set (byteArray.length); - this->offSize.set (offSize_); - if (!unlikely (c->allocate_size (offSize_ * (byteArray.length + 1)))) + this->count = byteArray.length; + this->offSize = offSize_; + if (unlikely (!c->allocate_size (offSize_ * (byteArray.length + 1)))) return_trace (false); /* serialize indices */ @@ -149,9 +146,8 @@ struct CFFIndex for (unsigned int i = 0; i < byteArray.length; i++) { const byte_str_t &bs = byteArray[i]; - unsigned char *dest = c->allocate_size (bs.length); - if (unlikely (dest == nullptr)) - return_trace (false); + unsigned char *dest = c->allocate_size (bs.length); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &bs[0], bs.length); } } @@ -166,14 +162,77 @@ struct CFFIndex byteArray.init (); byteArray.resize (buffArray.length); for (unsigned int i = 0; i < byteArray.length; i++) - { - byteArray[i] = byte_str_t (buffArray[i].arrayZ (), buffArray[i].length); - } + byteArray[i] = byte_str_t (buffArray[i].arrayZ, buffArray[i].length); bool result = this->serialize (c, offSize_, byteArray); byteArray.fini (); return result; } + template + bool serialize (hb_serialize_context_t *c, + Iterator it) + { + TRACE_SERIALIZE (this); + if (it.len () == 0) + { + COUNT *dest = c->allocate_min (); + if (unlikely (!dest)) return_trace (false); + *dest = 0; + } + else + { + serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; })); + for (const byte_str_t &_ : +it) + _.copy (c); + } + return_trace (true); + } + + bool serialize (hb_serialize_context_t *c, + const byte_str_array_t &byteArray) + { return serialize (c, + hb_iter (byteArray)); } + + bool serialize (hb_serialize_context_t *c, + const str_buff_vec_t &buffArray) + { + auto it = + + hb_iter (buffArray) + | hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); }) + ; + return serialize (c, it); + } + + template + bool serialize_header (hb_serialize_context_t *c, + Iterator it) + { + TRACE_SERIALIZE (this); + + unsigned total = + it | hb_reduce (hb_add, 0); + unsigned off_size = calcOffSize (total); + + /* serialize CFFIndex header */ + if (unlikely (!c->extend_min (*this))) return_trace (false); + this->count = it.len (); + this->offSize = off_size; + if (unlikely (!c->allocate_size (off_size * (it.len () + 1)))) + return_trace (false); + + /* serialize indices */ + unsigned int offset = 1; + unsigned int i = 0; + for (unsigned _ : +it) + { + CFFIndex::set_offset_at (i++, offset); + offset += _; + } + CFFIndex::set_offset_at (i, offset); + + return_trace (true); + } + void set_offset_at (unsigned int index, unsigned int offset) { HBUINT8 *p = offsets + offSize * index + offSize; @@ -181,7 +240,7 @@ struct CFFIndex for (; size; size--) { --p; - p->set (offset & 0xFF); + *p = offset & 0xFF; offset >>= 8; } } @@ -199,37 +258,38 @@ struct CFFIndex unsigned int length_at (unsigned int index) const { - if (likely ((offset_at (index + 1) >= offset_at (index)) && - (offset_at (index + 1) <= offset_at (count)))) - return offset_at (index + 1) - offset_at (index); - else - return 0; + if (unlikely ((offset_at (index + 1) < offset_at (index)) || + (offset_at (index + 1) > offset_at (count)))) + return 0; + return offset_at (index + 1) - offset_at (index); } const unsigned char *data_base () const - { return (const unsigned char *)this + min_size + offset_array_size (); } + { return (const unsigned char *) this + min_size + offset_array_size (); } unsigned int data_size () const { return HBINT8::static_size; } byte_str_t operator [] (unsigned int index) const { - if (likely (index < count)) - return byte_str_t (data_base () + offset_at (index) - 1, length_at (index)); - else - return Null(byte_str_t); + if (unlikely (index >= count)) return Null (byte_str_t); + return byte_str_t (data_base () + offset_at (index) - 1, length_at (index)); } unsigned int get_size () const { - if (this != &Null(CFFIndex)) - { - if (count > 0) - return min_size + offset_array_size () + (offset_at (count) - 1); - else - return count.static_size; /* empty CFFIndex contains count only */ - } - else - return 0; + if (this == &Null (CFFIndex)) return 0; + if (count > 0) + return min_size + offset_array_size () + (offset_at (count) - 1); + return count.static_size; /* empty CFFIndex contains count only */ + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely ((c->check_struct (this) && count == 0) || /* empty INDEX */ + (c->check_struct (this) && offSize >= 1 && offSize <= 4 && + c->check_array (offsets, offSize, count + 1) && + c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1)))); } protected: @@ -245,10 +305,11 @@ struct CFFIndex } public: - COUNT count; /* Number of object data. Note there are (count+1) offsets */ - HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ - HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */ - /* HBUINT8 data[VAR]; Object data */ + COUNT count; /* Number of object data. Note there are (count+1) offsets */ + HBUINT8 offSize; /* The byte size of each offset in the offsets array. */ + HBUINT8 offsets[HB_VAR_ARRAY]; + /* The array of (count + 1) offsets into objects array (1-base). */ + /* HBUINT8 data[HB_VAR_ARRAY]; Object data */ public: DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets); }; @@ -260,7 +321,7 @@ struct CFFIndexOf : CFFIndex { if (likely (index < CFFIndex::count)) return byte_str_t (CFFIndex::data_base () + CFFIndex::offset_at (index) - 1, CFFIndex::length_at (index)); - return Null(byte_str_t); + return Null (byte_str_t); } template @@ -275,9 +336,9 @@ struct CFFIndexOf : CFFIndex TRACE_SERIALIZE (this); /* serialize CFFIndex header */ if (unlikely (!c->extend_min (*this))) return_trace (false); - this->count.set (dataArrayLen); - this->offSize.set (offSize_); - if (!unlikely (c->allocate_size (offSize_ * (dataArrayLen + 1)))) + this->count = dataArrayLen; + this->offSize = offSize_; + if (unlikely (!c->allocate_size (offSize_ * (dataArrayLen + 1)))) return_trace (false); /* serialize indices */ @@ -293,112 +354,74 @@ struct CFFIndexOf : CFFIndex /* serialize data */ for (unsigned int i = 0; i < dataArrayLen; i++) { - TYPE *dest = c->start_embed (); - if (unlikely (dest == nullptr || - !dest->serialize (c, dataArray[i], param1, param2))) + TYPE *dest = c->start_embed (); + if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2))) return_trace (false); } return_trace (true); } - - /* in parallel to above */ - template - static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, - const DATA *dataArray, - unsigned int dataArrayLen, - hb_vector_t &dataSizeArray, /* OUT */ - const PARAM ¶m) - { - /* determine offset size */ - unsigned int totalDataSize = 0; - for (unsigned int i = 0; i < dataArrayLen; i++) - { - unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param); - dataSizeArray[i] = dataSize; - totalDataSize += dataSize; - } - offSize_ = calcOffSize (totalDataSize); - - return CFFIndex::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize); - } }; /* Top Dict, Font Dict, Private Dict */ struct Dict : UnsizedByteStr { - template + template bool serialize (hb_serialize_context_t *c, const DICTVAL &dictval, OP_SERIALIZER& opszr, - PARAM& param) + Ts&&... ds) { TRACE_SERIALIZE (this); for (unsigned int i = 0; i < dictval.get_count (); i++) - { - if (unlikely (!opszr.serialize (c, dictval[i], param))) + if (unlikely (!opszr.serialize (c, dictval[i], hb_forward (ds)...))) return_trace (false); - } - return_trace (true); - } - /* in parallel to above */ - template - static unsigned int calculate_serialized_size (const DICTVAL &dictval, - OP_SERIALIZER& opszr, - PARAM& param) - { - unsigned int size = 0; - for (unsigned int i = 0; i < dictval.get_count (); i++) - size += opszr.calculate_serialized_size (dictval[i], param); - return size; - } - - template - static unsigned int calculate_serialized_size (const DICTVAL &dictval, - OP_SERIALIZER& opszr) - { - unsigned int size = 0; - for (unsigned int i = 0; i < dictval.get_count (); i++) - size += opszr.calculate_serialized_size (dictval[i]); - return size; + return_trace (true); } - template - static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, int value, op_code_t intOp) + template + static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp) { // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation - if (/*unlikely*/ (!serialize_int (c, intOp, value))) + if (/*unlikely*/ (!serialize_int (c, intOp, value))) return false; TRACE_SERIALIZE (this); /* serialize the opcode */ HBUINT8 *p = c->allocate_size (OpCode_Size (op)); - if (unlikely (p == nullptr)) return_trace (false); + if (unlikely (!p)) return_trace (false); if (Is_OpCode_ESC (op)) { - p->set (OpCode_escape); + *p = OpCode_escape; op = Unmake_OpCode_ESC (op); p++; } - p->set (op); + *p = op; return_trace (true); } - static bool serialize_uint4_op (hb_serialize_context_t *c, op_code_t op, int value) - { return serialize_int_op (c, op, value, OpCode_longintdict); } + template + static bool serialize_int4_op (hb_serialize_context_t *c, op_code_t op, V value) + { return serialize_int_op (c, op, value, OpCode_longintdict); } - static bool serialize_uint2_op (hb_serialize_context_t *c, op_code_t op, int value) - { return serialize_int_op (c, op, value, OpCode_shortint); } + template + static bool serialize_int2_op (hb_serialize_context_t *c, op_code_t op, V value) + { return serialize_int_op (c, op, value, OpCode_shortint); } - static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value) + template + static bool serialize_link_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence) { - return serialize_uint4_op (c, op, value); + T &ofs = *(T *) (c->head + OpCode_Size (int_op)); + if (unlikely (!serialize_int_op (c, op, 0, int_op))) return false; + c->add_link (ofs, link, whence); + return true; } - static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value) - { - return serialize_uint2_op (c, op, value); - } + static bool serialize_link4_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head) + { return serialize_link_op (c, op, link, whence); } + + static bool serialize_link2_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head) + { return serialize_link_op (c, op, link, whence); } }; struct TopDict : Dict {}; @@ -407,155 +430,39 @@ struct PrivateDict : Dict {}; struct table_info_t { - void init () { offSize = offset = size = 0; } + void init () { offset = size = 0; link = 0; } unsigned int offset; unsigned int size; - unsigned int offSize; -}; - -/* used to remap font index or SID from fullset to subset. - * set to CFF_UNDEF_CODE if excluded from subset */ -struct remap_t : hb_vector_t -{ - void init () { SUPER::init (); } - - void fini () { SUPER::fini (); } - - bool reset (unsigned int size) - { - if (unlikely (!SUPER::resize (size))) - return false; - for (unsigned int i = 0; i < length; i++) - (*this)[i] = CFF_UNDEF_CODE; - count = 0; - return true; - } - - bool identity (unsigned int size) - { - if (unlikely (!SUPER::resize (size))) - return false; - unsigned int i; - for (i = 0; i < length; i++) - (*this)[i] = i; - count = i; - return true; - } - - bool excludes (hb_codepoint_t id) const - { return (id < length) && ((*this)[id] == CFF_UNDEF_CODE); } - - bool includes (hb_codepoint_t id) const - { return !excludes (id); } - - unsigned int add (unsigned int i) - { - if ((*this)[i] == CFF_UNDEF_CODE) - (*this)[i] = count++; - return (*this)[i]; - } - - hb_codepoint_t get_count () const { return count; } - - protected: - hb_codepoint_t count; - - private: - typedef hb_vector_t SUPER; + objidx_t link; }; template struct FDArray : CFFIndexOf { - /* used by CFF1 */ - template + template bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const hb_vector_t &fontDicts, + Iterator it, OP_SERIALIZER& opszr) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - this->count.set (fontDicts.length); - this->offSize.set (offSize_); - if (!unlikely (c->allocate_size (offSize_ * (fontDicts.length + 1)))) - return_trace (false); - - /* serialize font dict offsets */ - unsigned int offset = 1; - unsigned int fid = 0; - for (; fid < fontDicts.length; fid++) - { - CFFIndexOf::set_offset_at (fid, offset); - offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr); - } - CFFIndexOf::set_offset_at (fid, offset); - /* serialize font dicts */ - for (unsigned int i = 0; i < fontDicts.length; i++) + /* serialize INDEX data */ + hb_vector_t sizes; + c->push (); + + it + | hb_map ([&] (const hb_pair_t &_) { FontDict *dict = c->start_embed (); - if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i]))) - return_trace (false); - } - return_trace (true); - } - - /* used by CFF2 */ - template - bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const hb_vector_t &fontDicts, - unsigned int fdCount, - const remap_t &fdmap, - OP_SERIALIZER& opszr, - const hb_vector_t &privateInfos) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - this->count.set (fdCount); - this->offSize.set (offSize_); - if (!unlikely (c->allocate_size (offSize_ * (fdCount + 1)))) - return_trace (false); - - /* serialize font dict offsets */ - unsigned int offset = 1; - unsigned int fid = 0; - for (unsigned i = 0; i < fontDicts.length; i++) - if (fdmap.includes (i)) - { - CFFIndexOf::set_offset_at (fid++, offset); - offset += FontDict::calculate_serialized_size (fontDicts[i], opszr); - } - CFFIndexOf::set_offset_at (fid, offset); + dict->serialize (c, _.first, opszr, _.second); + return c->head - (const char*)dict; + }) + | hb_sink (sizes) + ; + c->pop_pack (false); - /* serialize font dicts */ - for (unsigned int i = 0; i < fontDicts.length; i++) - if (fdmap.includes (i)) - { - FontDict *dict = c->start_embed (); - if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]]))) - return_trace (false); - } - return_trace (true); - } - - /* in parallel to above */ - template - static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, - const hb_vector_t &fontDicts, - unsigned int fdCount, - const remap_t &fdmap, - OP_SERIALIZER& opszr) - { - unsigned int dictsSize = 0; - for (unsigned int i = 0; i < fontDicts.len; i++) - if (fdmap.includes (i)) - dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr); - - offSize_ = calcOffSize (dictsSize); - return CFFIndex::calculate_serialized_size (offSize_, fdCount, dictsSize); + /* serialize INDEX header */ + return_trace (CFFIndex::serialize_header (c, hb_iter (sizes))); } }; @@ -574,21 +481,20 @@ struct FDSelect0 { } hb_codepoint_t get_fd (hb_codepoint_t glyph) const - { - return (hb_codepoint_t)fds[glyph]; - } + { return (hb_codepoint_t) fds[glyph]; } unsigned int get_size (unsigned int num_glyphs) const { return HBUINT8::static_size * num_glyphs; } - HBUINT8 fds[VAR]; + HBUINT8 fds[HB_VAR_ARRAY]; - DEFINE_SIZE_MIN (1); + DEFINE_SIZE_MIN (0); }; template -struct FDSelect3_4_Range { - bool sanitize (hb_sanitize_context_t *c, const void */*nullptr*/, unsigned int fdcount) const +struct FDSelect3_4_Range +{ + bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const { TRACE_SANITIZE (this); return_trace (first < c->get_num_glyphs () && (fd < fdcount)); @@ -596,12 +502,13 @@ struct FDSelect3_4_Range { GID_TYPE first; FD_TYPE fd; - + public: DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size); }; template -struct FDSelect3_4 { +struct FDSelect3_4 +{ unsigned int get_size () const { return GID_TYPE::static_size * 2 + ranges.get_size (); } @@ -613,10 +520,8 @@ struct FDSelect3_4 { return_trace (false); for (unsigned int i = 1; i < nRanges (); i++) - { if (unlikely (ranges[i - 1].first >= ranges[i].first)) - return_trace (false); - } + return_trace (false); if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ()))) return_trace (false); @@ -631,13 +536,13 @@ struct FDSelect3_4 { if (glyph < ranges[i].first) break; - return (hb_codepoint_t)ranges[i - 1].fd; + return (hb_codepoint_t) ranges[i - 1].fd; } - GID_TYPE &nRanges () { return ranges.len; } - GID_TYPE nRanges () const { return ranges.len; } - GID_TYPE &sentinel () { return StructAfter (ranges[nRanges () - 1]); } - const GID_TYPE &sentinel () const { return StructAfter (ranges[nRanges () - 1]); } + GID_TYPE &nRanges () { return ranges.len; } + GID_TYPE nRanges () const { return ranges.len; } + GID_TYPE &sentinel () { return StructAfter (ranges[nRanges () - 1]); } + const GID_TYPE &sentinel () const { return StructAfter (ranges[nRanges () - 1]); } ArrayOf, GID_TYPE> ranges; /* GID_TYPE sentinel */ @@ -648,56 +553,60 @@ struct FDSelect3_4 { typedef FDSelect3_4 FDSelect3; typedef FDSelect3_4_Range FDSelect3_Range; -struct FDSelect { - bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const - { - TRACE_SANITIZE (this); - - return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) && - (format == 0)? - u.format0.sanitize (c, fdcount): - u.format3.sanitize (c, fdcount))); - } - +struct FDSelect +{ bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs) { TRACE_SERIALIZE (this); unsigned int size = src.get_size (num_glyphs); FDSelect *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } - unsigned int calculate_serialized_size (unsigned int num_glyphs) const - { return get_size (num_glyphs); } - unsigned int get_size (unsigned int num_glyphs) const { - unsigned int size = format.static_size; - if (format == 0) - size += u.format0.get_size (num_glyphs); - else - size += u.format3.get_size (); - return size; + switch (format) + { + case 0: return format.static_size + u.format0.get_size (num_glyphs); + case 3: return format.static_size + u.format3.get_size (); + default:return 0; + } } hb_codepoint_t get_fd (hb_codepoint_t glyph) const { - if (this == &Null(FDSelect)) - return 0; - if (format == 0) - return u.format0.get_fd (glyph); - else - return u.format3.get_fd (glyph); + if (this == &Null (FDSelect)) return 0; + + switch (format) + { + case 0: return u.format0.get_fd (glyph); + case 3: return u.format3.get_fd (glyph); + default:return 0; + } + } + + bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + + switch (format) + { + case 0: return_trace (u.format0.sanitize (c, fdcount)); + case 3: return_trace (u.format3.sanitize (c, fdcount)); + default:return_trace (false); + } } HBUINT8 format; union { - FDSelect0 format0; - FDSelect3 format3; + FDSelect0 format0; + FDSelect3 format3; } u; - + public: DEFINE_SIZE_MIN (1); }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh new file mode 100644 index 00000000000..65d56ae18b5 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh @@ -0,0 +1,425 @@ +/* + * Copyright © 2019 Adobe, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_OT_CFF1_STD_STR_HH +#if 0 /* Make checks happy. */ +#define HB_OT_CFF1_STD_STR_HH +#include "hb.hh" +#endif + +_S(".notdef") +_S("space") +_S("exclam") +_S("quotedbl") +_S("numbersign") +_S("dollar") +_S("percent") +_S("ampersand") +_S("quoteright") +_S("parenleft") +_S("parenright") +_S("asterisk") +_S("plus") +_S("comma") +_S("hyphen") +_S("period") +_S("slash") +_S("zero") +_S("one") +_S("two") +_S("three") +_S("four") +_S("five") +_S("six") +_S("seven") +_S("eight") +_S("nine") +_S("colon") +_S("semicolon") +_S("less") +_S("equal") +_S("greater") +_S("question") +_S("at") +_S("A") +_S("B") +_S("C") +_S("D") +_S("E") +_S("F") +_S("G") +_S("H") +_S("I") +_S("J") +_S("K") +_S("L") +_S("M") +_S("N") +_S("O") +_S("P") +_S("Q") +_S("R") +_S("S") +_S("T") +_S("U") +_S("V") +_S("W") +_S("X") +_S("Y") +_S("Z") +_S("bracketleft") +_S("backslash") +_S("bracketright") +_S("asciicircum") +_S("underscore") +_S("quoteleft") +_S("a") +_S("b") +_S("c") +_S("d") +_S("e") +_S("f") +_S("g") +_S("h") +_S("i") +_S("j") +_S("k") +_S("l") +_S("m") +_S("n") +_S("o") +_S("p") +_S("q") +_S("r") +_S("s") +_S("t") +_S("u") +_S("v") +_S("w") +_S("x") +_S("y") +_S("z") +_S("braceleft") +_S("bar") +_S("braceright") +_S("asciitilde") +_S("exclamdown") +_S("cent") +_S("sterling") +_S("fraction") +_S("yen") +_S("florin") +_S("section") +_S("currency") +_S("quotesingle") +_S("quotedblleft") +_S("guillemotleft") +_S("guilsinglleft") +_S("guilsinglright") +_S("fi") +_S("fl") +_S("endash") +_S("dagger") +_S("daggerdbl") +_S("periodcentered") +_S("paragraph") +_S("bullet") +_S("quotesinglbase") +_S("quotedblbase") +_S("quotedblright") +_S("guillemotright") +_S("ellipsis") +_S("perthousand") +_S("questiondown") +_S("grave") +_S("acute") +_S("circumflex") +_S("tilde") +_S("macron") +_S("breve") +_S("dotaccent") +_S("dieresis") +_S("ring") +_S("cedilla") +_S("hungarumlaut") +_S("ogonek") +_S("caron") +_S("emdash") +_S("AE") +_S("ordfeminine") +_S("Lslash") +_S("Oslash") +_S("OE") +_S("ordmasculine") +_S("ae") +_S("dotlessi") +_S("lslash") +_S("oslash") +_S("oe") +_S("germandbls") +_S("onesuperior") +_S("logicalnot") +_S("mu") +_S("trademark") +_S("Eth") +_S("onehalf") +_S("plusminus") +_S("Thorn") +_S("onequarter") +_S("divide") +_S("brokenbar") +_S("degree") +_S("thorn") +_S("threequarters") +_S("twosuperior") +_S("registered") +_S("minus") +_S("eth") +_S("multiply") +_S("threesuperior") +_S("copyright") +_S("Aacute") +_S("Acircumflex") +_S("Adieresis") +_S("Agrave") +_S("Aring") +_S("Atilde") +_S("Ccedilla") +_S("Eacute") +_S("Ecircumflex") +_S("Edieresis") +_S("Egrave") +_S("Iacute") +_S("Icircumflex") +_S("Idieresis") +_S("Igrave") +_S("Ntilde") +_S("Oacute") +_S("Ocircumflex") +_S("Odieresis") +_S("Ograve") +_S("Otilde") +_S("Scaron") +_S("Uacute") +_S("Ucircumflex") +_S("Udieresis") +_S("Ugrave") +_S("Yacute") +_S("Ydieresis") +_S("Zcaron") +_S("aacute") +_S("acircumflex") +_S("adieresis") +_S("agrave") +_S("aring") +_S("atilde") +_S("ccedilla") +_S("eacute") +_S("ecircumflex") +_S("edieresis") +_S("egrave") +_S("iacute") +_S("icircumflex") +_S("idieresis") +_S("igrave") +_S("ntilde") +_S("oacute") +_S("ocircumflex") +_S("odieresis") +_S("ograve") +_S("otilde") +_S("scaron") +_S("uacute") +_S("ucircumflex") +_S("udieresis") +_S("ugrave") +_S("yacute") +_S("ydieresis") +_S("zcaron") +_S("exclamsmall") +_S("Hungarumlautsmall") +_S("dollaroldstyle") +_S("dollarsuperior") +_S("ampersandsmall") +_S("Acutesmall") +_S("parenleftsuperior") +_S("parenrightsuperior") +_S("twodotenleader") +_S("onedotenleader") +_S("zerooldstyle") +_S("oneoldstyle") +_S("twooldstyle") +_S("threeoldstyle") +_S("fouroldstyle") +_S("fiveoldstyle") +_S("sixoldstyle") +_S("sevenoldstyle") +_S("eightoldstyle") +_S("nineoldstyle") +_S("commasuperior") +_S("threequartersemdash") +_S("periodsuperior") +_S("questionsmall") +_S("asuperior") +_S("bsuperior") +_S("centsuperior") +_S("dsuperior") +_S("esuperior") +_S("isuperior") +_S("lsuperior") +_S("msuperior") +_S("nsuperior") +_S("osuperior") +_S("rsuperior") +_S("ssuperior") +_S("tsuperior") +_S("ff") +_S("ffi") +_S("ffl") +_S("parenleftinferior") +_S("parenrightinferior") +_S("Circumflexsmall") +_S("hyphensuperior") +_S("Gravesmall") +_S("Asmall") +_S("Bsmall") +_S("Csmall") +_S("Dsmall") +_S("Esmall") +_S("Fsmall") +_S("Gsmall") +_S("Hsmall") +_S("Ismall") +_S("Jsmall") +_S("Ksmall") +_S("Lsmall") +_S("Msmall") +_S("Nsmall") +_S("Osmall") +_S("Psmall") +_S("Qsmall") +_S("Rsmall") +_S("Ssmall") +_S("Tsmall") +_S("Usmall") +_S("Vsmall") +_S("Wsmall") +_S("Xsmall") +_S("Ysmall") +_S("Zsmall") +_S("colonmonetary") +_S("onefitted") +_S("rupiah") +_S("Tildesmall") +_S("exclamdownsmall") +_S("centoldstyle") +_S("Lslashsmall") +_S("Scaronsmall") +_S("Zcaronsmall") +_S("Dieresissmall") +_S("Brevesmall") +_S("Caronsmall") +_S("Dotaccentsmall") +_S("Macronsmall") +_S("figuredash") +_S("hypheninferior") +_S("Ogoneksmall") +_S("Ringsmall") +_S("Cedillasmall") +_S("questiondownsmall") +_S("oneeighth") +_S("threeeighths") +_S("fiveeighths") +_S("seveneighths") +_S("onethird") +_S("twothirds") +_S("zerosuperior") +_S("foursuperior") +_S("fivesuperior") +_S("sixsuperior") +_S("sevensuperior") +_S("eightsuperior") +_S("ninesuperior") +_S("zeroinferior") +_S("oneinferior") +_S("twoinferior") +_S("threeinferior") +_S("fourinferior") +_S("fiveinferior") +_S("sixinferior") +_S("seveninferior") +_S("eightinferior") +_S("nineinferior") +_S("centinferior") +_S("dollarinferior") +_S("periodinferior") +_S("commainferior") +_S("Agravesmall") +_S("Aacutesmall") +_S("Acircumflexsmall") +_S("Atildesmall") +_S("Adieresissmall") +_S("Aringsmall") +_S("AEsmall") +_S("Ccedillasmall") +_S("Egravesmall") +_S("Eacutesmall") +_S("Ecircumflexsmall") +_S("Edieresissmall") +_S("Igravesmall") +_S("Iacutesmall") +_S("Icircumflexsmall") +_S("Idieresissmall") +_S("Ethsmall") +_S("Ntildesmall") +_S("Ogravesmall") +_S("Oacutesmall") +_S("Ocircumflexsmall") +_S("Otildesmall") +_S("Odieresissmall") +_S("OEsmall") +_S("Oslashsmall") +_S("Ugravesmall") +_S("Uacutesmall") +_S("Ucircumflexsmall") +_S("Udieresissmall") +_S("Yacutesmall") +_S("Thornsmall") +_S("Ydieresissmall") +_S("001.000") +_S("001.001") +_S("001.002") +_S("001.003") +_S("Black") +_S("Bold") +_S("Book") +_S("Light") +_S("Medium") +_S("Regular") +_S("Roman") +_S("Semibold") + +#endif /* HB_OT_CFF1_STD_STR_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc index a5ee1f31f6f..24287364ba2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc @@ -24,11 +24,29 @@ * Adobe Author(s): Michiharu Ariza */ +#include "hb.hh" + +#ifndef HB_NO_CFF + +#include "hb-draw.hh" +#include "hb-algs.hh" #include "hb-ot-cff1-table.hh" #include "hb-cff1-interp-cs.hh" using namespace CFF; +struct sid_to_gid_t +{ + uint16_t sid; + uint8_t gid; + + int cmp (uint16_t a) const + { + if (a == sid) return 0; + return (a < sid) ? -1 : 1; + } +}; + /* SID to code */ static const uint8_t standard_encoding_to_code [] = { @@ -100,6 +118,80 @@ static const uint16_t expert_subset_charset_to_sid [] = 340, 341, 342, 343, 344, 345, 346 }; +/* SID to glyph ID */ +static const sid_to_gid_t expert_charset_sid_to_gid [] = +{ + { 1, 1 }, { 13, 12 }, { 14, 13 }, { 15, 14 }, + { 27, 26 }, { 28, 27 }, { 99, 15 }, { 109, 46 }, + { 110, 47 }, { 150, 111 }, { 155, 101 }, { 158, 100 }, + { 163, 102 }, { 164, 112 }, { 169, 113 }, { 229, 2 }, + { 230, 3 }, { 231, 4 }, { 232, 5 }, { 233, 6 }, + { 234, 7 }, { 235, 8 }, { 236, 9 }, { 237, 10 }, + { 238, 11 }, { 239, 16 }, { 240, 17 }, { 241, 18 }, + { 242, 19 }, { 243, 20 }, { 244, 21 }, { 245, 22 }, + { 246, 23 }, { 247, 24 }, { 248, 25 }, { 249, 28 }, + { 250, 29 }, { 251, 30 }, { 252, 31 }, { 253, 32 }, + { 254, 33 }, { 255, 34 }, { 256, 35 }, { 257, 36 }, + { 258, 37 }, { 259, 38 }, { 260, 39 }, { 261, 40 }, + { 262, 41 }, { 263, 42 }, { 264, 43 }, { 265, 44 }, + { 266, 45 }, { 267, 48 }, { 268, 49 }, { 269, 50 }, + { 270, 51 }, { 271, 52 }, { 272, 53 }, { 273, 54 }, + { 274, 55 }, { 275, 56 }, { 276, 57 }, { 277, 58 }, + { 278, 59 }, { 279, 60 }, { 280, 61 }, { 281, 62 }, + { 282, 63 }, { 283, 64 }, { 284, 65 }, { 285, 66 }, + { 286, 67 }, { 287, 68 }, { 288, 69 }, { 289, 70 }, + { 290, 71 }, { 291, 72 }, { 292, 73 }, { 293, 74 }, + { 294, 75 }, { 295, 76 }, { 296, 77 }, { 297, 78 }, + { 298, 79 }, { 299, 80 }, { 300, 81 }, { 301, 82 }, + { 302, 83 }, { 303, 84 }, { 304, 85 }, { 305, 86 }, + { 306, 87 }, { 307, 88 }, { 308, 89 }, { 309, 90 }, + { 310, 91 }, { 311, 92 }, { 312, 93 }, { 313, 94 }, + { 314, 95 }, { 315, 96 }, { 316, 97 }, { 317, 98 }, + { 318, 99 }, { 319, 103 }, { 320, 104 }, { 321, 105 }, + { 322, 106 }, { 323, 107 }, { 324, 108 }, { 325, 109 }, + { 326, 110 }, { 327, 114 }, { 328, 115 }, { 329, 116 }, + { 330, 117 }, { 331, 118 }, { 332, 119 }, { 333, 120 }, + { 334, 121 }, { 335, 122 }, { 336, 123 }, { 337, 124 }, + { 338, 125 }, { 339, 126 }, { 340, 127 }, { 341, 128 }, + { 342, 129 }, { 343, 130 }, { 344, 131 }, { 345, 132 }, + { 346, 133 }, { 347, 134 }, { 348, 135 }, { 349, 136 }, + { 350, 137 }, { 351, 138 }, { 352, 139 }, { 353, 140 }, + { 354, 141 }, { 355, 142 }, { 356, 143 }, { 357, 144 }, + { 358, 145 }, { 359, 146 }, { 360, 147 }, { 361, 148 }, + { 362, 149 }, { 363, 150 }, { 364, 151 }, { 365, 152 }, + { 366, 153 }, { 367, 154 }, { 368, 155 }, { 369, 156 }, + { 370, 157 }, { 371, 158 }, { 372, 159 }, { 373, 160 }, + { 374, 161 }, { 375, 162 }, { 376, 163 }, { 377, 164 }, + { 378, 165 } +}; + +/* SID to glyph ID */ +static const sid_to_gid_t expert_subset_charset_sid_to_gid [] = +{ + { 1, 1 }, { 13, 8 }, { 14, 9 }, { 15, 10 }, + { 27, 22 }, { 28, 23 }, { 99, 11 }, { 109, 41 }, + { 110, 42 }, { 150, 64 }, { 155, 55 }, { 158, 54 }, + { 163, 56 }, { 164, 65 }, { 169, 66 }, { 231, 2 }, + { 232, 3 }, { 235, 4 }, { 236, 5 }, { 237, 6 }, + { 238, 7 }, { 239, 12 }, { 240, 13 }, { 241, 14 }, + { 242, 15 }, { 243, 16 }, { 244, 17 }, { 245, 18 }, + { 246, 19 }, { 247, 20 }, { 248, 21 }, { 249, 24 }, + { 250, 25 }, { 251, 26 }, { 253, 27 }, { 254, 28 }, + { 255, 29 }, { 256, 30 }, { 257, 31 }, { 258, 32 }, + { 259, 33 }, { 260, 34 }, { 261, 35 }, { 262, 36 }, + { 263, 37 }, { 264, 38 }, { 265, 39 }, { 266, 40 }, + { 267, 43 }, { 268, 44 }, { 269, 45 }, { 270, 46 }, + { 272, 47 }, { 300, 48 }, { 301, 49 }, { 302, 50 }, + { 305, 51 }, { 314, 52 }, { 315, 53 }, { 320, 57 }, + { 321, 58 }, { 322, 59 }, { 323, 60 }, { 324, 61 }, + { 325, 62 }, { 326, 63 }, { 327, 67 }, { 328, 68 }, + { 329, 69 }, { 330, 70 }, { 331, 71 }, { 332, 72 }, + { 333, 73 }, { 334, 74 }, { 335, 75 }, { 336, 76 }, + { 337, 77 }, { 338, 78 }, { 339, 79 }, { 340, 80 }, + { 341, 81 }, { 342, 82 }, { 343, 83 }, { 344, 84 }, + { 345, 85 }, { 346, 86 } +}; + /* code to SID */ static const uint8_t standard_encoding_to_sid [] = { @@ -153,6 +245,18 @@ hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t gl return 0; } +hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph (hb_codepoint_t sid) +{ + const auto *pair = hb_sorted_array (expert_charset_sid_to_gid).bsearch (sid); + return pair ? pair->gid : 0; +} + +hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid) +{ + const auto *pair = hb_sorted_array (expert_subset_charset_sid_to_gid).bsearch (sid); + return pair ? pair->gid : 0; +} + hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code) { if (code < ARRAY_LENGTH (standard_encoding_to_sid)) @@ -165,8 +269,8 @@ struct bounds_t { void init () { - min.set_int (0x7FFFFFFF, 0x7FFFFFFF); - max.set_int (-0x80000000, -0x80000000); + min.set_int (INT_MAX, INT_MAX); + max.set_int (INT_MIN, INT_MIN); } void update (const point_t &pt) @@ -199,14 +303,13 @@ struct bounds_t } } - bool empty () const - { return (min.x >= max.x) || (min.y >= max.y); } + bool empty () const { return (min.x >= max.x) || (min.y >= max.y); } point_t min; point_t max; }; -struct extents_param_t +struct cff1_extents_param_t { void init (const OT::cff1::accelerator_t *_cff) { @@ -215,25 +318,25 @@ struct extents_param_t bounds.init (); } - void start_path () { path_open = true; } - void end_path () { path_open = false; } + void start_path () { path_open = true; } + void end_path () { path_open = false; } bool is_path_open () const { return path_open; } - bool path_open; - bounds_t bounds; + bool path_open; + bounds_t bounds; const OT::cff1::accelerator_t *cff; }; -struct cff1_path_procs_extents_t : path_procs_t +struct cff1_path_procs_extents_t : path_procs_t { - static void moveto (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt) + static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt) { param.end_path (); env.moveto (pt); } - static void line (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1) + static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1) { if (!param.is_path_open ()) { @@ -244,7 +347,7 @@ struct cff1_path_procs_extents_t : path_procs_t +struct cff1_cs_opset_extents_t : cff1_cs_opset_t { - static void process_seac (cff1_cs_interp_env_t &env, extents_param_t& param) + static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param) { unsigned int n = env.argStack.get_count (); point_t delta; @@ -292,20 +395,25 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; unsigned int fd = cff->fdSelect->get_fd (glyph); - cff1_cs_interpreter_t interp; + cff1_cs_interpreter_t interp; const byte_str_t str = (*cff->charStrings)[glyph]; interp.env.init (str, *cff, fd); interp.env.set_in_seac (in_seac); - extents_param_t param; + cff1_extents_param_t param; param.init (cff); if (unlikely (!interp.interpret (param))) return false; bounds = param.bounds; return true; } -bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const +bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { - bounds_t bounds; +#ifdef HB_NO_OT_FONT_CFF + /* XXX Remove check when this code moves to .hh file. */ + return true; +#endif + + bounds_t bounds; if (!_get_bounds (this, glyph, bounds)) return false; @@ -317,8 +425,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent } else { - extents->x_bearing = (int32_t)bounds.min.x.floor (); - extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ()); + extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ()); } if (bounds.min.y >= bounds.max.y) { @@ -327,13 +435,137 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent } else { - extents->y_bearing = (int32_t)bounds.max.y.ceil (); - extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ()); + extents->height = font->em_scalef_y (bounds.min.y.to_real () - bounds.max.y.to_real ()); } return true; } +#ifdef HB_EXPERIMENTAL_API +struct cff1_path_param_t +{ + cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_, + draw_helper_t &draw_helper_, point_t *delta_) + { + draw_helper = &draw_helper_; + cff = cff_; + font = font_; + delta = delta_; + } + + void move_to (const point_t &p) + { + point_t point = p; + if (delta) point.move (*delta); + draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ())); + } + + void line_to (const point_t &p) + { + point_t point = p; + if (delta) point.move (*delta); + draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ())); + } + + void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3) + { + point_t point1 = p1, point2 = p2, point3 = p3; + if (delta) + { + point1.move (*delta); + point2.move (*delta); + point3.move (*delta); + } + draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()), + font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()), + font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ())); + } + + void end_path () { draw_helper->end_path (); } + + hb_font_t *font; + draw_helper_t *draw_helper; + point_t *delta; + + const OT::cff1::accelerator_t *cff; +}; + +struct cff1_path_procs_path_t : path_procs_t +{ + static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt) + { + param.move_to (pt); + env.moveto (pt); + } + + static void line (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1) + { + param.line_to (pt1); + env.moveto (pt1); + } + + static void curve (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1, const point_t &pt2, const point_t &pt3) + { + param.cubic_to (pt1, pt2, pt3); + env.moveto (pt3); + } +}; + +static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, + draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr); + +struct cff1_cs_opset_path_t : cff1_cs_opset_t +{ + static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param) + { + /* End previous path */ + param.end_path (); + + unsigned int n = env.argStack.get_count (); + point_t delta; + delta.x = env.argStack[n-4]; + delta.y = env.argStack[n-3]; + hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ()); + hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ()); + + if (unlikely (!(!env.in_seac && base && accent + && _get_path (param.cff, param.font, base, *param.draw_helper, true) + && _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta)))) + env.set_error (); + } +}; + +bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, + draw_helper_t &draw_helper, bool in_seac, point_t *delta) +{ + if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; + + unsigned int fd = cff->fdSelect->get_fd (glyph); + cff1_cs_interpreter_t interp; + const byte_str_t str = (*cff->charStrings)[glyph]; + interp.env.init (str, *cff, fd); + interp.env.set_in_seac (in_seac); + cff1_path_param_t param (cff, font, draw_helper, delta); + if (unlikely (!interp.interpret (param))) return false; + + /* Let's end the path specially since it is called inside seac also */ + param.end_path (); + + return true; +} + +bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const +{ +#ifdef HB_NO_OT_FONT_CFF + /* XXX Remove check when this code moves to .hh file. */ + return true; +#endif + + return _get_path (this, font, glyph, draw_helper); +} +#endif + struct get_seac_param_t { void init (const OT::cff1::accelerator_t *_cff) @@ -383,3 +615,6 @@ bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_code } return false; } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh index 73258e79007..6768e4ea107 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh @@ -27,15 +27,21 @@ #ifndef HB_OT_CFF1_TABLE_HH #define HB_OT_CFF1_TABLE_HH -#include "hb-ot-head-table.hh" #include "hb-ot-cff-common.hh" #include "hb-subset-cff1.hh" +#include "hb-draw.hh" + +#define HB_STRING_ARRAY_NAME cff1_std_strings +#define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh" +#include "hb-string-array.hh" +#undef HB_STRING_ARRAY_LIST +#undef HB_STRING_ARRAY_NAME namespace CFF { /* * CFF -- Compact Font Format (CFF) - * http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf + * https://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf */ #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') @@ -49,7 +55,6 @@ template struct CFF1IndexOf : CFFIndexOf {}; typedef CFFIndex CFF1Index; typedef CFF1Index CFF1CharStrings; -typedef FDArray CFF1FDArray; typedef Subrs CFF1Subrs; struct CFF1FDSelect : FDSelect {}; @@ -59,14 +64,14 @@ struct Encoding0 { bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && codes[nCodes - 1].sanitize (c)); + return_trace (codes.sanitize (c)); } hb_codepoint_t get_code (hb_codepoint_t glyph) const { assert (glyph > 0); glyph--; - if (glyph < nCodes) + if (glyph < nCodes ()) { return (hb_codepoint_t)codes[glyph]; } @@ -74,13 +79,12 @@ struct Encoding0 { return CFF_UNDEF_CODE; } - unsigned int get_size () const - { return HBUINT8::static_size * (nCodes + 1); } + HBUINT8 &nCodes () { return codes.len; } + HBUINT8 nCodes () const { return codes.len; } - HBUINT8 nCodes; - HBUINT8 codes[VAR]; + ArrayOf codes; - DEFINE_SIZE_ARRAY(1, codes); + DEFINE_SIZE_ARRAY_SIZED (1, codes); }; struct Encoding1_Range { @@ -97,34 +101,34 @@ struct Encoding1_Range { }; struct Encoding1 { - unsigned int get_size () const - { return HBUINT8::static_size + Encoding1_Range::static_size * nRanges; } - bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c))); + return_trace (ranges.sanitize (c)); } hb_codepoint_t get_code (hb_codepoint_t glyph) const { assert (glyph > 0); glyph--; - for (unsigned int i = 0; i < nRanges; i++) + for (unsigned int i = 0; i < nRanges (); i++) { if (glyph <= ranges[i].nLeft) { - return (hb_codepoint_t)ranges[i].first + glyph; + hb_codepoint_t code = (hb_codepoint_t) ranges[i].first + glyph; + return (likely (code < 0x100) ? code: CFF_UNDEF_CODE); } glyph -= (ranges[i].nLeft + 1); } return CFF_UNDEF_CODE; } - HBUINT8 nRanges; - Encoding1_Range ranges[VAR]; + HBUINT8 &nRanges () { return ranges.len; } + HBUINT8 nRanges () const { return ranges.len; } + + ArrayOf ranges; - DEFINE_SIZE_ARRAY (1, ranges); + DEFINE_SIZE_ARRAY_SIZED (1, ranges); }; struct SuppEncoding { @@ -144,47 +148,33 @@ struct CFF1SuppEncData { bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (c->check_struct (this) && ((nSups == 0) || (supps[nSups - 1]).sanitize (c))); + return_trace (supps.sanitize (c)); } void get_codes (hb_codepoint_t sid, hb_vector_t &codes) const { - for (unsigned int i = 0; i < nSups; i++) + for (unsigned int i = 0; i < nSups (); i++) if (sid == supps[i].glyph) codes.push (supps[i].code); } - unsigned int get_size () const - { return HBUINT8::static_size + SuppEncoding::static_size * nSups; } + HBUINT8 &nSups () { return supps.len; } + HBUINT8 nSups () const { return supps.len; } - HBUINT8 nSups; - SuppEncoding supps[VAR]; + ArrayOf supps; - DEFINE_SIZE_ARRAY (1, supps); + DEFINE_SIZE_ARRAY_SIZED (1, supps); }; -struct Encoding { - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - - if (unlikely (!c->check_struct (this))) - return_trace (false); - unsigned int fmt = format & 0x7F; - if (unlikely (fmt > 1)) - return_trace (false); - if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c)))) - return_trace (false); - return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c)); - } - +struct Encoding +{ /* serialize a fullset Encoding */ bool serialize (hb_serialize_context_t *c, const Encoding &src) { TRACE_SERIALIZE (this); unsigned int size = src.get_size (); Encoding *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } @@ -198,72 +188,66 @@ struct Encoding { { TRACE_SERIALIZE (this); Encoding *dest = c->extend_min (*this); - if (unlikely (dest == nullptr)) return_trace (false); - dest->format.set (format | ((supp_codes.length > 0)? 0x80: 0)); - if (format == 0) + if (unlikely (!dest)) return_trace (false); + dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0); + switch (format) { + case 0: { Encoding0 *fmt0 = c->allocate_size (Encoding0::min_size + HBUINT8::static_size * enc_count); - if (unlikely (fmt0 == nullptr)) return_trace (false); - fmt0->nCodes.set (enc_count); + if (unlikely (!fmt0)) return_trace (false); + fmt0->nCodes () = enc_count; unsigned int glyph = 0; for (unsigned int i = 0; i < code_ranges.length; i++) { hb_codepoint_t code = code_ranges[i].code; for (int left = (int)code_ranges[i].glyph; left >= 0; left--) - fmt0->codes[glyph++].set (code++); + fmt0->codes[glyph++] = code++; if (unlikely (!((glyph <= 0x100) && (code <= 0x100)))) return_trace (false); } } - else + break; + + case 1: { Encoding1 *fmt1 = c->allocate_size (Encoding1::min_size + Encoding1_Range::static_size * code_ranges.length); - if (unlikely (fmt1 == nullptr)) return_trace (false); - fmt1->nRanges.set (code_ranges.length); + if (unlikely (!fmt1)) return_trace (false); + fmt1->nRanges () = code_ranges.length; for (unsigned int i = 0; i < code_ranges.length; i++) { if (unlikely (!((code_ranges[i].code <= 0xFF) && (code_ranges[i].glyph <= 0xFF)))) return_trace (false); - fmt1->ranges[i].first.set (code_ranges[i].code); - fmt1->ranges[i].nLeft.set (code_ranges[i].glyph); + fmt1->ranges[i].first = code_ranges[i].code; + fmt1->ranges[i].nLeft = code_ranges[i].glyph; } } - if (supp_codes.length > 0) + break; + + } + + if (supp_codes.length) { CFF1SuppEncData *suppData = c->allocate_size (CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_codes.length); - if (unlikely (suppData == nullptr)) return_trace (false); - suppData->nSups.set (supp_codes.length); + if (unlikely (!suppData)) return_trace (false); + suppData->nSups () = supp_codes.length; for (unsigned int i = 0; i < supp_codes.length; i++) { - suppData->supps[i].code.set (supp_codes[i].code); - suppData->supps[i].glyph.set (supp_codes[i].glyph); /* actually SID */ + suppData->supps[i].code = supp_codes[i].code; + suppData->supps[i].glyph = supp_codes[i].glyph; /* actually SID */ } } - return_trace (true); - } - /* parallel to above: calculate the size of a subset Encoding */ - static unsigned int calculate_serialized_size (uint8_t format, - unsigned int enc_count, - unsigned int supp_count) - { - unsigned int size = min_size; - if (format == 0) - size += Encoding0::min_size + HBUINT8::static_size * enc_count; - else - size += Encoding1::min_size + Encoding1_Range::static_size * enc_count; - if (supp_count > 0) - size += CFF1SuppEncData::min_size + SuppEncoding::static_size * supp_count; - return size; + return_trace (true); } unsigned int get_size () const { unsigned int size = min_size; - if (table_format () == 0) - size += u.format0.get_size (); - else - size += u.format1.get_size (); + switch (table_format ()) + { + case 0: size += u.format0.get_size (); break; + case 1: size += u.format1.get_size (); break; + } if (has_supplement ()) size += suppEncData ().get_size (); return size; @@ -271,14 +255,16 @@ struct Encoding { hb_codepoint_t get_code (hb_codepoint_t glyph) const { - if (table_format () == 0) - return u.format0.get_code (glyph); - else - return u.format1.get_code (glyph); + switch (table_format ()) + { + case 0: return u.format0.get_code (glyph); + case 1: return u.format1.get_code (glyph); + default:return 0; + } } - uint8_t table_format () const { return (format & 0x7F); } - bool has_supplement () const { return (format & 0x80) != 0; } + uint8_t table_format () const { return format & 0x7F; } + bool has_supplement () const { return format & 0x80; } void get_supplement_codes (hb_codepoint_t sid, hb_vector_t &codes) const { @@ -287,21 +273,37 @@ struct Encoding { suppEncData().get_codes (sid, codes); } + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + + switch (table_format ()) + { + case 0: if (unlikely (!u.format0.sanitize (c))) { return_trace (false); } break; + case 1: if (unlikely (!u.format1.sanitize (c))) { return_trace (false); } break; + default:return_trace (false); + } + return_trace (likely (!has_supplement () || suppEncData ().sanitize (c))); + } + protected: const CFF1SuppEncData &suppEncData () const { - if ((format & 0x7F) == 0) - return StructAfter (u.format0.codes[u.format0.nCodes-1]); - else - return StructAfter (u.format1.ranges[u.format1.nRanges-1]); + switch (table_format ()) + { + case 0: return StructAfter (u.format0.codes[u.format0.nCodes ()-1]); + case 1: return StructAfter (u.format1.ranges[u.format1.nRanges ()-1]); + default:return Null (CFF1SuppEncData); + } } public: HBUINT8 format; - union { - Encoding0 format0; - Encoding1 format1; + Encoding0 format0; + Encoding1 format1; } u; /* CFF1SuppEncData suppEncData; */ @@ -343,7 +345,7 @@ struct Charset0 { return HBUINT16::static_size * (num_glyphs - 1); } - HBUINT16 sids[VAR]; + HBUINT16 sids[HB_VAR_ARRAY]; DEFINE_SIZE_ARRAY(0, sids); }; @@ -425,7 +427,7 @@ struct Charset1_2 { return size; } - Charset_Range ranges[VAR]; + Charset_Range ranges[HB_VAR_ARRAY]; DEFINE_SIZE_ARRAY (0, ranges); }; @@ -435,30 +437,15 @@ typedef Charset1_2 Charset2; typedef Charset_Range Charset1_Range; typedef Charset_Range Charset2_Range; -struct Charset { - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - - if (unlikely (!c->check_struct (this))) - return_trace (false); - if (format == 0) - return_trace (u.format0.sanitize (c, c->get_num_glyphs ())); - else if (format == 1) - return_trace (u.format1.sanitize (c, c->get_num_glyphs ())); - else if (likely (format == 2)) - return_trace (u.format2.sanitize (c, c->get_num_glyphs ())); - else - return_trace (false); - } - +struct Charset +{ /* serialize a fullset Charset */ bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs) { TRACE_SERIALIZE (this); unsigned int size = src.get_size (num_glyphs); Charset *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } @@ -471,93 +458,103 @@ struct Charset { { TRACE_SERIALIZE (this); Charset *dest = c->extend_min (*this); - if (unlikely (dest == nullptr)) return_trace (false); - dest->format.set (format); - if (format == 0) + if (unlikely (!dest)) return_trace (false); + dest->format = format; + switch (format) + { + case 0: { Charset0 *fmt0 = c->allocate_size (Charset0::min_size + HBUINT16::static_size * (num_glyphs - 1)); - if (unlikely (fmt0 == nullptr)) return_trace (false); + if (unlikely (!fmt0)) return_trace (false); unsigned int glyph = 0; for (unsigned int i = 0; i < sid_ranges.length; i++) { hb_codepoint_t sid = sid_ranges[i].code; for (int left = (int)sid_ranges[i].glyph; left >= 0; left--) - fmt0->sids[glyph++].set (sid++); + fmt0->sids[glyph++] = sid++; } } - else if (format == 1) + break; + + case 1: { Charset1 *fmt1 = c->allocate_size (Charset1::min_size + Charset1_Range::static_size * sid_ranges.length); - if (unlikely (fmt1 == nullptr)) return_trace (false); + if (unlikely (!fmt1)) return_trace (false); for (unsigned int i = 0; i < sid_ranges.length; i++) { if (unlikely (!(sid_ranges[i].glyph <= 0xFF))) return_trace (false); - fmt1->ranges[i].first.set (sid_ranges[i].code); - fmt1->ranges[i].nLeft.set (sid_ranges[i].glyph); + fmt1->ranges[i].first = sid_ranges[i].code; + fmt1->ranges[i].nLeft = sid_ranges[i].glyph; } } - else /* format 2 */ + break; + + case 2: { Charset2 *fmt2 = c->allocate_size (Charset2::min_size + Charset2_Range::static_size * sid_ranges.length); - if (unlikely (fmt2 == nullptr)) return_trace (false); + if (unlikely (!fmt2)) return_trace (false); for (unsigned int i = 0; i < sid_ranges.length; i++) { if (unlikely (!(sid_ranges[i].glyph <= 0xFFFF))) return_trace (false); - fmt2->ranges[i].first.set (sid_ranges[i].code); - fmt2->ranges[i].nLeft.set (sid_ranges[i].glyph); + fmt2->ranges[i].first = sid_ranges[i].code; + fmt2->ranges[i].nLeft = sid_ranges[i].glyph; } + } + break; + } return_trace (true); } - /* parallel to above: calculate the size of a subset Charset */ - static unsigned int calculate_serialized_size ( - uint8_t format, - unsigned int count) + unsigned int get_size (unsigned int num_glyphs) const { - unsigned int size = min_size; - if (format == 0) - size += Charset0::min_size + HBUINT16::static_size * (count - 1); - else if (format == 1) - size += Charset1::min_size + Charset1_Range::static_size * count; - else - size += Charset2::min_size + Charset2_Range::static_size * count; - - return size; + switch (format) + { + case 0: return min_size + u.format0.get_size (num_glyphs); + case 1: return min_size + u.format1.get_size (num_glyphs); + case 2: return min_size + u.format2.get_size (num_glyphs); + default:return 0; + } } - unsigned int get_size (unsigned int num_glyphs) const + hb_codepoint_t get_sid (hb_codepoint_t glyph, unsigned int num_glyphs) const { - unsigned int size = min_size; - if (format == 0) - size += u.format0.get_size (num_glyphs); - else if (format == 1) - size += u.format1.get_size (num_glyphs); - else - size += u.format2.get_size (num_glyphs); - return size; + if (unlikely (glyph >= num_glyphs)) return 0; + switch (format) + { + case 0: return u.format0.get_sid (glyph); + case 1: return u.format1.get_sid (glyph); + case 2: return u.format2.get_sid (glyph); + default:return 0; + } } - hb_codepoint_t get_sid (hb_codepoint_t glyph) const + hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const { - if (format == 0) - return u.format0.get_sid (glyph); - else if (format == 1) - return u.format1.get_sid (glyph); - else - return u.format2.get_sid (glyph); + switch (format) + { + case 0: return u.format0.get_glyph (sid, num_glyphs); + case 1: return u.format1.get_glyph (sid, num_glyphs); + case 2: return u.format2.get_glyph (sid, num_glyphs); + default:return 0; + } } - hb_codepoint_t get_glyph (hb_codepoint_t sid, unsigned int num_glyphs) const + bool sanitize (hb_sanitize_context_t *c) const { - if (format == 0) - return u.format0.get_glyph (sid, num_glyphs); - else if (format == 1) - return u.format1.get_glyph (sid, num_glyphs); - else - return u.format2.get_glyph (sid, num_glyphs); + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + + switch (format) + { + case 0: return_trace (u.format0.sanitize (c, c->get_num_glyphs ())); + case 1: return_trace (u.format1.sanitize (c, c->get_num_glyphs ())); + case 2: return_trace (u.format2.sanitize (c, c->get_num_glyphs ())); + default:return_trace (false); + } } HBUINT8 format; @@ -573,48 +570,32 @@ struct Charset { struct CFF1StringIndex : CFF1Index { bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, - unsigned int offSize_, const remap_t &sidmap) + const hb_inc_bimap_t &sidmap) { TRACE_SERIALIZE (this); - if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0))) + if (unlikely ((strings.count == 0) || (sidmap.get_population () == 0))) { - if (!unlikely (c->extend_min (this->count))) + if (unlikely (!c->extend_min (this->count))) return_trace (false); - count.set (0); + count = 0; return_trace (true); } byte_str_array_t bytesArray; bytesArray.init (); - if (!bytesArray.resize (sidmap.get_count ())) + if (!bytesArray.resize (sidmap.get_population ())) return_trace (false); for (unsigned int i = 0; i < strings.count; i++) { hb_codepoint_t j = sidmap[i]; - if (j != CFF_UNDEF_CODE) + if (j != HB_MAP_VALUE_INVALID) bytesArray[j] = strings[i]; } - bool result = CFF1Index::serialize (c, offSize_, bytesArray); + bool result = CFF1Index::serialize (c, bytesArray); bytesArray.fini (); return_trace (result); } - - /* in parallel to above */ - unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const remap_t &sidmap) const - { - offSize = 0; - if ((count == 0) || (sidmap.get_count () == 0)) - return count.static_size; - - unsigned int dataSize = 0; - for (unsigned int i = 0; i < count; i++) - if (sidmap[i] != CFF_UNDEF_CODE) - dataSize += length_at (i); - - offSize = calcOffSize(dataSize); - return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize); - } }; struct cff1_top_dict_interp_env_t : num_interp_env_t @@ -717,7 +698,7 @@ struct cff1_top_dict_values_t : top_dict_values_t unsigned int EncodingOffset; unsigned int CharsetOffset; unsigned int FDSelectOffset; - table_info_t privateDictInfo; + table_info_t privateDictInfo; }; struct cff1_top_dict_opset_t : top_dict_opset_t @@ -859,21 +840,10 @@ struct cff1_private_dict_values_base_t : dict_values_t { dict_values_t::init (); subrsOffset = 0; - localSubrs = &Null(CFF1Subrs); + localSubrs = &Null (CFF1Subrs); } void fini () { dict_values_t::fini (); } - unsigned int calculate_serialized_size () const - { - unsigned int size = 0; - for (unsigned int i = 0; i < dict_values_t::get_count; i++) - if (dict_values_t::get_value (i).op == OpCode_Subrs) - size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); - else - size += dict_values_t::get_value (i).str.length; - return size; - } - unsigned int subrsOffset; const CFF1Subrs *localSubrs; }; @@ -976,6 +946,37 @@ typedef dict_interpreter_t cff1 typedef CFF1Index CFF1NameIndex; typedef CFF1IndexOf CFF1TopDictIndex; +struct cff1_font_dict_values_mod_t +{ + cff1_font_dict_values_mod_t() { init (); } + + void init () { init ( &Null (cff1_font_dict_values_t), CFF_UNDEF_SID ); } + + void init (const cff1_font_dict_values_t *base_, + unsigned int fontName_) + { + base = base_; + fontName = fontName_; + privateDictInfo.init (); + } + + unsigned get_count () const { return base->get_count (); } + + const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; } + + const cff1_font_dict_values_t *base; + table_info_t privateDictInfo; + unsigned int fontName; +}; + +struct CFF1FDArray : FDArray +{ + /* FDArray::serialize() requires this partial specialization to compile */ + template + bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr) + { return FDArray::serialize (c, it, opszr); } +}; + } /* namespace CFF */ namespace OT { @@ -1010,7 +1011,7 @@ struct cff1 const OT::cff1 *cff = this->blob->template as (); - if (cff == &Null(OT::cff1)) + if (cff == &Null (OT::cff1)) { fini (); return; } nameIndex = &cff->nameIndex (cff); @@ -1031,7 +1032,7 @@ struct cff1 } if (is_predef_charset ()) - charset = &Null(Charset); + charset = &Null (Charset); else { charset = &StructAtOffsetOrNull (cff, topDict.CharsetOffset); @@ -1043,16 +1044,30 @@ struct cff1 { fdArray = &StructAtOffsetOrNull (cff, topDict.FDArrayOffset); fdSelect = &StructAtOffsetOrNull (cff, topDict.FDSelectOffset); - if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) || - (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) + if (unlikely ((fdArray == &Null (CFF1FDArray)) || !fdArray->sanitize (&sc) || + (fdSelect == &Null (CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) { fini (); return; } fdCount = fdArray->count; } else { - fdArray = &Null(CFF1FDArray); - fdSelect = &Null(CFF1FDSelect); + fdArray = &Null (CFF1FDArray); + fdSelect = &Null (CFF1FDSelect); + } + + encoding = &Null (Encoding); + if (is_CID ()) + { + if (unlikely (charset == &Null (Charset))) { fini (); return; } + } + else + { + if (!is_predef_encoding ()) + { + encoding = &StructAtOffsetOrNull (cff, topDict.EncodingOffset); + if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } + } } stringIndex = &StructAtOffset (topDictIndex, topDictIndex->get_size ()); @@ -1065,14 +1080,15 @@ struct cff1 charStrings = &StructAtOffsetOrNull (cff, topDict.charStringsOffset); - if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) + if ((charStrings == &Null (CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) { fini (); return; } num_glyphs = charStrings->count; if (num_glyphs != sc.get_num_glyphs ()) { fini (); return; } - privateDicts.resize (fdCount); + if (unlikely (!privateDicts.resize (fdCount))) + { fini (); return; } for (unsigned int i = 0; i < fdCount; i++) privateDicts[i].init (); @@ -1083,14 +1099,14 @@ struct cff1 { byte_str_t fontDictStr = (*fdArray)[i]; if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } - cff1_font_dict_values_t *font; + cff1_font_dict_values_t *font; cff1_font_dict_interpreter_t font_interp; font_interp.env.init (fontDictStr); font = fontDicts.push (); - if (unlikely (font == &Crap(cff1_font_dict_values_t))) { fini (); return; } + if (unlikely (font == &Crap (cff1_font_dict_values_t))) { fini (); return; } font->init (); if (unlikely (!font_interp.interpret (*font))) { fini (); return; } - PRIVDICTVAL *priv = &privateDicts[i]; + PRIVDICTVAL *priv = &privateDicts[i]; const byte_str_t privDictStr (StructAtOffset (cff, font->privateDictInfo.offset), font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } dict_interpreter_t priv_interp; @@ -1099,15 +1115,15 @@ struct cff1 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset); - if (priv->localSubrs != &Null(CFF1Subrs) && + if (priv->localSubrs != &Null (CFF1Subrs) && unlikely (!priv->localSubrs->sanitize (&sc))) { fini (); return; } } } else /* non-CID */ { - cff1_top_dict_values_t *font = &topDict; - PRIVDICTVAL *priv = &privateDicts[0]; + cff1_top_dict_values_t *font = &topDict; + PRIVDICTVAL *priv = &privateDicts[0]; const byte_str_t privDictStr (StructAtOffset (cff, font->privateDictInfo.offset), font->privateDictInfo.size); if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } @@ -1117,7 +1133,7 @@ struct cff1 if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; } priv->localSubrs = &StructAtOffsetOrNull (&privDictStr, priv->subrsOffset); - if (priv->localSubrs != &Null(CFF1Subrs) && + if (priv->localSubrs != &Null (CFF1Subrs) && unlikely (!priv->localSubrs->sanitize (&sc))) { fini (); return; } } @@ -1133,8 +1149,8 @@ struct cff1 blob = nullptr; } - bool is_valid () const { return blob != nullptr; } - bool is_CID () const { return topDict.is_CID (); } + bool is_valid () const { return blob; } + bool is_CID () const { return topDict.is_CID (); } bool is_predef_charset () const { return topDict.CharsetOffset <= ExpertSubsetCharset; } @@ -1144,144 +1160,232 @@ struct cff1 if (unlikely (sid == CFF_UNDEF_SID)) return 0; - if (charset != &Null(Charset)) + if (charset != &Null (Charset)) return charset->get_glyph (sid, num_glyphs); else if ((topDict.CharsetOffset == ISOAdobeCharset) && (code <= 228 /*zcaron*/)) return sid; return 0; } - protected: - hb_blob_t *blob; - hb_sanitize_context_t sc; - - public: - const Charset *charset; - const CFF1NameIndex *nameIndex; - const CFF1TopDictIndex *topDictIndex; - const CFF1StringIndex *stringIndex; - const CFF1Subrs *globalSubrs; - const CFF1CharStrings *charStrings; - const CFF1FDArray *fdArray; - const CFF1FDSelect *fdSelect; - unsigned int fdCount; - - cff1_top_dict_values_t topDict; - hb_vector_t fontDicts; - hb_vector_t privateDicts; - - unsigned int num_glyphs; - }; - - struct accelerator_t : accelerator_templ_t - { - HB_INTERNAL bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; - HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; - }; + bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } - struct accelerator_subset_t : accelerator_templ_t - { - void init (hb_face_t *face) + hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const { - SUPER::init (face); - if (blob == nullptr) return; - - const OT::cff1 *cff = this->blob->as (); - encoding = &Null(Encoding); - if (is_CID ()) - { - if (unlikely (charset == &Null(Charset))) { fini (); return; } - } + if (encoding != &Null (Encoding)) + return encoding->get_code (glyph); else { - if (!is_predef_encoding ()) + hb_codepoint_t sid = glyph_to_sid (glyph); + if (sid == 0) return 0; + hb_codepoint_t code = 0; + switch (topDict.EncodingOffset) { - encoding = &StructAtOffsetOrNull (cff, topDict.EncodingOffset); - if (unlikely ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))) { fini (); return; } + case StandardEncoding: + code = lookup_standard_encoding_for_code (sid); + break; + case ExpertEncoding: + code = lookup_expert_encoding_for_code (sid); + break; + default: + break; } + return code; } } - bool is_predef_encoding () const { return topDict.EncodingOffset <= ExpertEncoding; } - - hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const + hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const { - if (encoding != &Null(Encoding)) - return encoding->get_code (glyph); + if (charset != &Null (Charset)) + return charset->get_sid (glyph, num_glyphs); else { - hb_codepoint_t sid = glyph_to_sid (glyph); - if (sid == 0) return 0; - hb_codepoint_t code = 0; - switch (topDict.EncodingOffset) + hb_codepoint_t sid = 0; + switch (topDict.CharsetOffset) { - case StandardEncoding: - code = lookup_standard_encoding_for_code (sid); + case ISOAdobeCharset: + if (glyph <= 228 /*zcaron*/) sid = glyph; + break; + case ExpertCharset: + sid = lookup_expert_charset_for_sid (glyph); break; - case ExpertEncoding: - code = lookup_expert_encoding_for_code (sid); + case ExpertSubsetCharset: + sid = lookup_expert_subset_charset_for_sid (glyph); break; default: break; } - return code; + return sid; } } - hb_codepoint_t glyph_to_sid (hb_codepoint_t glyph) const + hb_codepoint_t sid_to_glyph (hb_codepoint_t sid) const { - if (charset != &Null(Charset)) - return charset->get_sid (glyph); + if (charset != &Null (Charset)) + return charset->get_glyph (sid, num_glyphs); else { - hb_codepoint_t sid = 0; + hb_codepoint_t glyph = 0; switch (topDict.CharsetOffset) { - case ISOAdobeCharset: - if (glyph <= 228 /*zcaron*/) sid = glyph; + case ISOAdobeCharset: + if (sid <= 228 /*zcaron*/) glyph = sid; break; - case ExpertCharset: - sid = lookup_expert_charset_for_sid (glyph); + case ExpertCharset: + glyph = lookup_expert_charset_for_glyph (sid); break; - case ExpertSubsetCharset: - sid = lookup_expert_subset_charset_for_sid (glyph); + case ExpertSubsetCharset: + glyph = lookup_expert_subset_charset_for_glyph (sid); break; default: break; } - return sid; + return glyph; } } - const Encoding *encoding; + protected: + hb_blob_t *blob; + hb_sanitize_context_t sc; - private: - typedef accelerator_templ_t SUPER; + public: + const Encoding *encoding; + const Charset *charset; + const CFF1NameIndex *nameIndex; + const CFF1TopDictIndex *topDictIndex; + const CFF1StringIndex *stringIndex; + const CFF1Subrs *globalSubrs; + const CFF1CharStrings *charStrings; + const CFF1FDArray *fdArray; + const CFF1FDSelect *fdSelect; + unsigned int fdCount; + + cff1_top_dict_values_t topDict; + hb_vector_t + fontDicts; + hb_vector_t privateDicts; + + unsigned int num_glyphs; }; - bool subset (hb_subset_plan_t *plan) const + struct accelerator_t : accelerator_templ_t { - hb_blob_t *cff_prime = nullptr; - - bool success = true; - if (hb_subset_cff1 (plan, &cff_prime)) { - success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime); - hb_blob_t *head_blob = hb_sanitize_context_t().reference_table (plan->source); - success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob); - hb_blob_destroy (head_blob); - } else { - success = false; + void init (hb_face_t *face) + { + SUPER::init (face); + + if (!is_valid ()) return; + if (is_CID ()) return; + + /* fill glyph_names */ + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t sid = glyph_to_sid (gid); + gname_t gname; + gname.sid = sid; + if (sid < cff1_std_strings_length) + gname.name = cff1_std_strings (sid); + else + { + byte_str_t ustr = (*stringIndex)[sid - cff1_std_strings_length]; + gname.name = hb_bytes_t ((const char*)ustr.arrayZ, ustr.length); + } + if (unlikely (!gname.name.arrayZ)) { fini (); return; } + glyph_names.push (gname); + } + glyph_names.qsort (); } - hb_blob_destroy (cff_prime); - return success; - } + void fini () + { + glyph_names.fini (); + + SUPER::fini (); + } + + bool get_glyph_name (hb_codepoint_t glyph, + char *buf, unsigned int buf_len) const + { + if (!buf) return true; + if (unlikely (!is_valid ())) return false; + if (is_CID()) return false; + hb_codepoint_t sid = glyph_to_sid (glyph); + const char *str; + size_t str_len; + if (sid < cff1_std_strings_length) + { + hb_bytes_t byte_str = cff1_std_strings (sid); + str = byte_str.arrayZ; + str_len = byte_str.length; + } + else + { + byte_str_t ubyte_str = (*stringIndex)[sid - cff1_std_strings_length]; + str = (const char *)ubyte_str.arrayZ; + str_len = ubyte_str.length; + } + if (!str_len) return false; + unsigned int len = hb_min (buf_len - 1, str_len); + strncpy (buf, (const char*)str, len); + buf[len] = '\0'; + return true; + } + + bool get_glyph_from_name (const char *name, int len, + hb_codepoint_t *glyph) const + { + if (len < 0) len = strlen (name); + if (unlikely (!len)) return false; + + gname_t key = { hb_bytes_t (name, len), 0 }; + const gname_t *gname = glyph_names.bsearch (key); + if (!gname) return false; + hb_codepoint_t gid = sid_to_glyph (gname->sid); + if (!gid && gname->sid) return false; + *glyph = gid; + return true; + } + + HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; +#ifdef HB_EXPERIMENTAL_API + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const; +#endif + + private: + struct gname_t + { + hb_bytes_t name; + uint16_t sid; + + static int cmp (const void *a_, const void *b_) + { + const gname_t *a = (const gname_t *)a_; + const gname_t *b = (const gname_t *)b_; + int minlen = hb_min (a->name.length, b->name.length); + int ret = strncmp (a->name.arrayZ, b->name.arrayZ, minlen); + if (ret) return ret; + return a->name.length - b->name.length; + } + + int cmp (const gname_t &a) const { return cmp (&a, this); } + }; + + hb_sorted_vector_t glyph_names; + + typedef accelerator_templ_t SUPER; + }; + + struct accelerator_subset_t : accelerator_templ_t {}; + + bool subset (hb_subset_context_t *c) const { return hb_subset_cff1 (c); } protected: HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_code (hb_codepoint_t sid); HB_INTERNAL static hb_codepoint_t lookup_expert_encoding_for_code (hb_codepoint_t sid); HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_sid (hb_codepoint_t glyph); HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_sid (hb_codepoint_t glyph); + HB_INTERNAL static hb_codepoint_t lookup_expert_charset_for_glyph (hb_codepoint_t sid); + HB_INTERNAL static hb_codepoint_t lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid); HB_INTERNAL static hb_codepoint_t lookup_standard_encoding_for_sid (hb_codepoint_t code); public: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc index 45eb8bd2761..56f331ed447 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc @@ -24,24 +24,29 @@ * Adobe Author(s): Michiharu Ariza */ +#include "hb.hh" + +#ifndef HB_NO_OT_FONT_CFF + #include "hb-ot-cff2-table.hh" #include "hb-cff2-interp-cs.hh" +#include "hb-draw.hh" using namespace CFF; -struct extents_param_t +struct cff2_extents_param_t { void init () { path_open = false; - min_x.set_int (0x7FFFFFFF); - min_y.set_int (0x7FFFFFFF); - max_x.set_int (-0x80000000); - max_y.set_int (-0x80000000); + min_x.set_int (INT_MAX); + min_y.set_int (INT_MAX); + max_x.set_int (INT_MIN); + max_y.set_int (INT_MIN); } - void start_path () { path_open = true; } - void end_path () { path_open = false; } + void start_path () { path_open = true; } + void end_path () { path_open = false; } bool is_path_open () const { return path_open; } void update_bounds (const point_t &pt) @@ -59,15 +64,15 @@ struct extents_param_t number_t max_y; }; -struct cff2_path_procs_extents_t : path_procs_t +struct cff2_path_procs_extents_t : path_procs_t { - static void moveto (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt) + static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt) { param.end_path (); env.moveto (pt); } - static void line (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1) + static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1) { if (!param.is_path_open ()) { @@ -78,7 +83,7 @@ struct cff2_path_procs_extents_t : path_procs_t {}; +struct cff2_cs_opset_extents_t : cff2_cs_opset_t {}; bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { +#ifdef HB_NO_OT_FONT_CFF + /* XXX Remove check when this code moves to .hh file. */ + return true; +#endif + if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; - unsigned int num_coords; - const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); unsigned int fd = fdSelect->get_fd (glyph); - cff2_cs_interpreter_t interp; + cff2_cs_interpreter_t interp; const byte_str_t str = (*charStrings)[glyph]; - interp.env.init (str, *this, fd, coords, num_coords); - extents_param_t param; + interp.env.init (str, *this, fd, font->coords, font->num_coords); + cff2_extents_param_t param; param.init (); if (unlikely (!interp.interpret (param))) return false; @@ -118,8 +126,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->x_bearing = (int32_t)param.min_x.floor (); - extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing; + extents->x_bearing = font->em_scalef_x (param.min_x.to_real ()); + extents->width = font->em_scalef_x (param.max_x.to_real () - param.min_x.to_real ()); } if (param.min_y >= param.max_y) { @@ -128,9 +136,80 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->y_bearing = (int32_t)param.max_y.ceil (); - extents->height = (int32_t)param.min_y.floor () - extents->y_bearing; + extents->y_bearing = font->em_scalef_y (param.max_y.to_real ()); + extents->height = font->em_scalef_y (param.min_y.to_real () - param.max_y.to_real ()); + } + + return true; +} + +#ifdef HB_EXPERIMENTAL_API +struct cff2_path_param_t +{ + cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_) + { + draw_helper = &draw_helper_; + font = font_; + } + + void move_to (const point_t &p) + { draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); } + + void line_to (const point_t &p) + { draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); } + + void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3) + { + draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()), + font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()), + font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ())); + } + + protected: + draw_helper_t *draw_helper; + hb_font_t *font; +}; + +struct cff2_path_procs_path_t : path_procs_t +{ + static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt) + { + param.move_to (pt); + env.moveto (pt); + } + + static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1) + { + param.line_to (pt1); + env.moveto (pt1); } + static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3) + { + param.cubic_to (pt1, pt2, pt3); + env.moveto (pt3); + } +}; + +struct cff2_cs_opset_path_t : cff2_cs_opset_t {}; + +bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const +{ +#ifdef HB_NO_OT_FONT_CFF + /* XXX Remove check when this code moves to .hh file. */ + return true; +#endif + + if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false; + + unsigned int fd = fdSelect->get_fd (glyph); + cff2_cs_interpreter_t interp; + const byte_str_t str = (*charStrings)[glyph]; + interp.env.init (str, *this, fd, font->coords, font->num_coords); + cff2_path_param_t param (font, draw_helper); + if (unlikely (!interp.interpret (param))) return false; return true; } +#endif + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh index 8111d503844..90c0b5b9cf6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh @@ -27,9 +27,9 @@ #ifndef HB_OT_CFF2_TABLE_HH #define HB_OT_CFF2_TABLE_HH -#include "hb-ot-head-table.hh" #include "hb-ot-cff-common.hh" #include "hb-subset-cff2.hh" +#include "hb-draw.hh" namespace CFF { @@ -43,7 +43,6 @@ typedef CFFIndex CFF2Index; template struct CFF2IndexOf : CFFIndexOf {}; typedef CFF2Index CFF2CharStrings; -typedef FDArray CFF2FDArray; typedef Subrs CFF2Subrs; typedef FDSelect3_4 FDSelect4; @@ -51,62 +50,63 @@ typedef FDSelect3_4_Range FDSelect4_Range; struct CFF2FDSelect { - bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const - { - TRACE_SANITIZE (this); - - return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) && - (format == 0)? - u.format0.sanitize (c, fdcount): - ((format == 3)? - u.format3.sanitize (c, fdcount): - u.format4.sanitize (c, fdcount)))); - } - bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs) { TRACE_SERIALIZE (this); unsigned int size = src.get_size (num_glyphs); CFF2FDSelect *dest = c->allocate_size (size); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, &src, size); return_trace (true); } - unsigned int calculate_serialized_size (unsigned int num_glyphs) const - { return get_size (num_glyphs); } - unsigned int get_size (unsigned int num_glyphs) const { - unsigned int size = format.static_size; - if (format == 0) - size += u.format0.get_size (num_glyphs); - else if (format == 3) - size += u.format3.get_size (); - else - size += u.format4.get_size (); - return size; + switch (format) + { + case 0: return format.static_size + u.format0.get_size (num_glyphs); + case 3: return format.static_size + u.format3.get_size (); + case 4: return format.static_size + u.format4.get_size (); + default:return 0; + } } hb_codepoint_t get_fd (hb_codepoint_t glyph) const { - if (this == &Null(CFF2FDSelect)) + if (this == &Null (CFF2FDSelect)) return 0; - if (format == 0) - return u.format0.get_fd (glyph); - else if (format == 3) - return u.format3.get_fd (glyph); - else - return u.format4.get_fd (glyph); + + switch (format) + { + case 0: return u.format0.get_fd (glyph); + case 3: return u.format3.get_fd (glyph); + case 4: return u.format4.get_fd (glyph); + default:return 0; + } + } + + bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const + { + TRACE_SANITIZE (this); + if (unlikely (!c->check_struct (this))) + return_trace (false); + + switch (format) + { + case 0: return_trace (u.format0.sanitize (c, fdcount)); + case 3: return_trace (u.format3.sanitize (c, fdcount)); + case 4: return_trace (u.format4.sanitize (c, fdcount)); + default:return_trace (false); + } } HBUINT8 format; union { - FDSelect0 format0; - FDSelect3 format3; - FDSelect4 format4; + FDSelect0 format0; + FDSelect3 format3; + FDSelect4 format4; } u; - + public: DEFINE_SIZE_MIN (2); }; @@ -123,7 +123,7 @@ struct CFF2VariationStore TRACE_SERIALIZE (this); unsigned int size_ = varStore->get_size (); CFF2VariationStore *dest = c->allocate_size (size_); - if (unlikely (dest == nullptr)) return_trace (false); + if (unlikely (!dest)) return_trace (false); memcpy (dest, varStore, size_); return_trace (true); } @@ -146,26 +146,6 @@ struct cff2_top_dict_values_t : top_dict_values_t<> } void fini () { top_dict_values_t<>::fini (); } - unsigned int calculate_serialized_size () const - { - unsigned int size = 0; - for (unsigned int i = 0; i < get_count (); i++) - { - op_code_t op = get_value (i).op; - switch (op) - { - case OpCode_vstore: - case OpCode_FDSelect: - size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); - break; - default: - size += top_dict_values_t<>::calculate_serialized_op_size (get_value (i)); - break; - } - } - return size; - } - unsigned int vstoreOffset; unsigned int FDSelectOffset; }; @@ -252,22 +232,11 @@ struct cff2_private_dict_values_base_t : dict_values_t { dict_values_t::init (); subrsOffset = 0; - localSubrs = &Null(CFF2Subrs); + localSubrs = &Null (CFF2Subrs); ivs = 0; } void fini () { dict_values_t::fini (); } - unsigned int calculate_serialized_size () const - { - unsigned int size = 0; - for (unsigned int i = 0; i < dict_values_t::get_count; i++) - if (dict_values_t::get_value (i).op == OpCode_Subrs) - size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs); - else - size += dict_values_t::get_value (i).str.length; - return size; - } - unsigned int subrsOffset; const CFF2Subrs *localSubrs; unsigned int ivs; @@ -400,6 +369,14 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t typedef dict_interpreter_t cff2_top_dict_interpreter_t; typedef dict_interpreter_t cff2_font_dict_interpreter_t; +struct CFF2FDArray : FDArray +{ + /* FDArray::serialize does not compile without this partial specialization */ + template + bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr) + { return FDArray::serialize (c, it, opszr); } +}; + } /* namespace CFF */ namespace OT { @@ -434,7 +411,7 @@ struct cff2 const OT::cff2 *cff2 = this->blob->template as (); - if (cff2 == &Null(OT::cff2)) + if (cff2 == &Null (OT::cff2)) { fini (); return; } { /* parse top dict */ @@ -452,11 +429,11 @@ struct cff2 fdArray = &StructAtOffsetOrNull (cff2, topDict.FDArrayOffset); fdSelect = &StructAtOffsetOrNull (cff2, topDict.FDSelectOffset); - if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) || - (charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) || - (globalSubrs == &Null(CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || - (fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) || - (((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))) + if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) || + (charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) || + (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || + (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) || + (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))) { fini (); return; } num_glyphs = charStrings->count; @@ -464,7 +441,8 @@ struct cff2 { fini (); return; } fdCount = fdArray->count; - privateDicts.resize (fdCount); + if (!privateDicts.resize (fdCount)) + { fini (); return; } /* parse font dicts and gather private dicts */ for (unsigned int i = 0; i < fdCount; i++) @@ -475,7 +453,7 @@ struct cff2 cff2_font_dict_interpreter_t font_interp; font_interp.env.init (fontDictStr); font = fontDicts.push (); - if (unlikely (font == &Crap(cff2_font_dict_values_t))) { fini (); return; } + if (unlikely (font == &Crap (cff2_font_dict_values_t))) { fini (); return; } font->init (); if (unlikely (!font_interp.interpret (*font))) { fini (); return; } @@ -487,7 +465,7 @@ struct cff2 if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; } privateDicts[i].localSubrs = &StructAtOffsetOrNull (&privDictStr[0], privateDicts[i].subrsOffset); - if (privateDicts[i].localSubrs != &Null(CFF2Subrs) && + if (privateDicts[i].localSubrs != &Null (CFF2Subrs) && unlikely (!privateDicts[i].localSubrs->sanitize (&sc))) { fini (); return; } } @@ -503,7 +481,7 @@ struct cff2 blob = nullptr; } - bool is_valid () const { return blob != nullptr; } + bool is_valid () const { return blob; } protected: hb_blob_t *blob; @@ -529,27 +507,14 @@ struct cff2 HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; +#ifdef HB_EXPERIMENTAL_API + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const; +#endif }; typedef accelerator_templ_t accelerator_subset_t; - bool subset (hb_subset_plan_t *plan) const - { - hb_blob_t *cff2_prime = nullptr; - - bool success = true; - if (hb_subset_cff2 (plan, &cff2_prime)) { - success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime); - hb_blob_t *head_blob = hb_sanitize_context_t().reference_table (plan->source); - success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob); - hb_blob_destroy (head_blob); - } else { - success = false; - } - hb_blob_destroy (cff2_prime); - - return success; - } + bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); } public: FixedVersion version; /* Version of CFF2 table. set to 0x0200u */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh index 9e2ada67c4a..7160b168a7a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh @@ -56,6 +56,18 @@ struct CmapSubtableFormat0 out->add (i); } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + for (unsigned i = 0; i < 256; i++) + if (glyphIdArray[i]) + { + hb_codepoint_t glyph = glyphIdArray[i]; + unicodes->add (i); + mapping->set (i, glyph); + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -74,154 +86,203 @@ struct CmapSubtableFormat0 struct CmapSubtableFormat4 { - struct segment_plan - { - HBUINT16 start_code; - HBUINT16 end_code; - bool use_delta; - }; - bool serialize (hb_serialize_context_t *c, - const hb_subset_plan_t *plan, - const hb_vector_t &segments) + template + HBUINT16* serialize_endcode_array (hb_serialize_context_t *c, + Iterator it) { - TRACE_SERIALIZE (this); - - if (unlikely (!c->extend_min (*this))) return_trace (false); + HBUINT16 *endCode = c->start_embed (); + hb_codepoint_t prev_endcp = 0xFFFF; - this->format.set (4); - this->length.set (get_sub_table_size (segments)); - - this->segCountX2.set (segments.length * 2); - this->entrySelector.set (MAX (1u, hb_bit_storage (segments.length)) - 1); - this->searchRange.set (2 * (1u << this->entrySelector)); - this->rangeShift.set (segments.length * 2 > this->searchRange - ? 2 * segments.length - this->searchRange - : 0); - - HBUINT16 *end_count = c->allocate_size (HBUINT16::static_size * segments.length); - c->allocate_size (HBUINT16::static_size); // 2 bytes of padding. - HBUINT16 *start_count = c->allocate_size (HBUINT16::static_size * segments.length); - HBINT16 *id_delta = c->allocate_size (HBUINT16::static_size * segments.length); - HBUINT16 *id_range_offset = c->allocate_size (HBUINT16::static_size * segments.length); - - if (id_range_offset == nullptr) - return_trace (false); + for (const hb_item_type _ : +it) + { + if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first) + { + HBUINT16 end_code; + end_code = prev_endcp; + c->copy (end_code); + } + prev_endcp = _.first; + } - for (unsigned int i = 0; i < segments.length; i++) { - end_count[i].set (segments[i].end_code); - start_count[i].set (segments[i].start_code); - if (segments[i].use_delta) + // last endCode + HBUINT16 endcode; + endcode = prev_endcp; + if (unlikely (!c->copy (endcode))) return nullptr; + // There must be a final entry with end_code == 0xFFFF. + if (prev_endcp != 0xFFFF) { - hb_codepoint_t cp = segments[i].start_code; - hb_codepoint_t start_gid = 0; - if (unlikely (!plan->new_gid_for_codepoint (cp, &start_gid) && cp != 0xFFFF)) - return_trace (false); - id_delta[i].set (start_gid - segments[i].start_code); - } else { - id_delta[i].set (0); - unsigned int num_codepoints = segments[i].end_code - segments[i].start_code + 1; - HBUINT16 *glyph_id_array = c->allocate_size (HBUINT16::static_size * num_codepoints); - if (glyph_id_array == nullptr) - return_trace (false); - // From the cmap spec: - // - // id_range_offset[i]/2 - // + (cp - segments[i].start_code) - // + (id_range_offset + i) - // = - // glyph_id_array + (cp - segments[i].start_code) - // - // So, solve for id_range_offset[i]: - // - // id_range_offset[i] - // = - // 2 * (glyph_id_array - id_range_offset - i) - id_range_offset[i].set (2 * ( - glyph_id_array - id_range_offset - i)); - for (unsigned int j = 0; j < num_codepoints; j++) - { - hb_codepoint_t cp = segments[i].start_code + j; - hb_codepoint_t new_gid; - if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) - return_trace (false); - glyph_id_array[j].set (new_gid); - } + HBUINT16 finalcode; + finalcode = 0xFFFF; + if (unlikely (!c->copy (finalcode))) return nullptr; } } - return_trace (true); + return endCode; } - static size_t get_sub_table_size (const hb_vector_t &segments) + template + HBUINT16* serialize_startcode_array (hb_serialize_context_t *c, + Iterator it) { - size_t segment_size = 0; - for (unsigned int i = 0; i < segments.length; i++) + HBUINT16 *startCode = c->start_embed (); + hb_codepoint_t prev_cp = 0xFFFF; + + for (const hb_item_type _ : +it) { - // Parallel array entries - segment_size += - 2 // end count - + 2 // start count - + 2 // delta - + 2; // range offset - - if (!segments[i].use_delta) - // Add bytes for the glyph index array entries for this segment. - segment_size += (segments[i].end_code - segments[i].start_code + 1) * 2; + if (prev_cp == 0xFFFF || prev_cp + 1u != _.first) + { + HBUINT16 start_code; + start_code = _.first; + c->copy (start_code); + } + + prev_cp = _.first; } - return min_size - + 2 // Padding - + segment_size; + // There must be a final entry with end_code == 0xFFFF. + if (it.len () == 0 || prev_cp != 0xFFFF) + { + HBUINT16 finalcode; + finalcode = 0xFFFF; + if (unlikely (!c->copy (finalcode))) return nullptr; + } + + return startCode; } - static bool create_sub_table_plan (const hb_subset_plan_t *plan, - hb_vector_t *segments) + template + HBINT16* serialize_idDelta_array (hb_serialize_context_t *c, + Iterator it, + HBUINT16 *endCode, + HBUINT16 *startCode, + unsigned segcount) { - segment_plan *segment = nullptr; - hb_codepoint_t last_gid = 0; + unsigned i = 0; + hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF; + bool use_delta = true; - hb_codepoint_t cp = HB_SET_VALUE_INVALID; - while (plan->unicodes->next (&cp)) { - hb_codepoint_t new_gid; - if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) + HBINT16 *idDelta = c->start_embed (); + if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size) + return nullptr; + + for (const hb_item_type _ : +it) + { + if (_.first == startCode[i]) { - DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); - return false; + use_delta = true; + start_gid = _.second; } + else if (_.second != last_gid + 1) use_delta = false; - /* Stop adding to cmap if we are now outside of unicode BMP. */ - if (cp > 0xFFFF) break; - - if (!segment || - cp != segment->end_code + 1u) + if (_.first == endCode[i]) { - segment = segments->push (); - segment->start_code.set (cp); - segment->end_code.set (cp); - segment->use_delta = true; - } else { - segment->end_code.set (cp); - if (last_gid + 1u != new_gid) - // gid's are not consecutive in this segment so delta - // cannot be used. - segment->use_delta = false; + HBINT16 delta; + if (use_delta) delta = (int)start_gid - (int)startCode[i]; + else delta = 0; + c->copy (delta); + + i++; } - last_gid = new_gid; + last_gid = _.second; + last_cp = _.first; } - // There must be a final entry with end_code == 0xFFFF. Check if we need to add one. - if (segment == nullptr || segment->end_code != 0xFFFF) + if (it.len () == 0 || last_cp != 0xFFFF) { - segment = segments->push (); - segment->start_code.set (0xFFFF); - segment->end_code.set (0xFFFF); - segment->use_delta = true; + HBINT16 delta; + delta = 1; + if (unlikely (!c->copy (delta))) return nullptr; } - return true; + return idDelta; + } + + template + HBUINT16* serialize_rangeoffset_glyid (hb_serialize_context_t *c, + Iterator it, + HBUINT16 *endCode, + HBUINT16 *startCode, + HBINT16 *idDelta, + unsigned segcount) + { + HBUINT16 *idRangeOffset = c->allocate_size (HBUINT16::static_size * segcount); + if (unlikely (!c->check_success (idRangeOffset))) return nullptr; + if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr; + + + hb_range (segcount) + | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }) + | hb_apply ([&] (const unsigned i) + { + idRangeOffset[i] = 2 * (c->start_embed () - idRangeOffset - i); + + + it + | hb_filter ([&] (const hb_item_type _) { return _.first >= startCode[i] && _.first <= endCode[i]; }) + | hb_apply ([&] (const hb_item_type _) + { + HBUINT16 glyID; + glyID = _.second; + c->copy (glyID); + }) + ; + + + }) + ; + + return idRangeOffset; + } + + template + void serialize (hb_serialize_context_t *c, + Iterator it) + { + auto format4_iter = + + it + | hb_filter ([&] (const hb_pair_t _) + { return _.first <= 0xFFFF; }) + ; + + if (format4_iter.len () == 0) return; + + unsigned table_initpos = c->length (); + if (unlikely (!c->extend_min (*this))) return; + this->format = 4; + + //serialize endCode[] + HBUINT16 *endCode = serialize_endcode_array (c, format4_iter); + if (unlikely (!endCode)) return; + + unsigned segcount = (c->length () - min_size) / HBUINT16::static_size; + + // 2 bytes of padding. + if (unlikely (!c->allocate_size (HBUINT16::static_size))) return; // 2 bytes of padding. + + // serialize startCode[] + HBUINT16 *startCode = serialize_startcode_array (c, format4_iter); + if (unlikely (!startCode)) return; + + //serialize idDelta[] + HBINT16 *idDelta = serialize_idDelta_array (c, format4_iter, endCode, startCode, segcount); + if (unlikely (!idDelta)) return; + + HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount); + if (unlikely (!c->check_success (idRangeOffset))) return; + + if (unlikely (!c->check_assign(this->length, c->length () - table_initpos))) return; + this->segCountX2 = segcount * 2; + this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1; + this->searchRange = 2 * (1u << this->entrySelector); + this->rangeShift = segcount * 2 > this->searchRange + ? 2 * segcount - this->searchRange + : 0; } struct accelerator_t @@ -244,27 +305,28 @@ struct CmapSubtableFormat4 bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { - /* Custom two-array bsearch. */ - int min = 0, max = (int) this->segCount - 1; - const HBUINT16 *startCount = this->startCount; - const HBUINT16 *endCount = this->endCount; - unsigned int i; - while (min <= max) + struct CustomRange { - int mid = ((unsigned int) min + (unsigned int) max) / 2; - if (codepoint < startCount[mid]) - max = mid - 1; - else if (codepoint > endCount[mid]) - min = mid + 1; - else + int cmp (hb_codepoint_t k, + unsigned distance) const { - i = mid; - goto found; + if (k > last) return +1; + if (k < (&last)[distance]) return -1; + return 0; } - } - return false; + HBUINT16 last; + }; + + const HBUINT16 *found = hb_bsearch (codepoint, + this->endCount, + this->segCount, + 2, + _hb_cmp_method, + this->segCount + 1); + if (!found) + return false; + unsigned int i = found - endCount; - found: hb_codepoint_t gid; unsigned int rangeOffset = this->idRangeOffset[i]; if (rangeOffset == 0) @@ -286,10 +348,10 @@ struct CmapSubtableFormat4 *glyph = gid; return true; } - static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) - { - return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); - } + + HB_INTERNAL static bool get_glyph_func (const void *obj, hb_codepoint_t codepoint, hb_codepoint_t *glyph) + { return ((const accelerator_t *) obj)->get_glyph (codepoint, glyph); } + void collect_unicodes (hb_set_t *out) const { unsigned int count = this->segCount; @@ -297,14 +359,22 @@ struct CmapSubtableFormat4 count--; /* Skip sentinel segment. */ for (unsigned int i = 0; i < count; i++) { + hb_codepoint_t start = this->startCount[i]; + hb_codepoint_t end = this->endCount[i]; unsigned int rangeOffset = this->idRangeOffset[i]; if (rangeOffset == 0) - out->add_range (this->startCount[i], this->endCount[i]); + { + for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) + { + hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu; + if (unlikely (!gid)) + continue; + out->add (codepoint); + } + } else { - for (hb_codepoint_t codepoint = this->startCount[i]; - codepoint <= this->endCount[i]; - codepoint++) + for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) { unsigned int index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; if (unlikely (index >= this->glyphIdArrayLength)) @@ -318,6 +388,45 @@ struct CmapSubtableFormat4 } } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + unsigned count = this->segCount; + if (count && this->startCount[count - 1] == 0xFFFFu) + count--; /* Skip sentinel segment. */ + for (unsigned i = 0; i < count; i++) + { + hb_codepoint_t start = this->startCount[i]; + hb_codepoint_t end = this->endCount[i]; + unsigned rangeOffset = this->idRangeOffset[i]; + if (rangeOffset == 0) + { + for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) + { + hb_codepoint_t gid = (codepoint + this->idDelta[i]) & 0xFFFFu; + if (unlikely (!gid)) + continue; + unicodes->add (codepoint); + mapping->set (codepoint, gid); + } + } + else + { + for (hb_codepoint_t codepoint = start; codepoint <= end; codepoint++) + { + unsigned index = rangeOffset / 2 + (codepoint - this->startCount[i]) + i - this->segCount; + if (unlikely (index >= this->glyphIdArrayLength)) + break; + hb_codepoint_t gid = this->glyphIdArray[index]; + if (unlikely (!gid)) + continue; + unicodes->add (codepoint); + mapping->set (codepoint, gid); + } + } + } + } + const HBUINT16 *endCount; const HBUINT16 *startCount; const HBUINT16 *idDelta; @@ -338,6 +447,13 @@ struct CmapSubtableFormat4 accel.collect_unicodes (out); } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + accelerator_t accel (this); + accel.collect_mapping (unicodes, mapping); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -349,9 +465,9 @@ struct CmapSubtableFormat4 /* Some broken fonts have too long of a "length" value. * If that is the case, just change the value to truncate * the subtable at the end of the blob. */ - uint16_t new_length = (uint16_t) MIN ((uintptr_t) 65535, - (uintptr_t) (c->end - - (char *) this)); + uint16_t new_length = (uint16_t) hb_min ((uintptr_t) 65535, + (uintptr_t) (c->end - + (char *) this)); if (!c->try_set (&length, new_length)) return_trace (false); } @@ -440,6 +556,21 @@ struct CmapSubtableTrimmed out->add (start + i); } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + hb_codepoint_t start_cp = startCharCode; + unsigned count = glyphIdArray.len; + for (unsigned i = 0; i < count; i++) + if (glyphIdArray[i]) + { + hb_codepoint_t unicode = start_cp + i; + hb_codepoint_t glyphid = glyphIdArray[i]; + unicodes->add (unicode); + mapping->set (unicode, glyphid); + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -451,7 +582,7 @@ struct CmapSubtableTrimmed UINT length; /* Byte length of this subtable. */ UINT language; /* Ignore. */ UINT startCharCode; /* First character code covered. */ - ArrayOf + ArrayOf glyphIdArray; /* Array of glyph index values for character * codes in the range. */ public: @@ -475,12 +606,56 @@ struct CmapSubtableLongSegmented return true; } - void collect_unicodes (hb_set_t *out) const + void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const + { + for (unsigned int i = 0; i < this->groups.len; i++) + { + hb_codepoint_t start = this->groups[i].startCharCode; + hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, + (hb_codepoint_t) HB_UNICODE_MAX); + hb_codepoint_t gid = this->groups[i].glyphID; + if (!gid) + { + /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */ + if (! T::group_get_glyph (this->groups[i], end)) continue; + start++; + gid++; + } + if (unlikely ((unsigned int) gid >= num_glyphs)) continue; + if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs)) + end = start + (hb_codepoint_t) num_glyphs - gid; + + out->add_range (start, end); + } + } + + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping, /* OUT */ + unsigned num_glyphs) const { - for (unsigned int i = 0; i < this->groups.len; i++) { - out->add_range (this->groups[i].startCharCode, - MIN ((hb_codepoint_t) this->groups[i].endCharCode, - (hb_codepoint_t) HB_UNICODE_MAX)); + for (unsigned i = 0; i < this->groups.len; i++) + { + hb_codepoint_t start = this->groups[i].startCharCode; + hb_codepoint_t end = hb_min ((hb_codepoint_t) this->groups[i].endCharCode, + (hb_codepoint_t) HB_UNICODE_MAX); + hb_codepoint_t gid = this->groups[i].glyphID; + if (!gid) + { + /* Intention is: if (hb_is_same (T, CmapSubtableFormat13)) continue; */ + if (! T::group_get_glyph (this->groups[i], end)) continue; + start++; + gid++; + } + if (unlikely ((unsigned int) gid >= num_glyphs)) continue; + if (unlikely ((unsigned int) (gid + end - start) >= num_glyphs)) + end = start + (hb_codepoint_t) num_glyphs - gid; + + for (unsigned cp = start; cp <= end; cp++) + { + unicodes->add (cp); + mapping->set (cp, gid); + gid++; + } } } @@ -490,15 +665,6 @@ struct CmapSubtableLongSegmented return_trace (c->check_struct (this) && groups.sanitize (c)); } - bool serialize (hb_serialize_context_t *c, - const hb_vector_t &group_data) - { - TRACE_SERIALIZE (this); - if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!groups.serialize (c, group_data.as_array ()))) return_trace (false); - return true; - } - protected: HBUINT16 format; /* Subtable format; set to 12. */ HBUINT16 reserved; /* Reserved; set to 0. */ @@ -518,63 +684,66 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented group.glyphID + (u - group.startCharCode) : 0; } - bool serialize (hb_serialize_context_t *c, - const hb_vector_t &groups) + template + void serialize (hb_serialize_context_t *c, + Iterator it) { - if (unlikely (!c->extend_min (*this))) return false; - - this->format.set (12); - this->reserved.set (0); - this->length.set (get_sub_table_size (groups)); + if (it.len () == 0) return; + unsigned table_initpos = c->length (); + if (unlikely (!c->extend_min (*this))) return; - return CmapSubtableLongSegmented::serialize (c, groups); - } + hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF; + hb_codepoint_t glyphID = 0; - static size_t get_sub_table_size (const hb_vector_t &groups) - { - return 16 + 12 * groups.length; - } - - static bool create_sub_table_plan (const hb_subset_plan_t *plan, - hb_vector_t *groups) - { - CmapSubtableLongGroup *group = nullptr; - - hb_codepoint_t cp = HB_SET_VALUE_INVALID; - while (plan->unicodes->next (&cp)) { - hb_codepoint_t new_gid; - if (unlikely (!plan->new_gid_for_codepoint (cp, &new_gid))) + for (const hb_item_type _ : +it) + { + if (startCharCode == 0xFFFF) { - DEBUG_MSG(SUBSET, nullptr, "Unable to find new gid for %04x", cp); - return false; + startCharCode = _.first; + endCharCode = _.first; + glyphID = _.second; } - - if (!group || !_is_gid_consecutive (group, cp, new_gid)) + else if (!_is_gid_consecutive (endCharCode, startCharCode, glyphID, _.first, _.second)) { - group = groups->push (); - group->startCharCode.set (cp); - group->endCharCode.set (cp); - group->glyphID.set (new_gid); + CmapSubtableLongGroup grouprecord; + grouprecord.startCharCode = startCharCode; + grouprecord.endCharCode = endCharCode; + grouprecord.glyphID = glyphID; + c->copy (grouprecord); + + startCharCode = _.first; + endCharCode = _.first; + glyphID = _.second; } - else group->endCharCode.set (cp); + else + endCharCode = _.first; } - DEBUG_MSG(SUBSET, nullptr, "cmap"); - for (unsigned int i = 0; i < groups->length; i++) { - CmapSubtableLongGroup& group = (*groups)[i]; - DEBUG_MSG(SUBSET, nullptr, " %d: U+%04X-U+%04X, gid %d-%d", i, (uint32_t) group.startCharCode, (uint32_t) group.endCharCode, (uint32_t) group.glyphID, (uint32_t) group.glyphID + ((uint32_t) group.endCharCode - (uint32_t) group.startCharCode)); - } + CmapSubtableLongGroup record; + record.startCharCode = startCharCode; + record.endCharCode = endCharCode; + record.glyphID = glyphID; + c->copy (record); - return true; + this->format = 12; + this->reserved = 0; + this->length = c->length () - table_initpos; + this->groups.len = (this->length - min_size)/CmapSubtableLongGroup::static_size; } - private: - static bool _is_gid_consecutive (CmapSubtableLongGroup *group, + static size_t get_sub_table_size (const hb_sorted_vector_t &groups_data) + { return 16 + 12 * groups_data.length; } + + private: + static bool _is_gid_consecutive (hb_codepoint_t endCharCode, + hb_codepoint_t startCharCode, + hb_codepoint_t glyphID, hb_codepoint_t cp, hb_codepoint_t new_gid) { - return (cp - 1 == group->endCharCode) && - new_gid == group->glyphID + (cp - group->startCharCode); + return (cp - 1 == endCharCode) && + new_gid == glyphID + (cp - startCharCode); } }; @@ -623,12 +792,69 @@ struct DefaultUVS : SortedArrayOf for (unsigned int i = 0; i < count; i++) { hb_codepoint_t first = arrayZ[i].startUnicodeValue; - hb_codepoint_t last = MIN ((hb_codepoint_t) (first + arrayZ[i].additionalCount), - (hb_codepoint_t) HB_UNICODE_MAX); + hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount), + (hb_codepoint_t) HB_UNICODE_MAX); out->add_range (first, last); } } + DefaultUVS* copy (hb_serialize_context_t *c, + const hb_set_t *unicodes) const + { + DefaultUVS *out = c->start_embed (); + if (unlikely (!out)) return nullptr; + auto snap = c->snapshot (); + + HBUINT32 len; + len = 0; + if (unlikely (!c->copy (len))) return nullptr; + unsigned init_len = c->length (); + + hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID; + int count = -1; + + for (const UnicodeValueRange& _ : as_array ()) + { + for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1)) + { + unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt; + if (!unicodes->has (curEntry)) continue; + count += 1; + if (lastCode == HB_MAP_VALUE_INVALID) + lastCode = curEntry; + else if (lastCode + count != curEntry) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count - 1; + c->copy (rec); + + lastCode = curEntry; + count = 0; + } + } + } + + if (lastCode != HB_MAP_VALUE_INVALID) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count; + c->copy (rec); + } + + if (c->length () - init_len == 0) + { + c->revert (snap); + return nullptr; + } + else + { + if (unlikely (!c->check_assign (out->len, (c->length () - init_len) / UnicodeValueRange::static_size))) return nullptr; + return out; + } + } + public: DEFINE_SIZE_ARRAY (4, *this); }; @@ -636,9 +862,7 @@ struct DefaultUVS : SortedArrayOf struct UVSMapping { int cmp (const hb_codepoint_t &codepoint) const - { - return unicodeValue.cmp (codepoint); - } + { return unicodeValue.cmp (codepoint); } bool sanitize (hb_sanitize_context_t *c) const { @@ -647,7 +871,7 @@ struct UVSMapping } HBUINT24 unicodeValue; /* Base Unicode value of the UVS */ - GlyphID glyphID; /* Glyph ID of the UVS */ + HBGlyphID glyphID; /* Glyph ID of the UVS */ public: DEFINE_SIZE_STATIC (5); }; @@ -658,7 +882,63 @@ struct NonDefaultUVS : SortedArrayOf { unsigned int count = len; for (unsigned int i = 0; i < count; i++) - out->add (arrayZ[i].glyphID); + out->add (arrayZ[i].unicodeValue); + } + + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const + { + unsigned count = len; + for (unsigned i = 0; i < count; i++) + { + hb_codepoint_t unicode = arrayZ[i].unicodeValue; + hb_codepoint_t glyphid = arrayZ[i].glyphID; + unicodes->add (unicode); + mapping->set (unicode, glyphid); + } + } + + void closure_glyphs (const hb_set_t *unicodes, + hb_set_t *glyphset) const + { + + as_array () + | hb_filter (unicodes, &UVSMapping::unicodeValue) + | hb_map (&UVSMapping::glyphID) + | hb_sink (glyphset) + ; + } + + NonDefaultUVS* copy (hb_serialize_context_t *c, + const hb_set_t *unicodes, + const hb_set_t *glyphs_requested, + const hb_map_t *glyph_map) const + { + NonDefaultUVS *out = c->start_embed (); + if (unlikely (!out)) return nullptr; + + auto it = + + as_array () + | hb_filter ([&] (const UVSMapping& _) + { + return unicodes->has (_.unicodeValue) || glyphs_requested->has (_.glyphID); + }) + ; + + if (!it) return nullptr; + + HBUINT32 len; + len = it.len (); + if (unlikely (!c->copy (len))) return nullptr; + + for (const UVSMapping& _ : it) + { + UVSMapping mapping; + mapping.unicodeValue = _.unicodeValue; + mapping.glyphID = glyph_map->get (_.glyphID); + c->copy (mapping); + } + + return out; } public: @@ -682,17 +962,37 @@ struct VariationSelectorRecord return GLYPH_VARIANT_NOT_FOUND; } + VariationSelectorRecord(const VariationSelectorRecord& other) + { + *this = other; + } + + void operator= (const VariationSelectorRecord& other) + { + varSelector = other.varSelector; + HBUINT32 offset = other.defaultUVS; + defaultUVS = offset; + offset = other.nonDefaultUVS; + nonDefaultUVS = offset; + } + void collect_unicodes (hb_set_t *out, const void *base) const { (base+defaultUVS).collect_unicodes (out); (base+nonDefaultUVS).collect_unicodes (out); } - int cmp (const hb_codepoint_t &variation_selector) const + void collect_mapping (const void *base, + hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const { - return varSelector.cmp (variation_selector); + (base+defaultUVS).collect_unicodes (unicodes); + (base+nonDefaultUVS).collect_mapping (unicodes, mapping); } + int cmp (const hb_codepoint_t &variation_selector) const + { return varSelector.cmp (variation_selector); } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -701,6 +1001,45 @@ struct VariationSelectorRecord nonDefaultUVS.sanitize (c, base)); } + hb_pair_t + copy (hb_serialize_context_t *c, + const hb_set_t *unicodes, + const hb_set_t *glyphs_requested, + const hb_map_t *glyph_map, + const void *base) const + { + auto snap = c->snapshot (); + auto *out = c->embed (*this); + if (unlikely (!out)) return hb_pair (0, 0); + + out->defaultUVS = 0; + out->nonDefaultUVS = 0; + + unsigned non_default_uvs_objidx = 0; + if (nonDefaultUVS != 0) + { + c->push (); + if (c->copy (base+nonDefaultUVS, unicodes, glyphs_requested, glyph_map)) + non_default_uvs_objidx = c->pop_pack (); + else c->pop_discard (); + } + + unsigned default_uvs_objidx = 0; + if (defaultUVS != 0) + { + c->push (); + if (c->copy (base+defaultUVS, unicodes)) + default_uvs_objidx = c->pop_pack (); + else c->pop_discard (); + } + + + if (!default_uvs_objidx && !non_default_uvs_objidx) + c->revert (snap); + + return hb_pair (default_uvs_objidx, non_default_uvs_objidx); + } + HBUINT24 varSelector; /* Variation selector. */ LOffsetTo defaultUVS; /* Offset to Default UVS Table. May be 0. */ @@ -715,9 +1054,7 @@ struct CmapSubtableFormat14 glyph_variant_t get_glyph_variant (hb_codepoint_t codepoint, hb_codepoint_t variation_selector, hb_codepoint_t *glyph) const - { - return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); - } + { return record.bsearch (variation_selector).get_glyph (codepoint, glyph, this); } void collect_variation_selectors (hb_set_t *out) const { @@ -727,8 +1064,110 @@ struct CmapSubtableFormat14 } void collect_variation_unicodes (hb_codepoint_t variation_selector, hb_set_t *out) const + { record.bsearch (variation_selector).collect_unicodes (out, this); } + + void serialize (hb_serialize_context_t *c, + const hb_set_t *unicodes, + const hb_set_t *glyphs_requested, + const hb_map_t *glyph_map, + const void *base) + { + auto snap = c->snapshot (); + unsigned table_initpos = c->length (); + const char* init_tail = c->tail; + + if (unlikely (!c->extend_min (*this))) return; + this->format = 14; + + auto src_tbl = reinterpret_cast (base); + + /* + * Some versions of OTS require that offsets are in order. Due to the use + * of push()/pop_pack() serializing the variation records in order results + * in the offsets being in reverse order (first record has the largest + * offset). While this is perfectly valid, it will cause some versions of + * OTS to consider this table bad. + * + * So to prevent this issue we serialize the variation records in reverse + * order, so that the offsets are ordered from small to large. Since + * variation records are supposed to be in increasing order of varSelector + * we then have to reverse the order of the written variation selector + * records after everything is finalized. + */ + hb_vector_t> obj_indices; + for (int i = src_tbl->record.len - 1; i >= 0; i--) + { + hb_pair_t result = src_tbl->record[i].copy (c, unicodes, glyphs_requested, glyph_map, base); + if (result.first || result.second) + obj_indices.push (result); + } + + if (c->length () - table_initpos == CmapSubtableFormat14::min_size) + { + c->revert (snap); + return; + } + + if (unlikely (!c->check_success (!obj_indices.in_error ()))) + return; + + int tail_len = init_tail - c->tail; + c->check_assign (this->length, c->length () - table_initpos + tail_len); + c->check_assign (this->record.len, + (c->length () - table_initpos - CmapSubtableFormat14::min_size) / + VariationSelectorRecord::static_size); + + /* Correct the incorrect write order by reversing the order of the variation + records array. */ + _reverse_variation_records (); + + /* Now that records are in the right order, we can set up the offsets. */ + _add_links_to_variation_records (c, obj_indices); + } + + void _reverse_variation_records () + { + record.as_array ().reverse (); + } + + void _add_links_to_variation_records (hb_serialize_context_t *c, + const hb_vector_t>& obj_indices) + { + for (unsigned i = 0; i < obj_indices.length; i++) + { + /* + * Since the record array has been reversed (see comments in copy()) + * but obj_indices has not been, the indices at obj_indices[i] + * are for the variation record at record[j]. + */ + int j = obj_indices.length - 1 - i; + c->add_link (record[j].defaultUVS, obj_indices[i].first); + c->add_link (record[j].nonDefaultUVS, obj_indices[i].second); + } + } + + void closure_glyphs (const hb_set_t *unicodes, + hb_set_t *glyphset) const + { + + hb_iter (record) + | hb_filter (hb_bool, &VariationSelectorRecord::nonDefaultUVS) + | hb_map (&VariationSelectorRecord::nonDefaultUVS) + | hb_map (hb_add (this)) + | hb_apply ([=] (const NonDefaultUVS& _) { _.closure_glyphs (unicodes, glyphset); }) + ; + } + + void collect_unicodes (hb_set_t *out) const + { + for (const VariationSelectorRecord& _ : record) + _.collect_unicodes (out, this); + } + + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping /* OUT */) const { - record.bsearch (variation_selector).collect_unicodes (out, this); + for (const VariationSelectorRecord& _ : record) + _.collect_mapping (this, unicodes, mapping); } bool sanitize (hb_sanitize_context_t *c) const @@ -766,20 +1205,52 @@ struct CmapSubtable default: return false; } } - void collect_unicodes (hb_set_t *out) const + void collect_unicodes (hb_set_t *out, unsigned int num_glyphs = UINT_MAX) const { switch (u.format) { case 0: u.format0 .collect_unicodes (out); return; case 4: u.format4 .collect_unicodes (out); return; case 6: u.format6 .collect_unicodes (out); return; case 10: u.format10.collect_unicodes (out); return; - case 12: u.format12.collect_unicodes (out); return; - case 13: u.format13.collect_unicodes (out); return; + case 12: u.format12.collect_unicodes (out, num_glyphs); return; + case 13: u.format13.collect_unicodes (out, num_glyphs); return; case 14: default: return; } } + void collect_mapping (hb_set_t *unicodes, /* OUT */ + hb_map_t *mapping, /* OUT */ + unsigned num_glyphs = UINT_MAX) const + { + switch (u.format) { + case 0: u.format0 .collect_mapping (unicodes, mapping); return; + case 4: u.format4 .collect_mapping (unicodes, mapping); return; + case 6: u.format6 .collect_mapping (unicodes, mapping); return; + case 10: u.format10.collect_mapping (unicodes, mapping); return; + case 12: u.format12.collect_mapping (unicodes, mapping, num_glyphs); return; + case 13: u.format13.collect_mapping (unicodes, mapping, num_glyphs); return; + case 14: + default: return; + } + } + + template + void serialize (hb_serialize_context_t *c, + Iterator it, + unsigned format, + const hb_subset_plan_t *plan, + const void *base) + { + switch (format) { + case 4: return u.format4.serialize (c, it); + case 12: return u.format12.serialize (c, it); + case 14: return u.format14.serialize (c, plan->unicodes, plan->glyphs_requested, plan->glyph_map, base); + default: return; + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -831,6 +1302,40 @@ struct EncodingRecord subtable.sanitize (c, base)); } + template + EncodingRecord* copy (hb_serialize_context_t *c, + Iterator it, + unsigned format, + const void *base, + const hb_subset_plan_t *plan, + /* INOUT */ unsigned *objidx) const + { + TRACE_SERIALIZE (this); + auto snap = c->snapshot (); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); + out->subtable = 0; + + if (*objidx == 0) + { + CmapSubtable *cmapsubtable = c->push (); + unsigned origin_length = c->length (); + cmapsubtable->serialize (c, it, format, plan, &(base+subtable)); + if (c->length () - origin_length > 0) *objidx = c->pop_pack (); + else c->pop_discard (); + } + + if (*objidx == 0) + { + c->revert (snap); + return_trace (nullptr); + } + + c->add_link (out->subtable, *objidx); + return_trace (out); + } + HBUINT16 platformID; /* Platform ID. */ HBUINT16 encodingID; /* Platform-specific encoding ID. */ LOffsetTo @@ -843,124 +1348,128 @@ struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; - struct subset_plan + template + void serialize (hb_serialize_context_t *c, + Iterator it, + EncodingRecIter encodingrec_iter, + const void *base, + const hb_subset_plan_t *plan) { - size_t final_size () const + if (unlikely (!c->extend_min ((*this)))) return; + this->version = 0; + + unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; + + for (const EncodingRecord& _ : encodingrec_iter) { - return 4 // header - + 8 * 3 // 3 EncodingRecord - + CmapSubtableFormat4::get_sub_table_size (this->format4_segments) - + CmapSubtableFormat12::get_sub_table_size (this->format12_groups); + unsigned format = (base+_.subtable).u.format; + if (!plan->glyphs_requested->is_empty ()) + { + hb_set_t unicodes_set; + hb_map_t cp_glyphid_map; + (base+_.subtable).collect_mapping (&unicodes_set, &cp_glyphid_map); + + auto table_iter = + + hb_zip (unicodes_set.iter(), unicodes_set.iter() | hb_map(cp_glyphid_map)) + | hb_filter (plan->_glyphset, hb_second) + | hb_filter ([plan] (const hb_pair_t& p) + { + return plan->unicodes->has (p.first) || + plan->glyphs_requested->has (p.second); + }) + | hb_map ([plan] (const hb_pair_t& p_org) + { + return hb_pair_t (p_org.first, plan->glyph_map->get(p_org.second)); + }) + ; + + if (format == 4) c->copy (_, table_iter, 4u, base, plan, &format4objidx); + else if (format == 12) c->copy (_, table_iter, 12u, base, plan, &format12objidx); + else if (format == 14) c->copy (_, table_iter, 14u, base, plan, &format14objidx); + } + /* when --gids option is not used, we iterate input unicodes instead of + * all codepoints in each subtable, which is more efficient */ + else + { + hb_set_t unicodes_set; + (base+_.subtable).collect_unicodes (&unicodes_set); + + if (format == 4) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx); + else if (format == 12) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx); + else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); + } } - hb_vector_t format4_segments; - hb_vector_t format12_groups; - }; + c->check_assign(this->encodingRecord.len, (c->length () - cmap::min_size)/EncodingRecord::static_size); + } - bool _create_plan (const hb_subset_plan_t *plan, - subset_plan *cmap_plan) const + void closure_glyphs (const hb_set_t *unicodes, + hb_set_t *glyphset) const { - if (unlikely (!CmapSubtableFormat4::create_sub_table_plan (plan, &cmap_plan->format4_segments))) - return false; - - return CmapSubtableFormat12::create_sub_table_plan (plan, &cmap_plan->format12_groups); + + hb_iter (encodingRecord) + | hb_map (&EncodingRecord::subtable) + | hb_map (hb_add (this)) + | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == 14; }) + | hb_apply ([=] (const CmapSubtable& _) { _.u.format14.closure_glyphs (unicodes, glyphset); }) + ; } - bool _subset (const hb_subset_plan_t *plan, - const subset_plan &cmap_subset_plan, - size_t dest_sz, - void *dest) const + bool subset (hb_subset_context_t *c) const { - hb_serialize_context_t c (dest, dest_sz); - - cmap *table = c.start_serialize (); - if (unlikely (!c.extend_min (*table))) - { - return false; - } + TRACE_SUBSET (this); - table->version.set (0); + cmap *cmap_prime = c->serializer->start_embed (); + if (unlikely (!c->serializer->check_success (cmap_prime))) return_trace (false); - if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3))) - return false; - - // TODO(grieger): Convert the below to a for loop + auto encodingrec_iter = + + hb_iter (encodingRecord) + | hb_filter ([&] (const EncodingRecord& _) + { + if ((_.platformID == 0 && _.encodingID == 3) || + (_.platformID == 0 && _.encodingID == 4) || + (_.platformID == 3 && _.encodingID == 1) || + (_.platformID == 3 && _.encodingID == 10) || + (this + _.subtable).u.format == 14) + return true; - // Format 4, Plat 0 Encoding Record - EncodingRecord &format4_plat0_rec = table->encodingRecord[0]; - format4_plat0_rec.platformID.set (0); // Unicode - format4_plat0_rec.encodingID.set (3); + return false; + }) + ; - // Format 4, Plat 3 Encoding Record - EncodingRecord &format4_plat3_rec = table->encodingRecord[1]; - format4_plat3_rec.platformID.set (3); // Windows - format4_plat3_rec.encodingID.set (1); // Unicode BMP + if (unlikely (!encodingrec_iter.len ())) return_trace (false); - // Format 12 Encoding Record - EncodingRecord &format12_rec = table->encodingRecord[2]; - format12_rec.platformID.set (3); // Windows - format12_rec.encodingID.set (10); // Unicode UCS-4 + const EncodingRecord *unicode_bmp= nullptr, *unicode_ucs4 = nullptr, *ms_bmp = nullptr, *ms_ucs4 = nullptr; + bool has_format12 = false; - // Write out format 4 sub table + for (const EncodingRecord& _ : encodingrec_iter) { - CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table); - format4_plat3_rec.subtable.set (format4_plat0_rec.subtable); - subtable.u.format.set (4); - - CmapSubtableFormat4 &format4 = subtable.u.format4; - if (unlikely (!format4.serialize (&c, plan, cmap_subset_plan.format4_segments))) - return false; + unsigned format = (this + _.subtable).u.format; + if (format == 12) has_format12 = true; + + const EncodingRecord *table = hb_addressof (_); + if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table; + else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table; + else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table; + else if (_.platformID == 3 && _.encodingID == 10) ms_ucs4 = table; } - // Write out format 12 sub table. - { - CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table); - subtable.u.format.set (12); - - CmapSubtableFormat12 &format12 = subtable.u.format12; - if (unlikely (!format12.serialize (&c, cmap_subset_plan.format12_groups))) - return false; - } - - c.end_serialize (); - - return true; - } - - bool subset (hb_subset_plan_t *plan) const - { - subset_plan cmap_subset_plan; - - if (unlikely (!_create_plan (plan, &cmap_subset_plan))) - { - DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cmap subsetting plan."); - return false; - } - - // We now know how big our blob needs to be - size_t dest_sz = cmap_subset_plan.final_size (); - void *dest = malloc (dest_sz); - if (unlikely (!dest)) { - DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for cmap subset output", (unsigned long) dest_sz); - return false; - } - - if (unlikely (!_subset (plan, cmap_subset_plan, dest_sz, dest))) - { - DEBUG_MSG(SUBSET, nullptr, "Failed to perform subsetting of cmap."); - free (dest); - return false; - } - - // all done, write the blob into dest - hb_blob_t *cmap_prime = hb_blob_create ((const char *) dest, - dest_sz, - HB_MEMORY_MODE_READONLY, - dest, - free); - bool result = plan->add_table (HB_OT_TAG_cmap, cmap_prime); - hb_blob_destroy (cmap_prime); - return result; + if (unlikely (!has_format12 && !unicode_bmp && !ms_bmp)) return_trace (false); + if (unlikely (has_format12 && (!unicode_ucs4 && !ms_ucs4))) return_trace (false); + + auto it = + + hb_iter (c->plan->unicodes) + | hb_map ([&] (hb_codepoint_t _) + { + hb_codepoint_t new_gid = HB_MAP_VALUE_INVALID; + c->plan->new_gid_for_codepoint (_, &new_gid); + return hb_pair_t (_, new_gid); + }) + | hb_filter ([&] (const hb_pair_t _) + { return (_.second != HB_MAP_VALUE_INVALID); }) + ; + cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan); + return_trace (true); } const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const @@ -969,6 +1478,15 @@ struct cmap const CmapSubtable *subtable; + /* Symbol subtable. + * Prefer symbol if available. + * https://github.com/harfbuzz/harfbuzz/issues/1918 */ + if ((subtable = this->find_subtable (3, 0))) + { + if (symbol) *symbol = true; + return subtable; + } + /* 32-bit subtables. */ if ((subtable = this->find_subtable (3, 10))) return subtable; if ((subtable = this->find_subtable (0, 6))) return subtable; @@ -981,13 +1499,6 @@ struct cmap if ((subtable = this->find_subtable (0, 1))) return subtable; if ((subtable = this->find_subtable (0, 0))) return subtable; - /* Symbol subtable. */ - if ((subtable = this->find_subtable (3, 0))) - { - if (symbol) *symbol = true; - return subtable; - } - /* Meh. */ return &Null (CmapSubtable); } @@ -1008,9 +1519,9 @@ struct cmap this->get_glyph_data = subtable; if (unlikely (symbol)) - { this->get_glyph_funcZ = get_glyph_from_symbol; - } else { + else + { switch (subtable->u.format) { /* Accelerate format 4 and format 12. */ default: @@ -1020,20 +1531,20 @@ struct cmap this->get_glyph_funcZ = get_glyph_from; break; case 4: - { - this->format4_accel.init (&subtable->u.format4); - this->get_glyph_data = &this->format4_accel; - this->get_glyph_funcZ = this->format4_accel.get_glyph_func; - } + { + this->format4_accel.init (&subtable->u.format4); + this->get_glyph_data = &this->format4_accel; + this->get_glyph_funcZ = this->format4_accel.get_glyph_func; break; } + } } } void fini () { this->table.destroy (); } bool get_nominal_glyph (hb_codepoint_t unicode, - hb_codepoint_t *glyph) const + hb_codepoint_t *glyph) const { if (unlikely (!this->get_glyph_funcZ)) return false; return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); @@ -1076,19 +1587,16 @@ struct cmap return get_nominal_glyph (unicode, glyph); } - void collect_unicodes (hb_set_t *out) const - { - subtable->collect_unicodes (out); - } + void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const + { subtable->collect_unicodes (out, num_glyphs); } + void collect_mapping (hb_set_t *unicodes, hb_map_t *mapping, + unsigned num_glyphs = UINT_MAX) const + { subtable->collect_mapping (unicodes, mapping, num_glyphs); } void collect_variation_selectors (hb_set_t *out) const - { - subtable_uvs->collect_variation_selectors (out); - } + { subtable_uvs->collect_variation_selectors (out); } void collect_variation_unicodes (hb_codepoint_t variation_selector, hb_set_t *out) const - { - subtable_uvs->collect_variation_unicodes (variation_selector, out); - } + { subtable_uvs->collect_variation_unicodes (variation_selector, out); } protected: typedef bool (*hb_cmap_get_glyph_func_t) (const void *obj, @@ -1096,18 +1604,18 @@ struct cmap hb_codepoint_t *glyph); template - static bool get_glyph_from (const void *obj, - hb_codepoint_t codepoint, - hb_codepoint_t *glyph) + HB_INTERNAL static bool get_glyph_from (const void *obj, + hb_codepoint_t codepoint, + hb_codepoint_t *glyph) { const Type *typed_obj = (const Type *) obj; return typed_obj->get_glyph (codepoint, glyph); } template - static bool get_glyph_from_symbol (const void *obj, - hb_codepoint_t codepoint, - hb_codepoint_t *glyph) + HB_INTERNAL static bool get_glyph_from_symbol (const void *obj, + hb_codepoint_t codepoint, + hb_codepoint_t *glyph) { const Type *typed_obj = (const Type *) obj; if (likely (typed_obj->get_glyph (codepoint, glyph))) @@ -1135,6 +1643,7 @@ struct cmap CmapSubtableFormat4::accelerator_t format4_accel; + public: hb_blob_ptr_t table; }; @@ -1144,8 +1653,8 @@ struct cmap unsigned int encoding_id) const { EncodingRecord key; - key.platformID.set (platform_id); - key.encodingID.set (encoding_id); + key.platformID = platform_id; + key.encodingID = encoding_id; const EncodingRecord &result = encodingRecord.bsearch (key); if (!result.subtable) @@ -1154,6 +1663,28 @@ struct cmap return &(this+result.subtable); } + const EncodingRecord *find_encodingrec (unsigned int platform_id, + unsigned int encoding_id) const + { + EncodingRecord key; + key.platformID = platform_id; + key.encodingID = encoding_id; + + return encodingRecord.as_array ().bsearch (key); + } + + bool find_subtable (unsigned format) const + { + auto it = + + hb_iter (encodingRecord) + | hb_map (&EncodingRecord::subtable) + | hb_map (hb_add (this)) + | hb_filter ([&] (const CmapSubtable& _) { return _.u.format == format; }) + ; + + return it.len (); + } + public: bool sanitize (hb_sanitize_context_t *c) const @@ -1165,9 +1696,9 @@ struct cmap } protected: - HBUINT16 version; /* Table version number (0). */ + HBUINT16 version; /* Table version number (0). */ SortedArrayOf - encodingRecord; /* Encoding tables. */ + encodingRecord; /* Encoding tables. */ public: DEFINE_SIZE_ARRAY (4, encodingRecord); }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh index 36ec2be984f..3e619bd4035 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh @@ -21,7 +21,7 @@ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * - * Google Author(s): Seigo Nonaka + * Google Author(s): Seigo Nonaka, Calder Kitagawa */ #ifndef HB_OT_COLOR_CBDT_TABLE_HH @@ -43,6 +43,35 @@ namespace OT { +struct cblc_bitmap_size_subset_context_t +{ + const char *cbdt; + unsigned int cbdt_length; + hb_vector_t *cbdt_prime; + unsigned int size; /* INOUT + * Input: old size of IndexSubtable + * Output: new size of IndexSubtable + */ + unsigned int num_tables; /* INOUT + * Input: old number of subtables. + * Output: new number of subtables. + */ + hb_codepoint_t start_glyph; /* OUT */ + hb_codepoint_t end_glyph; /* OUT */ +}; + +static inline bool +_copy_data_to_cbdt (hb_vector_t *cbdt_prime, + const void *data, + unsigned length) +{ + unsigned int new_len = cbdt_prime->length + length; + if (unlikely (!cbdt_prime->alloc (new_len))) return false; + memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length); + cbdt_prime->length = new_len; + return true; +} + struct SmallGlyphMetrics { bool sanitize (hb_sanitize_context_t *c) const @@ -51,12 +80,12 @@ struct SmallGlyphMetrics return_trace (c->check_struct (this)); } - void get_extents (hb_glyph_extents_t *extents) const + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const { - extents->x_bearing = bearingX; - extents->y_bearing = bearingY; - extents->width = width; - extents->height = - (hb_position_t) height; + extents->x_bearing = font->em_scale_x (bearingX); + extents->y_bearing = font->em_scale_y (bearingY); + extents->width = font->em_scale_x (width); + extents->height = font->em_scale_y (-static_cast(height)); } HBUINT8 height; @@ -65,7 +94,7 @@ struct SmallGlyphMetrics HBINT8 bearingY; HBUINT8 advance; public: - DEFINE_SIZE_STATIC(5); + DEFINE_SIZE_STATIC (5); }; struct BigGlyphMetrics : SmallGlyphMetrics @@ -74,7 +103,7 @@ struct BigGlyphMetrics : SmallGlyphMetrics HBINT8 vertBearingY; HBUINT8 vertAdvance; public: - DEFINE_SIZE_STATIC(8); + DEFINE_SIZE_STATIC (8); }; struct SBitLineMetrics @@ -98,7 +127,7 @@ struct SBitLineMetrics HBINT8 padding1; HBINT8 padding2; public: - DEFINE_SIZE_STATIC(12); + DEFINE_SIZE_STATIC (12); }; @@ -118,7 +147,7 @@ struct IndexSubtableHeader HBUINT16 imageFormat; HBUINT32 imageDataOffset; public: - DEFINE_SIZE_STATIC(8); + DEFINE_SIZE_STATIC (8); }; template @@ -143,11 +172,23 @@ struct IndexSubtableFormat1Or3 return true; } + bool add_offset (hb_serialize_context_t *c, + unsigned int offset, + unsigned int *size /* OUT (accumulated) */) + { + TRACE_SERIALIZE (this); + Offset embedded_offset; + embedded_offset = offset; + *size += sizeof (OffsetType); + auto *o = c->embed (embedded_offset); + return_trace ((bool) o); + } + IndexSubtableHeader header; - UnsizedArrayOf > + UnsizedArrayOf> offsetArrayZ; public: - DEFINE_SIZE_ARRAY(8, offsetArrayZ); + DEFINE_SIZE_ARRAY (8, offsetArrayZ); }; struct IndexSubtableFormat1 : IndexSubtableFormat1Or3 {}; @@ -159,35 +200,153 @@ struct IndexSubtable { TRACE_SANITIZE (this); if (!u.header.sanitize (c)) return_trace (false); - switch (u.header.indexFormat) { + switch (u.header.indexFormat) + { case 1: return_trace (u.format1.sanitize (c, glyph_count)); case 3: return_trace (u.format3.sanitize (c, glyph_count)); default:return_trace (true); } } + bool + finish_subtable (hb_serialize_context_t *c, + unsigned int cbdt_prime_len, + unsigned int num_glyphs, + unsigned int *size /* OUT (accumulated) */) + { + TRACE_SERIALIZE (this); + + unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset; + switch (u.header.indexFormat) + { + case 1: return_trace (u.format1.add_offset (c, local_offset, size)); + case 3: { + if (!u.format3.add_offset (c, local_offset, size)) + return_trace (false); + if (!(num_glyphs & 0x01)) // Pad to 32-bit alignment if needed. + return_trace (u.format3.add_offset (c, 0, size)); + return_trace (true); + } + // TODO: implement 2, 4, 5. + case 2: case 4: // No-op. + case 5: // Pad to 32-bit aligned. + default: return_trace (false); + } + } + + bool + fill_missing_glyphs (hb_serialize_context_t *c, + unsigned int cbdt_prime_len, + unsigned int num_missing, + unsigned int *size /* OUT (accumulated) */, + unsigned int *num_glyphs /* OUT (accumulated) */) + { + TRACE_SERIALIZE (this); + + unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset; + switch (u.header.indexFormat) + { + case 1: { + for (unsigned int i = 0; i < num_missing; i++) + { + if (unlikely (!u.format1.add_offset (c, local_offset, size))) + return_trace (false); + *num_glyphs += 1; + } + return_trace (true); + } + case 3: { + for (unsigned int i = 0; i < num_missing; i++) + { + if (unlikely (!u.format3.add_offset (c, local_offset, size))) + return_trace (false); + *num_glyphs += 1; + } + return_trace (true); + } + // TODO: implement 2, 4, 5. + case 2: // Add empty space in cbdt_prime?. + case 4: case 5: // No-op as sparse is supported. + default: return_trace (false); + } + } + + bool + copy_glyph_at_idx (hb_serialize_context_t *c, unsigned int idx, + const char *cbdt, unsigned int cbdt_length, + hb_vector_t *cbdt_prime /* INOUT */, + IndexSubtable *subtable_prime /* INOUT */, + unsigned int *size /* OUT (accumulated) */) const + { + TRACE_SERIALIZE (this); + + unsigned int offset, length, format; + if (unlikely (!get_image_data (idx, &offset, &length, &format))) return_trace (false); + if (unlikely (offset > cbdt_length || cbdt_length - offset < length)) return_trace (false); + + auto *header_prime = subtable_prime->get_header (); + unsigned int new_local_offset = cbdt_prime->length - (unsigned int) header_prime->imageDataOffset; + if (unlikely (!_copy_data_to_cbdt (cbdt_prime, cbdt + offset, length))) return_trace (false); + + return_trace (subtable_prime->add_offset (c, new_local_offset, size)); + } + + bool + add_offset (hb_serialize_context_t *c, unsigned int local_offset, + unsigned int *size /* OUT (accumulated) */) + { + TRACE_SERIALIZE (this); + switch (u.header.indexFormat) + { + case 1: return_trace (u.format1.add_offset (c, local_offset, size)); + case 3: return_trace (u.format3.add_offset (c, local_offset, size)); + // TODO: Implement tables 2, 4, 5 + case 2: // Should be a no-op. + case 4: case 5: // Handle sparse cases. + default: return_trace (false); + } + } + bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const { - switch (u.header.indexFormat) { + switch (u.header.indexFormat) + { case 2: case 5: /* TODO */ case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */ default:return (false); } } - bool get_image_data (unsigned int idx, - unsigned int *offset, - unsigned int *length, - unsigned int *format) const + bool + get_image_data (unsigned int idx, unsigned int *offset, + unsigned int *length, unsigned int *format) const { *format = u.header.imageFormat; - switch (u.header.indexFormat) { + switch (u.header.indexFormat) + { case 1: return u.format1.get_image_data (idx, offset, length); case 3: return u.format3.get_image_data (idx, offset, length); default: return false; } } + const IndexSubtableHeader* get_header () const { return &u.header; } + + void populate_header (unsigned index_format, + unsigned image_format, + unsigned int image_data_offset, + unsigned int *size) + { + u.header.indexFormat = index_format; + u.header.imageFormat = image_format; + u.header.imageDataOffset = image_data_offset; + switch (u.header.indexFormat) + { + case 1: *size += IndexSubtableFormat1::min_size; break; + case 3: *size += IndexSubtableFormat3::min_size; break; + } + } + protected: union { IndexSubtableHeader header; @@ -209,12 +368,135 @@ struct IndexSubtableRecord offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1)); } - bool get_extents (hb_glyph_extents_t *extents, - const void *base) const + const IndexSubtable* get_subtable (const void *base) const + { + return &(base+offsetToSubtable); + } + + bool add_new_subtable (hb_subset_context_t* c, + cblc_bitmap_size_subset_context_t *bitmap_size_context, + IndexSubtableRecord *record, + const hb_vector_t> *lookup, /* IN */ + const void *base, + unsigned int *start /* INOUT */) const + { + TRACE_SERIALIZE (this); + + auto *subtable = c->serializer->start_embed (); + if (unlikely (!subtable)) return_trace (false); + if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false); + + auto *old_subtable = get_subtable (base); + auto *old_header = old_subtable->get_header (); + + subtable->populate_header (old_header->indexFormat, + old_header->imageFormat, + bitmap_size_context->cbdt_prime->length, + &bitmap_size_context->size); + + unsigned int num_glyphs = 0; + bool early_exit = false; + for (unsigned int i = *start; i < lookup->length; i++) + { + hb_codepoint_t new_gid = (*lookup)[i].first; + const IndexSubtableRecord *next_record = (*lookup)[i].second; + const IndexSubtable *next_subtable = next_record->get_subtable (base); + auto *next_header = next_subtable->get_header (); + if (next_header != old_header) + { + *start = i; + early_exit = true; + break; + } + unsigned int num_missing = record->add_glyph_for_subset (new_gid); + if (unlikely (!subtable->fill_missing_glyphs (c->serializer, + bitmap_size_context->cbdt_prime->length, + num_missing, + &bitmap_size_context->size, + &num_glyphs))) + return_trace (false); + + hb_codepoint_t old_gid = 0; + c->plan->old_gid_for_new_gid (new_gid, &old_gid); + if (old_gid < next_record->firstGlyphIndex) + return_trace (false); + + unsigned int old_idx = (unsigned int) old_gid - next_record->firstGlyphIndex; + if (unlikely (!next_subtable->copy_glyph_at_idx (c->serializer, + old_idx, + bitmap_size_context->cbdt, + bitmap_size_context->cbdt_length, + bitmap_size_context->cbdt_prime, + subtable, + &bitmap_size_context->size))) + return_trace (false); + num_glyphs += 1; + } + if (!early_exit) + *start = lookup->length; + if (unlikely (!subtable->finish_subtable (c->serializer, + bitmap_size_context->cbdt_prime->length, + num_glyphs, + &bitmap_size_context->size))) + return_trace (false); + return_trace (true); + } + + bool add_new_record (hb_subset_context_t *c, + cblc_bitmap_size_subset_context_t *bitmap_size_context, + const hb_vector_t> *lookup, /* IN */ + const void *base, + unsigned int *start, /* INOUT */ + hb_vector_t* records /* INOUT */) const + { + TRACE_SERIALIZE (this); + auto snap = c->serializer->snapshot (); + unsigned int old_size = bitmap_size_context->size; + unsigned int old_cbdt_prime_length = bitmap_size_context->cbdt_prime->length; + + // Set to invalid state to indicate filling glyphs is not yet started. + if (unlikely (!records->resize (records->length + 1))) + return_trace (c->serializer->check_success (false)); + + (*records)[records->length - 1].firstGlyphIndex = 1; + (*records)[records->length - 1].lastGlyphIndex = 0; + bitmap_size_context->size += IndexSubtableRecord::min_size; + + c->serializer->push (); + + if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start))) + { + c->serializer->pop_discard (); + c->serializer->revert (snap); + bitmap_size_context->cbdt_prime->shrink (old_cbdt_prime_length); + bitmap_size_context->size = old_size; + records->resize (records->length - 1); + return_trace (false); + } + + bitmap_size_context->num_tables += 1; + return_trace (true); + } + + unsigned int add_glyph_for_subset (hb_codepoint_t gid) { - return (base+offsetToSubtable).get_extents (extents); + if (firstGlyphIndex > lastGlyphIndex) + { + firstGlyphIndex = gid; + lastGlyphIndex = gid; + return 0; + } + // TODO maybe assert? this shouldn't occur. + if (lastGlyphIndex > gid) + return 0; + unsigned int num_missing = (unsigned int) (gid - lastGlyphIndex - 1); + lastGlyphIndex = gid; + return num_missing; } + bool get_extents (hb_glyph_extents_t *extents, const void *base) const + { return (base+offsetToSubtable).get_extents (extents); } + bool get_image_data (unsigned int gid, const void *base, unsigned int *offset, @@ -226,11 +508,11 @@ struct IndexSubtableRecord offset, length, format); } - GlyphID firstGlyphIndex; - GlyphID lastGlyphIndex; + HBGlyphID firstGlyphIndex; + HBGlyphID lastGlyphIndex; LOffsetTo offsetToSubtable; public: - DEFINE_SIZE_STATIC(8); + DEFINE_SIZE_STATIC (8); }; struct IndexSubtableArray @@ -243,6 +525,79 @@ struct IndexSubtableArray return_trace (indexSubtablesZ.sanitize (c, count, this)); } + void + build_lookup (hb_subset_context_t *c, cblc_bitmap_size_subset_context_t *bitmap_size_context, + hb_vector_t> *lookup /* OUT */) const + { + bool start_glyph_is_set = false; + for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++) + { + hb_codepoint_t old_gid; + if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue; + + const IndexSubtableRecord* record = find_table (old_gid, bitmap_size_context->num_tables); + if (unlikely (!record)) continue; + + // Don't add gaps to the lookup. The best way to determine if a glyph is a + // gap is that it has no image data. + unsigned int offset, length, format; + if (unlikely (!record->get_image_data (old_gid, this, &offset, &length, &format))) continue; + + lookup->push (hb_pair_t (new_gid, record)); + + if (!start_glyph_is_set) + { + bitmap_size_context->start_glyph = new_gid; + start_glyph_is_set = true; + } + + bitmap_size_context->end_glyph = new_gid; + } + } + + bool + subset (hb_subset_context_t *c, + cblc_bitmap_size_subset_context_t *bitmap_size_context) const + { + TRACE_SUBSET (this); + + auto *dst = c->serializer->start_embed (); + if (unlikely (!dst)) return_trace (false); + + hb_vector_t> lookup; + build_lookup (c, bitmap_size_context, &lookup); + if (unlikely (lookup.in_error ())) + return c->serializer->check_success (false); + + bitmap_size_context->size = 0; + bitmap_size_context->num_tables = 0; + hb_vector_t records; + for (unsigned int start = 0; start < lookup.length;) + { + if (unlikely (!lookup[start].second->add_new_record (c, bitmap_size_context, &lookup, this, &start, &records))) + { + // Discard any leftover pushes to the serializer from successful records. + for (unsigned int i = 0; i < records.length; i++) + c->serializer->pop_discard (); + return_trace (false); + } + } + + /* Workaround to ensure offset ordering is from least to greatest when + * resolving links. */ + hb_vector_t objidxs; + for (unsigned int i = 0; i < records.length; i++) + objidxs.push (c->serializer->pop_pack ()); + for (unsigned int i = 0; i < records.length; i++) + { + IndexSubtableRecord* record = c->serializer->embed (records[i]); + if (unlikely (!record)) return_trace (false); + c->serializer->add_link (record->offsetToSubtable, objidxs[records.length - 1 - i]); + } + return_trace (true); + } + public: const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const { @@ -274,14 +629,48 @@ struct BitmapSizeTable vertical.sanitize (c)); } - const IndexSubtableRecord *find_table (hb_codepoint_t glyph, - const void *base, - const void **out_base) const + const IndexSubtableRecord * + find_table (hb_codepoint_t glyph, const void *base, const void **out_base) const { *out_base = &(base+indexSubtableArrayOffset); return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables); } + bool + subset (hb_subset_context_t *c, const void *base, + const char *cbdt, unsigned int cbdt_length, + hb_vector_t *cbdt_prime /* INOUT */) const + { + TRACE_SUBSET (this); + auto *out_table = c->serializer->embed (this); + if (unlikely (!out_table)) return_trace (false); + + cblc_bitmap_size_subset_context_t bitmap_size_context; + bitmap_size_context.cbdt = cbdt; + bitmap_size_context.cbdt_length = cbdt_length; + bitmap_size_context.cbdt_prime = cbdt_prime; + bitmap_size_context.size = indexTablesSize; + bitmap_size_context.num_tables = numberOfIndexSubtables; + bitmap_size_context.start_glyph = 1; + bitmap_size_context.end_glyph = 0; + + if (!out_table->indexSubtableArrayOffset.serialize_subset (c, + indexSubtableArrayOffset, + base, + &bitmap_size_context)) + return_trace (false); + if (!bitmap_size_context.size || + !bitmap_size_context.num_tables || + bitmap_size_context.start_glyph > bitmap_size_context.end_glyph) + return_trace (false); + + out_table->indexTablesSize = bitmap_size_context.size; + out_table->numberOfIndexSubtables = bitmap_size_context.num_tables; + out_table->startGlyphIndex = bitmap_size_context.start_glyph; + out_table->endGlyphIndex = bitmap_size_context.end_glyph; + return_trace (true); + } + protected: LNNOffsetTo indexSubtableArrayOffset; @@ -290,14 +679,14 @@ struct BitmapSizeTable HBUINT32 colorRef; SBitLineMetrics horizontal; SBitLineMetrics vertical; - GlyphID startGlyphIndex; - GlyphID endGlyphIndex; + HBGlyphID startGlyphIndex; + HBGlyphID endGlyphIndex; HBUINT8 ppemX; HBUINT8 ppemY; HBUINT8 bitDepth; HBINT8 flags; public: - DEFINE_SIZE_STATIC(48); + DEFINE_SIZE_STATIC (48); }; @@ -310,7 +699,7 @@ struct GlyphBitmapDataFormat17 SmallGlyphMetrics glyphMetrics; LArrayOf data; public: - DEFINE_SIZE_ARRAY(9, data); + DEFINE_SIZE_ARRAY (9, data); }; struct GlyphBitmapDataFormat18 @@ -318,14 +707,14 @@ struct GlyphBitmapDataFormat18 BigGlyphMetrics glyphMetrics; LArrayOf data; public: - DEFINE_SIZE_ARRAY(12, data); + DEFINE_SIZE_ARRAY (12, data); }; struct GlyphBitmapDataFormat19 { LArrayOf data; public: - DEFINE_SIZE_ARRAY(4, data); + DEFINE_SIZE_ARRAY (4, data); }; struct CBLC @@ -342,22 +731,60 @@ struct CBLC sizeTables.sanitize (c, this)); } + static bool + sink_cbdt (hb_subset_context_t *c, hb_vector_t* cbdt_prime) + { + hb_blob_t *cbdt_prime_blob = hb_blob_create (cbdt_prime->arrayZ, + cbdt_prime->length, + HB_MEMORY_MODE_WRITABLE, + cbdt_prime->arrayZ, + free); + cbdt_prime->init (); // Leak arrayZ to the blob. + bool ret = c->plan->add_table (HB_OT_TAG_CBDT, cbdt_prime_blob); + hb_blob_destroy (cbdt_prime_blob); + return ret; + } + + bool + subset_size_table (hb_subset_context_t *c, const BitmapSizeTable& table, + const char *cbdt /* IN */, unsigned int cbdt_length, + CBLC *cblc_prime /* INOUT */, hb_vector_t *cbdt_prime /* INOUT */) const + { + TRACE_SUBSET (this); + cblc_prime->sizeTables.len++; + + auto snap = c->serializer->snapshot (); + auto cbdt_prime_len = cbdt_prime->length; + + if (!table.subset (c, this, cbdt, cbdt_length, cbdt_prime)) + { + cblc_prime->sizeTables.len--; + c->serializer->revert (snap); + cbdt_prime->shrink (cbdt_prime_len); + return_trace (false); + } + return_trace (true); + } + + // Implemented in cc file as it depends on definition of CBDT. + HB_INTERNAL bool subset (hb_subset_context_t *c) const; + protected: const BitmapSizeTable &choose_strike (hb_font_t *font) const { unsigned count = sizeTables.len; if (unlikely (!count)) - return Null(BitmapSizeTable); + return Null (BitmapSizeTable); - unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem); + unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem); if (!requested_ppem) requested_ppem = 1<<30; /* Choose largest strike. */ unsigned int best_i = 0; - unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY); + unsigned int best_ppem = hb_max (sizeTables[0].ppemX, sizeTables[0].ppemY); for (unsigned int i = 1; i < count; i++) { - unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY); + unsigned int ppem = hb_max (sizeTables[i].ppemX, sizeTables[i].ppemY); if ((requested_ppem <= ppem && ppem < best_ppem) || (requested_ppem > best_ppem && ppem > best_ppem)) { @@ -373,7 +800,7 @@ struct CBLC FixedVersion<> version; LArrayOf sizeTables; public: - DEFINE_SIZE_ARRAY(8, sizeTables); + DEFINE_SIZE_ARRAY (8, sizeTables); }; struct CBDT @@ -384,8 +811,8 @@ struct CBDT { void init (hb_face_t *face) { - cblc = hb_sanitize_context_t().reference_table (face); - cbdt = hb_sanitize_context_t().reference_table (face); + cblc = hb_sanitize_context_t ().reference_table (face); + cbdt = hb_sanitize_context_t ().reference_table (face); upem = hb_face_get_upem (face); } @@ -396,8 +823,8 @@ struct CBDT this->cbdt.destroy (); } - bool get_extents (hb_font_t *font, hb_codepoint_t glyph, - hb_glyph_extents_t *extents) const + bool + get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const { const void *base; const BitmapSizeTable &strike = this->cblc->choose_strike (font); @@ -412,48 +839,42 @@ struct CBDT if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format)) return false; + unsigned int cbdt_len = cbdt.get_length (); + if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) + return false; + + switch (image_format) { - unsigned int cbdt_len = cbdt.get_length (); - if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) + case 17: { + if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) return false; - - switch (image_format) - { - case 17: { - if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) - return false; - const GlyphBitmapDataFormat17& glyphFormat17 = - StructAtOffset (this->cbdt, image_offset); - glyphFormat17.glyphMetrics.get_extents (extents); - break; - } - case 18: { - if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) - return false; - const GlyphBitmapDataFormat18& glyphFormat18 = - StructAtOffset (this->cbdt, image_offset); - glyphFormat18.glyphMetrics.get_extents (extents); - break; - } - default: - // TODO: Support other image formats. - return false; - } + auto &glyphFormat17 = StructAtOffset (this->cbdt, image_offset); + glyphFormat17.glyphMetrics.get_extents (font, extents); + break; + } + case 18: { + if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) + return false; + auto &glyphFormat18 = StructAtOffset (this->cbdt, image_offset); + glyphFormat18.glyphMetrics.get_extents (font, extents); + break; + } + default: return false; /* TODO: Support other image formats. */ } /* Convert to font units. */ - double x_scale = upem / (double) strike.ppemX; - double y_scale = upem / (double) strike.ppemY; - extents->x_bearing = round (extents->x_bearing * x_scale); - extents->y_bearing = round (extents->y_bearing * y_scale); - extents->width = round (extents->width * x_scale); - extents->height = round (extents->height * y_scale); + float x_scale = upem / (float) strike.ppemX; + float y_scale = upem / (float) strike.ppemY; + extents->x_bearing = roundf (extents->x_bearing * x_scale); + extents->y_bearing = roundf (extents->y_bearing * y_scale); + extents->width = roundf (extents->width * x_scale); + extents->height = roundf (extents->height * y_scale); return true; } - hb_blob_t* reference_png (hb_font_t *font, - hb_codepoint_t glyph) const + hb_blob_t* + reference_png (hb_font_t *font, hb_codepoint_t glyph) const { const void *base; const BitmapSizeTable &strike = this->cblc->choose_strike (font); @@ -465,44 +886,41 @@ struct CBDT if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format)) return hb_blob_get_empty (); + unsigned int cbdt_len = cbdt.get_length (); + if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) + return hb_blob_get_empty (); + + switch (image_format) + { + case 17: { - unsigned int cbdt_len = cbdt.get_length (); - if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length)) + if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) return hb_blob_get_empty (); - - switch (image_format) - { - case 17: { - if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) - return hb_blob_get_empty (); - const GlyphBitmapDataFormat17& glyphFormat17 = - StructAtOffset (this->cbdt, image_offset); - return hb_blob_create_sub_blob (cbdt.get_blob (), - image_offset + GlyphBitmapDataFormat17::min_size, - glyphFormat17.data.len); - } - case 18: { - if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) - return hb_blob_get_empty (); - const GlyphBitmapDataFormat18& glyphFormat18 = - StructAtOffset (this->cbdt, image_offset); - return hb_blob_create_sub_blob (cbdt.get_blob (), - image_offset + GlyphBitmapDataFormat18::min_size, - glyphFormat18.data.len); - } - case 19: { - if (unlikely (image_length < GlyphBitmapDataFormat19::min_size)) - return hb_blob_get_empty (); - const GlyphBitmapDataFormat19& glyphFormat19 = - StructAtOffset (this->cbdt, image_offset); - return hb_blob_create_sub_blob (cbdt.get_blob (), - image_offset + GlyphBitmapDataFormat19::min_size, - glyphFormat19.data.len); - } - } + auto &glyphFormat17 = StructAtOffset (this->cbdt, image_offset); + return hb_blob_create_sub_blob (cbdt.get_blob (), + image_offset + GlyphBitmapDataFormat17::min_size, + glyphFormat17.data.len); + } + case 18: + { + if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) + return hb_blob_get_empty (); + auto &glyphFormat18 = StructAtOffset (this->cbdt, image_offset); + return hb_blob_create_sub_blob (cbdt.get_blob (), + image_offset + GlyphBitmapDataFormat18::min_size, + glyphFormat18.data.len); + } + case 19: + { + if (unlikely (image_length < GlyphBitmapDataFormat19::min_size)) + return hb_blob_get_empty (); + auto &glyphFormat19 = StructAtOffset (this->cbdt, image_offset); + return hb_blob_create_sub_blob (cbdt.get_blob (), + image_offset + GlyphBitmapDataFormat19::min_size, + glyphFormat19.data.len); + } + default: return hb_blob_get_empty (); /* TODO: Support other image formats. */ } - - return hb_blob_get_empty (); } bool has_data () const { return cbdt.get_length (); } @@ -525,9 +943,41 @@ struct CBDT FixedVersion<> version; UnsizedArrayOf dataZ; public: - DEFINE_SIZE_ARRAY(4, dataZ); + DEFINE_SIZE_ARRAY (4, dataZ); }; +inline bool +CBLC::subset (hb_subset_context_t *c) const +{ + TRACE_SUBSET (this); + + auto *cblc_prime = c->serializer->start_embed (); + + // Use a vector as a secondary buffer as the tables need to be built in parallel. + hb_vector_t cbdt_prime; + + if (unlikely (!cblc_prime)) return_trace (false); + if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false); + cblc_prime->version = version; + + hb_blob_t* cbdt_blob = hb_sanitize_context_t ().reference_table (c->plan->source); + unsigned int cbdt_length; + CBDT* cbdt = (CBDT *) hb_blob_get_data (cbdt_blob, &cbdt_length); + if (unlikely (cbdt_length < CBDT::min_size)) + { + hb_blob_destroy (cbdt_blob); + return_trace (false); + } + _copy_data_to_cbdt (&cbdt_prime, cbdt, CBDT::min_size); + + for (const BitmapSizeTable& table : + sizeTables.iter ()) + subset_size_table (c, table, (const char *) cbdt, cbdt_length, cblc_prime, &cbdt_prime); + + hb_blob_destroy (cbdt_blob); + + return_trace (CBLC::sink_cbdt (c, &cbdt_prime)); +} + struct CBDT_accelerator_t : CBDT::accelerator_t {}; } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh index 362b4a14de6..21821d458a5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh @@ -1,5 +1,6 @@ /* * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2020 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -20,6 +21,8 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Calder Kitagawa */ #ifndef HB_OT_COLOR_COLR_TABLE_HH @@ -39,6 +42,8 @@ namespace OT { struct LayerRecord { + operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -46,7 +51,7 @@ struct LayerRecord } public: - GlyphID glyphId; /* Glyph ID of layer glyph */ + HBGlyphID glyphId; /* Glyph ID of layer glyph */ Index colorIdx; /* Index value to use with a * selected color palette. * An index value of 0xFFFF @@ -73,7 +78,7 @@ struct BaseGlyphRecord } public: - GlyphID glyphId; /* Glyph ID of reference glyph */ + HBGlyphID glyphId; /* Glyph ID of reference glyph */ HBUINT16 firstLayerIdx; /* Index (from beginning of * the Layer Records) to the * layer record. There will be @@ -98,22 +103,50 @@ struct COLR { const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph); - hb_array_t all_layers ((this+layersZ).arrayZ, numLayers); + hb_array_t all_layers = (this+layersZ).as_array (numLayers); hb_array_t glyph_layers = all_layers.sub_array (record.firstLayerIdx, record.numLayers); if (count) { - hb_array_t segment_layers = glyph_layers.sub_array (start_offset, *count); - *count = segment_layers.length; - for (unsigned int i = 0; i < segment_layers.length; i++) - { - layers[i].glyph = segment_layers.arrayZ[i].glyphId; - layers[i].color_index = segment_layers.arrayZ[i].colorIdx; - } + + glyph_layers.sub_array (start_offset, count) + | hb_sink (hb_array (layers, *count)) + ; } return glyph_layers.length; } + struct accelerator_t + { + accelerator_t () {} + ~accelerator_t () { fini (); } + + void init (hb_face_t *face) + { colr = hb_sanitize_context_t ().reference_table (face); } + + void fini () { this->colr.destroy (); } + + bool is_valid () { return colr.get_blob ()->length; } + + void closure_glyphs (hb_codepoint_t glyph, + hb_set_t *related_ids /* OUT */) const + { colr->closure_glyphs (glyph, related_ids); } + + private: + hb_blob_ptr_t colr; + }; + + void closure_glyphs (hb_codepoint_t glyph, + hb_set_t *related_ids /* OUT */) const + { + const BaseGlyphRecord *record = get_base_glyph_record (glyph); + if (!record) return; + + auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx, + record->numLayers); + if (!glyph_layers.length) return; + related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -122,12 +155,117 @@ struct COLR (this+layersZ).sanitize (c, numLayers))); } + template + bool serialize (hb_serialize_context_t *c, + unsigned version, + BaseIterator base_it, + LayerIterator layer_it) + { + TRACE_SERIALIZE (this); + if (unlikely (base_it.len () != layer_it.len ())) + return_trace (false); + + if (unlikely (!c->extend_min (this))) return_trace (false); + this->version = version; + numLayers = 0; + numBaseGlyphs = base_it.len (); + baseGlyphsZ = COLR::min_size; + layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size; + + for (const hb_item_type _ : + base_it.iter ()) + { + auto* record = c->embed (_); + if (unlikely (!record)) return_trace (false); + record->firstLayerIdx = numLayers; + numLayers += record->numLayers; + } + + for (const hb_item_type& _ : + layer_it.iter ()) + _.as_array ().copy (c); + + return_trace (true); + } + + const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const + { + if ((unsigned int) gid == 0) // Ignore notdef. + return nullptr; + const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid); + if ((record && (hb_codepoint_t) record->glyphId != gid)) + record = nullptr; + return record; + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; + + auto base_it = + + hb_range (c->plan->num_output_glyphs ()) + | hb_map_retains_sorting ([&](hb_codepoint_t new_gid) + { + hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); + + const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); + if (unlikely (!old_record)) + return hb_pair_t (false, Null (BaseGlyphRecord)); + + BaseGlyphRecord new_record; + new_record.glyphId = new_gid; + new_record.numLayers = old_record->numLayers; + return hb_pair_t (true, new_record); + }) + | hb_filter (hb_first) + | hb_map_retains_sorting (hb_second) + ; + + auto layer_it = + + hb_range (c->plan->num_output_glyphs ()) + | hb_map (reverse_glyph_map) + | hb_map_retains_sorting ([&](hb_codepoint_t old_gid) + { + const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); + hb_vector_t out_layers; + + if (unlikely (!old_record || + old_record->firstLayerIdx >= numLayers || + old_record->firstLayerIdx + old_record->numLayers > numLayers)) + return hb_pair_t> (false, out_layers); + + auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx, + old_record->numLayers); + out_layers.resize (layers.length); + for (unsigned int i = 0; i < layers.length; i++) { + out_layers[i] = layers[i]; + hb_codepoint_t new_gid = 0; + if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) + return hb_pair_t> (false, out_layers); + out_layers[i].glyphId = new_gid; + } + + return hb_pair_t> (true, out_layers); + }) + | hb_filter (hb_first) + | hb_map_retains_sorting (hb_second) + ; + + if (unlikely (!base_it || !layer_it || base_it.len () != layer_it.len ())) + return_trace (false); + + COLR *colr_prime = c->serializer->start_embed (); + return_trace (colr_prime->serialize (c->serializer, version, base_it, layer_it)); + } + protected: HBUINT16 version; /* Table version number (starts at 0). */ HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ - LNNOffsetTo > + LNNOffsetTo> baseGlyphsZ; /* Offset to Base Glyph records. */ - LNNOffsetTo > + LNNOffsetTo> layersZ; /* Offset to Layer Records. */ HBUINT16 numLayers; /* Number of Layer Records. */ public: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh index f4ef6973417..f5f642d6bfa 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh @@ -87,15 +87,15 @@ struct CPALV1Tail } protected: - LNNOffsetTo > + LNNOffsetTo> paletteFlagsZ; /* Offset from the beginning of CPAL table to * the Palette Type Array. Set to 0 if no array * is provided. */ - LNNOffsetTo > + LNNOffsetTo> paletteLabelsZ; /* Offset from the beginning of CPAL table to * the palette labels array. Set to 0 if no * array is provided. */ - LNNOffsetTo > + LNNOffsetTo> colorLabelsZ; /* Offset from the beginning of CPAL table to * the color labels array. Set to 0 * if no array is provided. */ @@ -115,7 +115,7 @@ struct CPAL { return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); } unsigned int get_palette_count () const { return numPalettes; } - unsigned int get_color_count () const { return numColors; } + unsigned int get_color_count () const { return numColors; } hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const { return v1 ().get_palette_flags (this, palette_index, numPalettes); } @@ -142,12 +142,9 @@ struct CPAL numColors); if (color_count) { - hb_array_t segment_colors = palette_colors.sub_array (start_offset, *color_count); - /* Always return numColors colors per palette even if it has out-of-bounds start index. */ - unsigned int count = MIN (MAX (numColors - start_offset, 0), *color_count); - *color_count = count; - for (unsigned int i = 0; i < count; i++) - colors[i] = segment_colors[i]; /* Bound-checked read. */ + + palette_colors.sub_array (start_offset, color_count) + | hb_sink (hb_array (colors, *color_count)) + ; } return numColors; } @@ -155,7 +152,7 @@ struct CPAL private: const CPALV1Tail& v1 () const { - if (version == 0) return Null(CPALV1Tail); + if (version == 0) return Null (CPALV1Tail); return StructAfter (*this); } @@ -176,7 +173,7 @@ struct CPAL HBUINT16 numPalettes; /* Number of palettes in the table. */ HBUINT16 numColorRecords; /* Total number of color records, combined for * all palettes. */ - LNNOffsetTo > + LNNOffsetTo> colorRecordsZ; /* Offset from the beginning of CPAL table to * the first ColorRecord. */ UnsizedArrayOf diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh index 5b89796d561..27b935edbbc 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh @@ -1,5 +1,6 @@ /* * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2020 Google, Inc. * * This is part of HarfBuzz, a text shaping library. * @@ -20,12 +21,15 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Calder Kitagawa */ #ifndef HB_OT_COLOR_SBIX_TABLE_HH #define HB_OT_COLOR_SBIX_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-layout-common.hh" /* * sbix -- Standard Bitmap Graphics @@ -40,6 +44,20 @@ namespace OT { struct SBIXGlyph { + SBIXGlyph* copy (hb_serialize_context_t *c, unsigned int data_length) const + { + TRACE_SERIALIZE (this); + SBIXGlyph* new_glyph = c->start_embed (); + if (unlikely (!new_glyph)) return_trace (nullptr); + if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr); + + new_glyph->xOffset = xOffset; + new_glyph->yOffset = yOffset; + new_glyph->graphicType = graphicType; + data.copy (c, data_length); + return_trace (new_glyph); + } + HBINT16 xOffset; /* The horizontal (x-axis) offset from the left * edge of the graphic to the glyph’s origin. * That is, the x-coordinate of the point on the @@ -62,6 +80,9 @@ struct SBIXGlyph struct SBIXStrike { + static unsigned int get_size (unsigned num_glyphs) + { return min_size + num_glyphs * HBUINT32::static_size; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -116,16 +137,59 @@ struct SBIXStrike return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length); } + bool subset (hb_subset_context_t *c, unsigned int available_len) const + { + TRACE_SUBSET (this); + unsigned int num_output_glyphs = c->plan->num_output_glyphs (); + + auto* out = c->serializer->start_embed (); + if (unlikely (!out)) return_trace (false); + auto snap = c->serializer->snapshot (); + if (unlikely (!c->serializer->extend (*out, num_output_glyphs + 1))) return_trace (false); + out->ppem = ppem; + out->resolution = resolution; + HBUINT32 head; + head = get_size (num_output_glyphs + 1); + + bool has_glyphs = false; + for (unsigned new_gid = 0; new_gid < num_output_glyphs; new_gid++) + { + hb_codepoint_t old_gid; + if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid) || + unlikely (imageOffsetsZ[old_gid].is_null () || + imageOffsetsZ[old_gid + 1].is_null () || + imageOffsetsZ[old_gid + 1] <= imageOffsetsZ[old_gid] || + imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid] <= SBIXGlyph::min_size) || + (unsigned int) imageOffsetsZ[old_gid + 1] > available_len) + { + out->imageOffsetsZ[new_gid] = head; + continue; + } + has_glyphs = true; + unsigned int delta = imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid]; + unsigned int glyph_data_length = delta - SBIXGlyph::min_size; + if (!(this+imageOffsetsZ[old_gid]).copy (c->serializer, glyph_data_length)) + return_trace (false); + out->imageOffsetsZ[new_gid] = head; + head += delta; + } + if (has_glyphs) + out->imageOffsetsZ[num_output_glyphs] = head; + else + c->serializer->revert (snap); + return_trace (has_glyphs); + } + public: HBUINT16 ppem; /* The PPEM size for which this strike was designed. */ HBUINT16 resolution; /* The device pixel density (in PPI) for which this * strike was designed. (E.g., 96 PPI, 192 PPI.) */ protected: - UnsizedArrayOf > + UnsizedArrayOf> imageOffsetsZ; /* Offset from the beginning of the strike data header * to bitmap data for an individual glyph ID. */ public: - DEFINE_SIZE_STATIC (8); + DEFINE_SIZE_ARRAY (4, imageOffsetsZ); }; struct sbix @@ -140,7 +204,7 @@ struct sbix { void init (hb_face_t *face) { - table = hb_sanitize_context_t().reference_table (face); + table = hb_sanitize_context_t ().reference_table (face); num_glyphs = face->get_num_glyphs (); } void fini () { table.destroy (); } @@ -173,9 +237,9 @@ struct sbix { unsigned count = table->strikes.len; if (unlikely (!count)) - return Null(SBIXStrike); + return Null (SBIXStrike); - unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem); + unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem); if (!requested_ppem) requested_ppem = 1<<30; /* Choose largest strike. */ /* TODO Add DPI sensitivity as well? */ @@ -235,18 +299,25 @@ struct sbix const PNGHeader &png = *blob->as(); extents->x_bearing = x_offset; - extents->y_bearing = y_offset; + extents->y_bearing = png.IHDR.height + y_offset; extents->width = png.IHDR.width; - extents->height = png.IHDR.height; + extents->height = -1 * png.IHDR.height; /* Convert to font units. */ if (strike_ppem) { - double scale = font->face->get_upem () / (double) strike_ppem; - extents->x_bearing = round (extents->x_bearing * scale); - extents->y_bearing = round (extents->y_bearing * scale); - extents->width = round (extents->width * scale); - extents->height = round (extents->height * scale); + float scale = font->face->get_upem () / (float) strike_ppem; + extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale); + extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale); + extents->width = font->em_scalef_x (extents->width * scale); + extents->height = font->em_scalef_y (extents->height * scale); + } + else + { + extents->x_bearing = font->em_scale_x (extents->x_bearing); + extents->y_bearing = font->em_scale_y (extents->y_bearing); + extents->width = font->em_scale_x (extents->width); + extents->height = font->em_scale_y (extents->height); } hb_blob_destroy (blob); @@ -268,6 +339,63 @@ struct sbix strikes.sanitize (c, this))); } + bool + add_strike (hb_subset_context_t *c, unsigned i) const + { + if (strikes[i].is_null () || c->source_blob->length < (unsigned) strikes[i]) + return false; + + return (this+strikes[i]).subset (c, c->source_blob->length - (unsigned) strikes[i]); + } + + bool serialize_strike_offsets (hb_subset_context_t *c) const + { + TRACE_SERIALIZE (this); + + auto *out = c->serializer->start_embed> (); + if (unlikely (!out)) return_trace (false); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_vector_t*> new_strikes; + hb_vector_t objidxs; + for (int i = strikes.len - 1; i >= 0; --i) + { + auto* o = out->serialize_append (c->serializer); + if (unlikely (!o)) return_trace (false); + *o = 0; + auto snap = c->serializer->snapshot (); + c->serializer->push (); + bool ret = add_strike (c, i); + if (!ret) + { + c->serializer->pop_discard (); + out->pop (); + c->serializer->revert (snap); + } + else + { + objidxs.push (c->serializer->pop_pack ()); + new_strikes.push (o); + } + } + for (unsigned int i = 0; i < new_strikes.length; ++i) + c->serializer->add_link (*new_strikes[i], objidxs[new_strikes.length - 1 - i]); + + return_trace (true); + } + + bool subset (hb_subset_context_t* c) const + { + TRACE_SUBSET (this); + + sbix *sbix_prime = c->serializer->start_embed (); + if (unlikely (!sbix_prime)) return_trace (false); + if (unlikely (!c->serializer->embed (this->version))) return_trace (false); + if (unlikely (!c->serializer->embed (this->flags))) return_trace (false); + + return_trace (serialize_strike_offsets (c)); + } + protected: HBUINT16 version; /* Table version number — set to 1 */ HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh index eb0ba22debc..ccf9ed3365c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh @@ -62,7 +62,7 @@ struct SVGDocumentIndexEntry * this index entry. */ HBUINT16 endGlyphID; /* The last glyph ID in the range described by * this index entry. Must be >= startGlyphID. */ - LNNOffsetTo > + LNNOffsetTo> svgDoc; /* Offset from the beginning of the SVG Document Index * to an SVG document. Must be non-zero. */ HBUINT32 svgDocLength; /* Length of the SVG document. @@ -80,7 +80,7 @@ struct SVG struct accelerator_t { void init (hb_face_t *face) - { table = hb_sanitize_context_t().reference_table (face); } + { table = hb_sanitize_context_t ().reference_table (face); } void fini () { table.destroy (); } hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const @@ -107,7 +107,7 @@ struct SVG protected: HBUINT16 version; /* Table version (starting at 0). */ - LOffsetTo > + LOffsetTo> svgDocEntries; /* Offset (relative to the start of the SVG table) to the * SVG Documents Index. Must be non-zero. */ /* Array of SVG Document Index Entries. */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc index 84aeb96126e..d37e134c08b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc @@ -25,20 +25,21 @@ * Google Author(s): Sascha Brawer, Behdad Esfahbod */ -#include "hb-open-type.hh" +#include "hb.hh" + +#ifndef HB_NO_COLOR + +#include "hb-ot.h" + #include "hb-ot-color-cbdt-table.hh" #include "hb-ot-color-colr-table.hh" #include "hb-ot-color-cpal-table.hh" #include "hb-ot-color-sbix-table.hh" #include "hb-ot-color-svg-table.hh" -#include "hb-ot-face.hh" -#include "hb-ot.h" #include #include -#include "hb-ot-layout.hh" - /** * SECTION:hb-ot-color @@ -47,6 +48,8 @@ * @include: hb-ot.h * * Functions for fetching color-font information from OpenType font faces. + * + * HarfBuzz supports `COLR`/`CPAL`, `sbix`, `CBDT`, and `SVG` color fonts. **/ @@ -57,9 +60,11 @@ /** * hb_ot_color_has_palettes: - * @face: a font face. + * @face: #hb_face_t to work upon + * + * Tests whether a face includes a `CPAL` color-palette table. * - * Returns: whether CPAL table is available. + * Return value: true if data found, false otherwise * * Since: 2.1.0 */ @@ -71,10 +76,11 @@ hb_ot_color_has_palettes (hb_face_t *face) /** * hb_ot_color_palette_get_count: - * @face: a font face. + * @face: #hb_face_t to work upon * - * Returns: the number of color palettes in @face, or zero if @face has - * no colors. + * Fetches the number of color palettes in a face. + * + * Return value: the number of palettes found * * Since: 2.1.0 */ @@ -86,13 +92,16 @@ hb_ot_color_palette_get_count (hb_face_t *face) /** * hb_ot_color_palette_get_name_id: - * @face: a font face. - * @palette_index: the index of the color palette whose name is being requested. + * @face: #hb_face_t to work upon + * @palette_index: The index of the color palette + * + * Fetches the `name` table Name ID that provides display names for + * a `CPAL` color palette. * - * Retrieves the name id of a color palette. For example, a color font can - * have themed palettes like "Spring", "Summer", "Fall", and "Winter". + * Palette display names can be generic (e.g., "Default") or provide + * specific, themed names (e.g., "Spring", "Summer", "Fall", and "Winter"). * - * Returns: an identifier within @face's `name` table. + * Return value: the Named ID found for the palette. * If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID. * * Since: 2.1.0 @@ -106,10 +115,16 @@ hb_ot_color_palette_get_name_id (hb_face_t *face, /** * hb_ot_color_palette_color_get_name_id: - * @face: a font face. - * @color_index: palette entry index. + * @face: #hb_face_t to work upon + * @color_index: The index of the color * - * Returns: Name ID associated with a palette entry, e.g. eye color + * Fetches the `name` table Name ID that provides display names for + * the specificed color in a face's `CPAL` color palette. + * + * Display names can be generic (e.g., "Background") or specific + * (e.g., "Eye color"). + * + * Return value: the Name ID found for the color. * * Since: 2.1.0 */ @@ -122,10 +137,12 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face, /** * hb_ot_color_palette_get_flags: - * @face: a font face - * @palette_index: the index of the color palette whose flags are being requested + * @face: #hb_face_t to work upon + * @palette_index: The index of the color palette + * + * Fetches the flags defined for a color palette. * - * Returns: the flags for the requested color palette. + * Return value: the #hb_ot_color_palette_flags_t of the requested color palette * * Since: 2.1.0 */ @@ -138,25 +155,22 @@ hb_ot_color_palette_get_flags (hb_face_t *face, /** * hb_ot_color_palette_get_colors: - * @face: a font face. - * @palette_index:the index of the color palette whose colors - * are being requested. - * @start_offset: the index of the first color being requested. - * @color_count: (inout) (optional): on input, how many colors - * can be maximally stored into the @colors array; - * on output, how many colors were actually stored. - * @colors: (array length=color_count) (out) (optional): - * an array of #hb_color_t records. After calling - * this function, @colors will be filled with - * the palette colors. If @colors is NULL, the function - * will just return the number of total colors - * without storing any actual colors; this can be used - * for allocating a buffer of suitable size before calling - * hb_ot_color_palette_get_colors() a second time. - * - * Retrieves the colors in a color palette. - * - * Returns: the total number of colors in the palette. + * @face: #hb_face_t to work upon + * @palette_index: the index of the color palette to query + * @start_offset: offset of the first color to retrieve + * @color_count: (inout) (optional): Input = the maximum number of colors to return; + * Output = the actual number of colors returned (may be zero) + * @colors: (out) (array length=color_count) (nullable): The array of #hb_color_t records found + * + * Fetches a list of the colors in a color palette. + * + * After calling this function, @colors will be filled with the palette + * colors. If @colors is NULL, the function will just return the number + * of total colors without storing any actual colors; this can be used + * for allocating a buffer of suitable size before calling + * hb_ot_color_palette_get_colors() a second time. + * + * Return value: the total number of colors in the palette * * Since: 2.1.0 */ @@ -177,9 +191,11 @@ hb_ot_color_palette_get_colors (hb_face_t *face, /** * hb_ot_color_has_layers: - * @face: a font face. + * @face: #hb_face_t to work upon + * + * Tests whether a face includes any `COLR` color layers. * - * Returns: whether COLR table is available. + * Return value: true if data found, false otherwise * * Since: 2.1.0 */ @@ -191,14 +207,17 @@ hb_ot_color_has_layers (hb_face_t *face) /** * hb_ot_color_glyph_get_layers: - * @face: a font face. - * @glyph: a layered color glyph id. - * @start_offset: starting offset of layers. - * @count: (inout) (optional): gets number of layers available to be written on buffer - * and returns number of written layers. - * @layers: (array length=count) (out) (optional): layers buffer to buffer. + * @face: #hb_face_t to work upon + * @glyph: The glyph index to query + * @start_offset: offset of the first layer to retrieve + * @layer_count: (inout) (optional): Input = the maximum number of layers to return; + * Output = the actual number of layers returned (may be zero) + * @layers: (out) (array length=layer_count) (nullable): The array of layers found + * + * Fetches a list of all color layers for the specified glyph index in the specified + * face. The list returned will begin at the offset provided. * - * Returns: Total number of layers a layered color glyph have. + * Return value: Total number of layers available for the glyph index queried * * Since: 2.1.0 */ @@ -206,10 +225,10 @@ unsigned int hb_ot_color_glyph_get_layers (hb_face_t *face, hb_codepoint_t glyph, unsigned int start_offset, - unsigned int *count, /* IN/OUT. May be NULL. */ + unsigned int *layer_count, /* IN/OUT. May be NULL. */ hb_ot_color_layer_t *layers /* OUT. May be NULL. */) { - return face->table.COLR->get_glyph_layers (glyph, start_offset, count, layers); + return face->table.COLR->get_glyph_layers (glyph, start_offset, layer_count, layers); } @@ -219,11 +238,11 @@ hb_ot_color_glyph_get_layers (hb_face_t *face, /** * hb_ot_color_has_svg: - * @face: a font face. + * @face: #hb_face_t to work upon. * - * Check whether @face has SVG glyph images. + * Tests whether a face includes any `SVG` glyph images. * - * Returns true if available, false otherwise. + * Return value: true if data found, false otherwise. * * Since: 2.1.0 */ @@ -235,12 +254,12 @@ hb_ot_color_has_svg (hb_face_t *face) /** * hb_ot_color_glyph_reference_svg: - * @face: a font face. - * @glyph: a svg glyph index. + * @face: #hb_face_t to work upon + * @glyph: a svg glyph index * - * Get SVG document for a glyph. The blob may be either plain text or gzip-encoded. + * Fetches the SVG document for a glyph. The blob may be either plain text or gzip-encoded. * - * Returns: (transfer full): respective svg blob of the glyph, if available. + * Return value: (transfer full): An #hb_blob_t containing the SVG document of the glyph, if available * * Since: 2.1.0 */ @@ -257,11 +276,11 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph) /** * hb_ot_color_has_png: - * @face: a font face. + * @face: #hb_face_t to work upon * - * Check whether @face has PNG glyph images (either CBDT or sbix tables). + * Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables). * - * Returns true if available, false otherwise. + * Return value: true if data found, false otherwise * * Since: 2.1.0 */ @@ -273,14 +292,14 @@ hb_ot_color_has_png (hb_face_t *face) /** * hb_ot_color_glyph_reference_png: - * @font: a font object, not face. upem should be set on - * that font object if one wants to get optimal png blob, otherwise - * return the biggest one - * @glyph: a glyph index. + * @font: #hb_font_t to work upon + * @glyph: a glyph index * - * Get PNG image for a glyph. + * Fetches the PNG image for a glyph. This function takes a font object, not a face object, + * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font + * object. If UPEM is unset, the blob returned will be the largest PNG available. * - * Returns: (transfer full): respective PNG blob of the glyph, if available. + * Return value: (transfer full): An #hb_blob_t containing the PNG image for the glyph, if available * * Since: 2.1.0 */ @@ -297,3 +316,6 @@ hb_ot_color_glyph_reference_png (hb_font_t *font, hb_codepoint_t glyph) return blob; } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h index 5736890fbe5..593447568dd 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h @@ -59,11 +59,11 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face, /** * hb_ot_color_palette_flags_t: - * @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: default indicating that there is nothing special + * @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: Default indicating that there is nothing special * to note about a color palette. - * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: flag indicating that the color + * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: Flag indicating that the color * palette is appropriate to use when displaying the font on a light background such as white. - * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: flag indicating that the color + * @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: Flag indicating that the color * palette is appropriate to use when displaying the font on a dark background such as black. * * Since: 2.1.0 @@ -110,7 +110,7 @@ HB_EXTERN unsigned int hb_ot_color_glyph_get_layers (hb_face_t *face, hb_codepoint_t glyph, unsigned int start_offset, - unsigned int *count, /* IN/OUT. May be NULL. */ + unsigned int *layer_count, /* IN/OUT. May be NULL. */ hb_ot_color_layer_t *layers /* OUT. May be NULL. */); /* diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h index 2a31b320671..4fdb2b36ab9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h @@ -40,6 +40,10 @@ HB_BEGIN_DECLS #ifndef HB_DISABLE_DEPRECATED +/* https://github.com/harfbuzz/harfbuzz/issues/1734 */ +#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER + + /* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */ HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t hb_ot_layout_table_choose_script (hb_face_t *face, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh new file mode 100644 index 00000000000..367e143fdfb --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh @@ -0,0 +1,138 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2012,2013 Google, Inc. + * Copyright © 2019, Facebook Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + * Facebook Author(s): Behdad Esfahbod + */ + +#ifndef HB_OT_FACE_TABLE_LIST_HH +#define HB_OT_FACE_TABLE_LIST_HH +#endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */ + +#ifndef HB_OT_ACCELERATOR +#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) +#define _HB_OT_ACCELERATOR_UNDEF +#endif + + +/* This lists font tables that the hb_face_t will contain and lazily + * load. Don't add a table unless it's used though. This is not + * exactly free. */ + +/* v--- Add new tables in the right place here. */ + + +/* OpenType fundamentals. */ +HB_OT_TABLE (OT, head) +#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT) +HB_OT_ACCELERATOR (OT, cmap) +#endif +HB_OT_TABLE (OT, hhea) +HB_OT_ACCELERATOR (OT, hmtx) +HB_OT_TABLE (OT, OS2) +#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE) +HB_OT_ACCELERATOR (OT, post) +#endif +#ifndef HB_NO_NAME +HB_OT_ACCELERATOR (OT, name) +#endif +#ifndef HB_NO_STYLE +HB_OT_TABLE (OT, STAT) +#endif +#ifndef HB_NO_META +HB_OT_ACCELERATOR (OT, meta) +#endif + +/* Vertical layout. */ +HB_OT_TABLE (OT, vhea) +HB_OT_ACCELERATOR (OT, vmtx) + +/* TrueType outlines. */ +HB_OT_ACCELERATOR (OT, glyf) + +/* CFF outlines. */ +#ifndef HB_NO_CFF +HB_OT_ACCELERATOR (OT, cff1) +HB_OT_ACCELERATOR (OT, cff2) +HB_OT_TABLE (OT, VORG) +#endif + +/* OpenType variations. */ +#ifndef HB_NO_VAR +HB_OT_TABLE (OT, fvar) +HB_OT_TABLE (OT, avar) +HB_OT_ACCELERATOR (OT, gvar) +HB_OT_TABLE (OT, MVAR) +#endif + +/* Legacy kern. */ +#ifndef HB_NO_OT_KERN +HB_OT_TABLE (OT, kern) +#endif + +/* OpenType shaping. */ +#ifndef HB_NO_OT_LAYOUT +HB_OT_ACCELERATOR (OT, GDEF) +HB_OT_ACCELERATOR (OT, GSUB) +HB_OT_ACCELERATOR (OT, GPOS) +//HB_OT_TABLE (OT, JSTF) +#endif + +/* OpenType baseline. */ +#ifndef HB_NO_BASE +HB_OT_TABLE (OT, BASE) +#endif + +/* AAT shaping. */ +#ifndef HB_NO_AAT +HB_OT_TABLE (AAT, morx) +HB_OT_TABLE (AAT, mort) +HB_OT_TABLE (AAT, kerx) +HB_OT_TABLE (AAT, ankr) +HB_OT_TABLE (AAT, trak) +HB_OT_TABLE (AAT, ltag) +HB_OT_TABLE (AAT, feat) +// HB_OT_TABLE (AAT, opbd) +#endif + +/* OpenType color fonts. */ +#ifndef HB_NO_COLOR +HB_OT_TABLE (OT, COLR) +HB_OT_TABLE (OT, CPAL) +HB_OT_ACCELERATOR (OT, CBDT) +HB_OT_ACCELERATOR (OT, sbix) +HB_OT_ACCELERATOR (OT, SVG) +#endif + +/* OpenType math. */ +#ifndef HB_NO_MATH +HB_OT_TABLE (OT, MATH) +#endif + + +#ifdef _HB_OT_ACCELERATOR_UNDEF +#undef HB_OT_ACCELERATOR +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc index 9b17526b7e4..5ef8df43ce7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc @@ -32,6 +32,7 @@ #include "hb-ot-cff2-table.hh" #include "hb-ot-hmtx-table.hh" #include "hb-ot-kern-table.hh" +#include "hb-ot-meta-table.hh" #include "hb-ot-name-table.hh" #include "hb-ot-post-table.hh" #include "hb-ot-color-cbdt-table.hh" @@ -46,16 +47,12 @@ void hb_ot_face_t::init0 (hb_face_t *face) { this->face = face; #define HB_OT_TABLE(Namespace, Type) Type.init0 (); -#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) - HB_OT_TABLES -#undef HB_OT_ACCELERATOR +#include "hb-ot-face-table-list.hh" #undef HB_OT_TABLE } void hb_ot_face_t::fini () { #define HB_OT_TABLE(Namespace, Type) Type.fini (); -#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) - HB_OT_TABLES -#undef HB_OT_ACCELERATOR +#include "hb-ot-face-table-list.hh" #undef HB_OT_TABLE } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh index 7f47ba6cb8e..e24d380bca8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.hh @@ -38,54 +38,10 @@ * hb_ot_face_t */ -#define HB_OT_TABLES \ - /* OpenType fundamentals. */ \ - HB_OT_TABLE(OT, head) \ - HB_OT_ACCELERATOR(OT, cmap) \ - HB_OT_ACCELERATOR(OT, hmtx) \ - HB_OT_ACCELERATOR(OT, vmtx) \ - HB_OT_ACCELERATOR(OT, post) \ - HB_OT_TABLE(OT, kern) \ - HB_OT_ACCELERATOR(OT, glyf) \ - HB_OT_ACCELERATOR(OT, cff1) \ - HB_OT_ACCELERATOR(OT, cff2) \ - HB_OT_TABLE(OT, VORG) \ - HB_OT_ACCELERATOR(OT, name) \ - HB_OT_TABLE(OT, OS2) \ - HB_OT_TABLE(OT, STAT) \ - /* OpenType shaping. */ \ - HB_OT_ACCELERATOR(OT, GDEF) \ - HB_OT_ACCELERATOR(OT, GSUB) \ - HB_OT_ACCELERATOR(OT, GPOS) \ - HB_OT_TABLE(OT, BASE) \ - HB_OT_TABLE(OT, JSTF) \ - /* AAT shaping. */ \ - HB_OT_TABLE(AAT, mort) \ - HB_OT_TABLE(AAT, morx) \ - HB_OT_TABLE(AAT, kerx) \ - HB_OT_TABLE(AAT, ankr) \ - HB_OT_TABLE(AAT, trak) \ - HB_OT_TABLE(AAT, lcar) \ - HB_OT_TABLE(AAT, ltag) \ - HB_OT_TABLE(AAT, feat) \ - /* OpenType variations. */ \ - HB_OT_TABLE(OT, fvar) \ - HB_OT_TABLE(OT, avar) \ - HB_OT_TABLE(OT, MVAR) \ - /* OpenType math. */ \ - HB_OT_TABLE(OT, MATH) \ - /* OpenType color fonts. */ \ - HB_OT_TABLE(OT, COLR) \ - HB_OT_TABLE(OT, CPAL) \ - HB_OT_ACCELERATOR(OT, CBDT) \ - HB_OT_ACCELERATOR(OT, sbix) \ - HB_OT_ACCELERATOR(OT, SVG) \ - /* */ - /* Declare tables. */ #define HB_OT_TABLE(Namespace, Type) namespace Namespace { struct Type; } #define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type##_accelerator_t) -HB_OT_TABLES +#include "hb-ot-face-table-list.hh" #undef HB_OT_ACCELERATOR #undef HB_OT_TABLE @@ -100,9 +56,7 @@ struct hb_ot_face_t { ORDER_ZERO, #define HB_OT_TABLE(Namespace, Type) HB_OT_TABLE_ORDER (Namespace, Type), -#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) - HB_OT_TABLES -#undef HB_OT_ACCELERATOR +#include "hb-ot-face-table-list.hh" #undef HB_OT_TABLE }; @@ -111,7 +65,7 @@ struct hb_ot_face_t hb_table_lazy_loader_t Type; #define HB_OT_ACCELERATOR(Namespace, Type) \ hb_face_lazy_loader_t Type; - HB_OT_TABLES +#include "hb-ot-face-table-list.hh" #undef HB_OT_ACCELERATOR #undef HB_OT_TABLE }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc index b290c497762..f28de2af628 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc @@ -26,6 +26,8 @@ #include "hb.hh" +#ifndef HB_NO_OT_FONT + #include "hb-ot.h" #include "hb-font.hh" @@ -37,7 +39,6 @@ #include "hb-ot-cff1-table.hh" #include "hb-ot-cff2-table.hh" #include "hb-ot-hmtx-table.hh" -#include "hb-ot-kern-table.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-post-table.hh" #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise. @@ -52,7 +53,7 @@ * @short_description: OpenType font implementation * @include: hb-ot.h * - * Functions for using OpenType fonts with hb_shape(). Not that fonts returned + * Functions for using OpenType fonts with hb_shape(). Note that fonts returned * by hb_font_create() default to using these functions, so most clients would * never need to call these functions directly. **/ @@ -149,19 +150,21 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, *x = font->get_glyph_h_advance (glyph) / 2; +#ifndef HB_NO_OT_FONT_CFF const OT::VORG &VORG = *ot_face->VORG; if (VORG.has_data ()) { *y = font->em_scale_y (VORG.get_y_origin (glyph)); return true; } +#endif hb_glyph_extents_t extents = {0}; - if (ot_face->glyf->get_extents (glyph, &extents)) + if (ot_face->glyf->get_extents (font, glyph, &extents)) { const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - hb_position_t tsb = vmtx.get_side_bearing (glyph); - *y = font->em_scale_y (extents.y_bearing + tsb); + hb_position_t tsb = vmtx.get_side_bearing (font, glyph); + *y = extents.y_bearing + font->em_scale_y (tsb); return true; } @@ -180,23 +183,24 @@ hb_ot_get_glyph_extents (hb_font_t *font, void *user_data HB_UNUSED) { const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - bool ret = ot_face->sbix->get_extents (font, glyph, extents); - if (!ret) - ret = ot_face->glyf->get_extents (glyph, extents); - if (!ret) - ret = ot_face->cff1->get_extents (glyph, extents); - if (!ret) - ret = ot_face->cff2->get_extents (font, glyph, extents); - if (!ret) - ret = ot_face->CBDT->get_extents (font, glyph, extents); + +#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) + if (ot_face->sbix->get_extents (font, glyph, extents)) return true; +#endif + if (ot_face->glyf->get_extents (font, glyph, extents)) return true; +#ifndef HB_NO_OT_FONT_CFF + if (ot_face->cff1->get_extents (font, glyph, extents)) return true; + if (ot_face->cff2->get_extents (font, glyph, extents)) return true; +#endif +#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) + if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; +#endif + // TODO Hook up side-bearings variations. - extents->x_bearing = font->em_scale_x (extents->x_bearing); - extents->y_bearing = font->em_scale_y (extents->y_bearing); - extents->width = font->em_scale_x (extents->width); - extents->height = font->em_scale_y (extents->height); - return ret; + return false; } +#ifndef HB_NO_OT_FONT_GLYPH_NAMES static hb_bool_t hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, void *font_data, @@ -205,9 +209,12 @@ hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - return ot_face->post->get_glyph_name (glyph, name, size); + if (ot_face->post->get_glyph_name (glyph, name, size)) return true; +#ifndef HB_NO_OT_FONT_CFF + if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true; +#endif + return false; } - static hb_bool_t hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, void *font_data, @@ -216,37 +223,34 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED, void *user_data HB_UNUSED) { const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - return ot_face->post->get_glyph_from_name (name, len, glyph); + if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true; +#ifndef HB_NO_OT_FONT_CFF + if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true; +#endif + return false; } +#endif static hb_bool_t hb_ot_get_font_h_extents (hb_font_t *font, - void *font_data, + void *font_data HB_UNUSED, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; - metrics->ascender = font->em_scale_y (hmtx.ascender); - metrics->descender = font->em_scale_y (hmtx.descender); - metrics->line_gap = font->em_scale_y (hmtx.line_gap); - // TODO Hook up variations. - return hmtx.has_font_extents; + return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); } static hb_bool_t hb_ot_get_font_v_extents (hb_font_t *font, - void *font_data, + void *font_data HB_UNUSED, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; - const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - metrics->ascender = font->em_scale_x (vmtx.ascender); - metrics->descender = font->em_scale_x (vmtx.descender); - metrics->line_gap = font->em_scale_x (vmtx.line_gap); - // TODO Hook up variations. - return vmtx.has_font_extents; + return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_ASCENDER, &metrics->ascender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap); } #if HB_USE_ATEXIT @@ -270,8 +274,10 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_tface->table, nullptr); } + +#ifndef HB_NO_VAR +int +_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +{ + return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical); +} + +unsigned +_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +{ + return font->face->table.glyf->get_advance_var (font, glyph, is_vertical); +} +#endif + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-glyf-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-glyf-table.hh index 252d0b4eb1a..cd95828e2f5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-glyf-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-glyf-table.hh @@ -1,5 +1,7 @@ /* * Copyright © 2015 Google, Inc. + * Copyright © 2019 Adobe Inc. + * Copyright © 2019 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -21,7 +23,8 @@ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * - * Google Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod, Garret Rieger, Roderick Sheeter + * Adobe Author(s): Michiharu Ariza */ #ifndef HB_OT_GLYF_TABLE_HH @@ -29,7 +32,9 @@ #include "hb-open-type.hh" #include "hb-ot-head-table.hh" -#include "hb-subset-glyf.hh" +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-var-gvar-table.hh" +#include "hb-draw.hh" namespace OT { @@ -54,11 +59,12 @@ struct loca } protected: - UnsizedArrayOf dataZ; /* Location data. */ + UnsizedArrayOf + dataZ; /* Location data. */ public: - DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always - * check the size externally, allow Null() object of it by - * defining it MIN() instead. */ + DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always + * check the size externally, allow Null() object of it by + * defining it _MIN instead. */ }; @@ -76,29 +82,143 @@ struct glyf bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const { TRACE_SANITIZE (this); - /* We don't check for anything specific here. The users of the - * struct do all the hard work... */ + /* Runtime checks as eager sanitizing each glyph is costy */ return_trace (true); } - bool subset (hb_subset_plan_t *plan) const + template + static bool + _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets) + { + unsigned max_offset = + + padded_offsets + | hb_reduce (hb_add, 0) + ; + unsigned num_offsets = padded_offsets.len () + 1; + bool use_short_loca = max_offset < 0x1FFFF; + unsigned entry_size = use_short_loca ? 2 : 4; + char *loca_prime_data = (char *) calloc (entry_size, num_offsets); + + if (unlikely (!loca_prime_data)) return false; + + DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d " + "max_offset %d size %d", + entry_size, num_offsets, max_offset, entry_size * num_offsets); + + if (use_short_loca) + _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets)); + else + _write_loca (padded_offsets, 0, hb_array ((HBUINT32 *) loca_prime_data, num_offsets)); + + hb_blob_t *loca_blob = hb_blob_create (loca_prime_data, + entry_size * num_offsets, + HB_MEMORY_MODE_WRITABLE, + loca_prime_data, + free); + + bool result = plan->add_table (HB_OT_TAG_loca, loca_blob) + && _add_head_and_set_loca_version (plan, use_short_loca); + + hb_blob_destroy (loca_blob); + return result; + } + + template + static void + _write_loca (IteratorIn it, unsigned right_shift, IteratorOut dest) { - hb_blob_t *glyf_prime = nullptr; - hb_blob_t *loca_prime = nullptr; - - bool success = true; - bool use_short_loca = false; - if (hb_subset_glyf_and_loca (plan, &use_short_loca, &glyf_prime, &loca_prime)) { - success = success && plan->add_table (HB_OT_TAG_glyf, glyf_prime); - success = success && plan->add_table (HB_OT_TAG_loca, loca_prime); - success = success && _add_head_and_set_loca_version (plan, use_short_loca); - } else { - success = false; + unsigned int offset = 0; + dest << 0; + + it + | hb_map ([=, &offset] (unsigned int padded_size) + { + offset += padded_size; + DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); + return offset >> right_shift; + }) + | hb_sink (dest) + ; + } + + /* requires source of SubsetGlyph complains the identifier isn't declared */ + template + bool serialize (hb_serialize_context_t *c, + Iterator it, + const hb_subset_plan_t *plan) + { + TRACE_SERIALIZE (this); + unsigned init_len = c->length (); + for (const auto &_ : it) _.serialize (c, plan); + + /* As a special case when all glyph in the font are empty, add a zero byte + * to the table, so that OTS doesn’t reject it, and to make the table work + * on Windows as well. + * See https://github.com/khaledhosny/ots/issues/52 */ + if (init_len == c->length ()) + { + HBUINT8 empty_byte; + empty_byte = 0; + c->copy (empty_byte); } - hb_blob_destroy (loca_prime); - hb_blob_destroy (glyf_prime); + return_trace (true); + } - return success; + /* Byte region(s) per glyph to output + unpadded, hints removed if so requested + If we fail to process a glyph we produce an empty (0-length) glyph */ + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + glyf *glyf_prime = c->serializer->start_embed (); + if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); + + hb_vector_t glyphs; + _populate_subset_glyphs (c->plan, &glyphs); + + glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan); + + auto padded_offsets = + + hb_iter (glyphs) + | hb_map (&SubsetGlyph::padded_size) + ; + + if (c->serializer->in_error ()) return_trace (false); + return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, + padded_offsets))); + } + + template + void + _populate_subset_glyphs (const hb_subset_plan_t *plan, + hb_vector_t *glyphs /* OUT */) const + { + OT::glyf::accelerator_t glyf; + glyf.init (plan->source); + + + hb_range (plan->num_output_glyphs ()) + | hb_map ([&] (hb_codepoint_t new_gid) + { + SubsetGlyph subset_glyph = {0}; + subset_glyph.new_gid = new_gid; + + /* should never fail: all old gids should be mapped */ + if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) + return subset_glyph; + + subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); + if (plan->drop_hints) subset_glyph.drop_hints_bytes (); + else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); + + return subset_glyph; + }) + | hb_sink (glyphs) + ; + + glyf.fini (); } static bool @@ -112,218 +232,292 @@ struct glyf return false; head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); - head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1); + head_prime->indexToLocFormat = use_short_loca ? 0 : 1; bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); hb_blob_destroy (head_prime_blob); return success; } - struct GlyphHeader - { - HBINT16 numberOfContours; /* If the number of contours is - * greater than or equal to zero, - * this is a simple glyph; if negative, - * this is a composite glyph. */ - FWORD xMin; /* Minimum x for coordinate data. */ - FWORD yMin; /* Minimum y for coordinate data. */ - FWORD xMax; /* Maximum x for coordinate data. */ - FWORD yMax; /* Maximum y for coordinate data. */ - - DEFINE_SIZE_STATIC (10); - }; - - struct CompositeGlyphHeader + struct CompositeGlyphChain { - enum composite_glyph_flag_t { - ARG_1_AND_2_ARE_WORDS = 0x0001, - ARGS_ARE_XY_VALUES = 0x0002, - ROUND_XY_TO_GRID = 0x0004, - WE_HAVE_A_SCALE = 0x0008, - MORE_COMPONENTS = 0x0020, - WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, - WE_HAVE_A_TWO_BY_TWO = 0x0080, - WE_HAVE_INSTRUCTIONS = 0x0100, - USE_MY_METRICS = 0x0200, - OVERLAP_COMPOUND = 0x0400, - SCALED_COMPONENT_OFFSET = 0x0800, - UNSCALED_COMPONENT_OFFSET = 0x1000 + protected: + enum composite_glyph_flag_t + { + ARG_1_AND_2_ARE_WORDS = 0x0001, + ARGS_ARE_XY_VALUES = 0x0002, + ROUND_XY_TO_GRID = 0x0004, + WE_HAVE_A_SCALE = 0x0008, + MORE_COMPONENTS = 0x0020, + WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, + WE_HAVE_A_TWO_BY_TWO = 0x0080, + WE_HAVE_INSTRUCTIONS = 0x0100, + USE_MY_METRICS = 0x0200, + OVERLAP_COMPOUND = 0x0400, + SCALED_COMPONENT_OFFSET = 0x0800, + UNSCALED_COMPONENT_OFFSET = 0x1000 }; - HBUINT16 flags; - GlyphID glyphIndex; - + public: unsigned int get_size () const { unsigned int size = min_size; - // arg1 and 2 are int16 + /* arg1 and 2 are int16 */ if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; - // arg1 and 2 are int8 + /* arg1 and 2 are int8 */ else size += 2; - // One x 16 bit (scale) + /* One x 16 bit (scale) */ if (flags & WE_HAVE_A_SCALE) size += 2; - // Two x 16 bit (xscale, yscale) + /* Two x 16 bit (xscale, yscale) */ else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) size += 4; - // Four x 16 bit (xscale, scale01, scale10, yscale) + /* Four x 16 bit (xscale, scale01, scale10, yscale) */ else if (flags & WE_HAVE_A_TWO_BY_TWO) size += 8; return size; } - struct Iterator + void set_glyph_index (hb_codepoint_t new_gid) { glyphIndex = new_gid; } + hb_codepoint_t get_glyph_index () const { return glyphIndex; } + + void drop_instructions_flag () { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; } + bool has_instructions () const { return flags & WE_HAVE_INSTRUCTIONS; } + + bool has_more () const { return flags & MORE_COMPONENTS; } + bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } + bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); } + void get_anchor_points (unsigned int &point1, unsigned int &point2) const { - const char *glyph_start; - const char *glyph_end; - const CompositeGlyphHeader *current; + const HBUINT8 *p = &StructAfter (glyphIndex); + if (flags & ARG_1_AND_2_ARE_WORDS) + { + point1 = ((const HBUINT16 *) p)[0]; + point2 = ((const HBUINT16 *) p)[1]; + } + else + { + point1 = p[0]; + point2 = p[1]; + } + } - bool move_to_next () + void transform_points (contour_point_vector_t &points) const + { + float matrix[4]; + contour_point_t trans; + if (get_transformation (matrix, trans)) { - if (current->flags & CompositeGlyphHeader::MORE_COMPONENTS) + if (scaled_offsets ()) { - const CompositeGlyphHeader *possible = - &StructAfter (*current); - if (!in_range (possible)) - return false; - current = possible; - return true; + points.translate (trans); + points.transform (matrix); + } + else + { + points.transform (matrix); + points.translate (trans); } - return false; } + } - bool in_range (const CompositeGlyphHeader *composite) const - { - return (const char *) composite >= glyph_start - && ((const char *) composite + CompositeGlyphHeader::min_size) <= glyph_end - && ((const char *) composite + composite->get_size ()) <= glyph_end; - } - }; + protected: + bool scaled_offsets () const + { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } - static bool get_iterator (const char * glyph_data, - unsigned int length, - CompositeGlyphHeader::Iterator *iterator /* OUT */) + bool get_transformation (float (&matrix)[4], contour_point_t &trans) const { - if (length < GlyphHeader::static_size) - return false; /* Empty glyph; zero extents. */ + matrix[0] = matrix[3] = 1.f; + matrix[1] = matrix[2] = 0.f; - const GlyphHeader &glyph_header = StructAtOffset (glyph_data, 0); - if (glyph_header.numberOfContours < 0) + int tx, ty; + const HBINT8 *p = &StructAfter (glyphIndex); + if (flags & ARG_1_AND_2_ARE_WORDS) { - const CompositeGlyphHeader *possible = - &StructAfter (glyph_header); - - iterator->glyph_start = glyph_data; - iterator->glyph_end = (const char *) glyph_data + length; - if (!iterator->in_range (possible)) - return false; - iterator->current = possible; - return true; + tx = *(const HBINT16 *) p; + p += HBINT16::static_size; + ty = *(const HBINT16 *) p; + p += HBINT16::static_size; } + else + { + tx = *p++; + ty = *p++; + } + if (is_anchored ()) tx = ty = 0; - return false; + trans.init ((float) tx, (float) ty); + + { + const F2DOT14 *points = (const F2DOT14 *) p; + if (flags & WE_HAVE_A_SCALE) + { + matrix[0] = matrix[3] = points[0].to_float (); + return true; + } + else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) + { + matrix[0] = points[0].to_float (); + matrix[3] = points[1].to_float (); + return true; + } + else if (flags & WE_HAVE_A_TWO_BY_TWO) + { + matrix[0] = points[0].to_float (); + matrix[1] = points[1].to_float (); + matrix[2] = points[2].to_float (); + matrix[3] = points[3].to_float (); + return true; + } + } + return tx || ty; } + protected: + HBUINT16 flags; + HBGlyphID glyphIndex; + public: DEFINE_SIZE_MIN (4); }; - struct accelerator_t + struct composite_iter_t : hb_iter_with_fallback_t { - void init (hb_face_t *face) + typedef const CompositeGlyphChain *__item_t__; + composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : + glyph (glyph_), current (current_) + { if (!check_range (current)) current = nullptr; } + composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {} + + const CompositeGlyphChain &__item__ () const { return *current; } + bool __more__ () const { return current; } + void __next__ () { - memset (this, 0, sizeof (accelerator_t)); + if (!current->has_more ()) { current = nullptr; return; } - const OT::head &head = *face->table.head; - if (head.indexToLocFormat > 1 || head.glyphDataFormat != 0) - /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ - return; - short_offset = 0 == head.indexToLocFormat; - - loca_table = hb_sanitize_context_t ().reference_table (face); - glyf_table = hb_sanitize_context_t ().reference_table (face); - - num_glyphs = MAX (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; + const CompositeGlyphChain *possible = &StructAfter (*current); + if (!check_range (possible)) { current = nullptr; return; } + current = possible; } + bool operator != (const composite_iter_t& o) const + { return glyph != o.glyph || current != o.current; } - void fini () + bool check_range (const CompositeGlyphChain *composite) const { - loca_table.destroy (); - glyf_table.destroy (); + return glyph.check_range (composite, CompositeGlyphChain::min_size) + && glyph.check_range (composite, composite->get_size ()); } - /* - * Returns true if the referenced glyph is a valid glyph and a composite glyph. - * If true is returned a pointer to the composite glyph will be written into - * composite. - */ - bool get_composite (hb_codepoint_t glyph, - CompositeGlyphHeader::Iterator *composite /* OUT */) const - { - if (unlikely (!num_glyphs)) - return false; + private: + hb_bytes_t glyph; + __item_t__ current; + }; - unsigned int start_offset, end_offset; - if (!get_offsets (glyph, &start_offset, &end_offset)) - return false; /* glyph not found */ + enum phantom_point_index_t + { + PHANTOM_LEFT = 0, + PHANTOM_RIGHT = 1, + PHANTOM_TOP = 2, + PHANTOM_BOTTOM = 3, + PHANTOM_COUNT = 4 + }; - return CompositeGlyphHeader::get_iterator ((const char *) this->glyf_table + start_offset, - end_offset - start_offset, - composite); - } + struct accelerator_t; - enum simple_glyph_flag_t { - FLAG_ON_CURVE = 0x01, - FLAG_X_SHORT = 0x02, - FLAG_Y_SHORT = 0x04, - FLAG_REPEAT = 0x08, - FLAG_X_SAME = 0x10, - FLAG_Y_SAME = 0x20, + struct Glyph + { + enum simple_glyph_flag_t + { + FLAG_ON_CURVE = 0x01, + FLAG_X_SHORT = 0x02, + FLAG_Y_SHORT = 0x04, + FLAG_REPEAT = 0x08, + FLAG_X_SAME = 0x10, + FLAG_Y_SAME = 0x20, FLAG_RESERVED1 = 0x40, FLAG_RESERVED2 = 0x80 }; - /* based on FontTools _g_l_y_f.py::trim */ - bool remove_padding (unsigned int start_offset, - unsigned int *end_offset) const + private: + struct GlyphHeader { - if (*end_offset - start_offset < GlyphHeader::static_size) return true; + bool has_data () const { return numberOfContours; } - const char *glyph = ((const char *) glyf_table) + start_offset; - const char * const glyph_end = glyph + (*end_offset - start_offset); - const GlyphHeader &glyph_header = StructAtOffset (glyph, 0); - int16_t num_contours = (int16_t) glyph_header.numberOfContours; + bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, + hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ + /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ + extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid)); + extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); + extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); + extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); - if (num_contours < 0) - /* Trimming for composites not implemented. - * If removing hints it falls out of that. */ return true; - else if (num_contours > 0) + } + + HBINT16 numberOfContours; + /* If the number of contours is + * greater than or equal to zero, + * this is a simple glyph; if negative, + * this is a composite glyph. */ + FWORD xMin; /* Minimum x for coordinate data. */ + FWORD yMin; /* Minimum y for coordinate data. */ + FWORD xMax; /* Maximum x for coordinate data. */ + FWORD yMax; /* Maximum y for coordinate data. */ + public: + DEFINE_SIZE_STATIC (10); + }; + + struct SimpleGlyph + { + const GlyphHeader &header; + hb_bytes_t bytes; + SimpleGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} + + unsigned int instruction_len_offset () const + { return GlyphHeader::static_size + 2 * header.numberOfContours; } + + unsigned int length (unsigned int instruction_len) const + { return instruction_len_offset () + 2 + instruction_len; } + + unsigned int instructions_length () const { + unsigned int instruction_length_offset = instruction_len_offset (); + if (unlikely (instruction_length_offset + 2 > bytes.length)) return 0; + + const HBUINT16 &instructionLength = StructAtOffset (&bytes, instruction_length_offset); + /* Out of bounds of the current glyph */ + if (unlikely (length (instructionLength) > bytes.length)) return 0; + return instructionLength; + } + + const Glyph trim_padding () const + { + /* based on FontTools _g_l_y_f.py::trim */ + const char *glyph = bytes.arrayZ; + const char *glyph_end = glyph + bytes.length; /* simple glyph w/contours, possibly trimmable */ - glyph += GlyphHeader::static_size + 2 * num_contours; + glyph += instruction_len_offset (); - if (unlikely (glyph + 2 >= glyph_end)) return false; - uint16_t nCoordinates = (uint16_t) StructAtOffset (glyph - 2, 0) + 1; - uint16_t nInstructions = (uint16_t) StructAtOffset (glyph, 0); + if (unlikely (glyph + 2 >= glyph_end)) return Glyph (); + unsigned int num_coordinates = StructAtOffset (glyph - 2, 0) + 1; + unsigned int num_instructions = StructAtOffset (glyph, 0); - glyph += 2 + nInstructions; - if (unlikely (glyph + 2 >= glyph_end)) return false; + glyph += 2 + num_instructions; - unsigned int coordBytes = 0; - unsigned int coordsWithFlags = 0; + unsigned int coord_bytes = 0; + unsigned int coords_with_flags = 0; while (glyph < glyph_end) { - uint8_t flag = (uint8_t) *glyph; + uint8_t flag = *glyph; glyph++; unsigned int repeat = 1; if (flag & FLAG_REPEAT) { - if (glyph >= glyph_end) - { - DEBUG_MSG(SUBSET, nullptr, "Bad flag"); - return false; - } - repeat = ((uint8_t) *glyph) + 1; + if (unlikely (glyph >= glyph_end)) return Glyph (); + repeat = *glyph + 1; glyph++; } @@ -335,143 +529,728 @@ struct glyf if (flag & FLAG_Y_SHORT) yBytes = 1; else if ((flag & FLAG_Y_SAME) == 0) yBytes = 2; - coordBytes += (xBytes + yBytes) * repeat; - coordsWithFlags += repeat; - if (coordsWithFlags >= nCoordinates) - break; + coord_bytes += (xBytes + yBytes) * repeat; + coords_with_flags += repeat; + if (coords_with_flags >= num_coordinates) break; } - if (coordsWithFlags != nCoordinates) + if (unlikely (coords_with_flags != num_coordinates)) return Glyph (); + return Glyph (bytes.sub_array (0, bytes.length + coord_bytes - (glyph_end - glyph))); + } + + /* zero instruction length */ + void drop_hints () + { + GlyphHeader &glyph_header = const_cast (header); + (HBUINT16 &) StructAtOffset (&glyph_header, instruction_len_offset ()) = 0; + } + + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + { + unsigned int instructions_len = instructions_length (); + unsigned int glyph_length = length (instructions_len); + dest_start = bytes.sub_array (0, glyph_length - instructions_len); + dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length); + } + + static bool read_points (const HBUINT8 *&p /* IN/OUT */, + contour_point_vector_t &points_ /* IN/OUT */, + const hb_bytes_t &bytes, + void (* setter) (contour_point_t &_, float v), + const simple_glyph_flag_t short_flag, + const simple_glyph_flag_t same_flag) + { + float v = 0; + for (unsigned i = 0; i < points_.length; i++) { - DEBUG_MSG(SUBSET, nullptr, "Expect %d coords to have flags, got flags for %d", nCoordinates, coordsWithFlags); - return false; + uint8_t flag = points_[i].flag; + if (flag & short_flag) + { + if (unlikely (!bytes.check_range (p))) return false; + if (flag & same_flag) + v += *p++; + else + v -= *p++; + } + else + { + if (!(flag & same_flag)) + { + if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) return false; + v += *(const HBINT16 *) p; + p += HBINT16::static_size; + } + } + setter (points_[i], v); } - glyph += coordBytes; + return true; + } + + bool get_contour_points (contour_point_vector_t &points_ /* OUT */, + bool phantom_only = false) const + { + const HBUINT16 *endPtsOfContours = &StructAfter (header); + int num_contours = header.numberOfContours; + if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false; + unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; + + points_.resize (num_points); + for (unsigned int i = 0; i < points_.length; i++) points_[i].init (); + if (phantom_only) return true; - if (glyph < glyph_end) - *end_offset -= glyph_end - glyph; + for (int i = 0; i < num_contours; i++) + points_[endPtsOfContours[i]].is_end_point = true; + + /* Skip instructions */ + const HBUINT8 *p = &StructAtOffset (&endPtsOfContours[num_contours + 1], + endPtsOfContours[num_contours]); + + /* Read flags */ + for (unsigned int i = 0; i < num_points; i++) + { + if (unlikely (!bytes.check_range (p))) return false; + uint8_t flag = *p++; + points_[i].flag = flag; + if (flag & FLAG_REPEAT) + { + if (unlikely (!bytes.check_range (p))) return false; + unsigned int repeat_count = *p++; + while ((repeat_count-- > 0) && (++i < num_points)) + points_[i].flag = flag; + } + } + + /* Read x & y coordinates */ + return read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.x = v; }, + FLAG_X_SHORT, FLAG_X_SAME) + && read_points (p, points_, bytes, [] (contour_point_t &p, float v) { p.y = v; }, + FLAG_Y_SHORT, FLAG_Y_SAME); } - return true; - } + }; - bool get_offsets (hb_codepoint_t glyph, - unsigned int *start_offset /* OUT */, - unsigned int *end_offset /* OUT */) const + struct CompositeGlyph { - if (unlikely (glyph >= num_glyphs)) - return false; + const GlyphHeader &header; + hb_bytes_t bytes; + CompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} - if (short_offset) + composite_iter_t get_iterator () const + { return composite_iter_t (bytes, &StructAfter (header)); } + + unsigned int instructions_length (hb_bytes_t bytes) const { - const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; - *start_offset = 2 * offsets[glyph]; - *end_offset = 2 * offsets[glyph + 1]; + unsigned int start = bytes.length; + unsigned int end = bytes.length; + const CompositeGlyphChain *last = nullptr; + for (auto &item : get_iterator ()) + last = &item; + if (unlikely (!last)) return 0; + + if (last->has_instructions ()) + start = (char *) last - &bytes + last->get_size (); + if (unlikely (start > end)) return 0; + return end - start; } - else + + /* Trimming for composites not implemented. + * If removing hints it falls out of that. */ + const Glyph trim_padding () const { return Glyph (bytes); } + + void drop_hints () { - const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; + for (const auto &_ : get_iterator ()) + const_cast (_).drop_instructions_flag (); + } + + /* Chop instructions off the end */ + void drop_hints_bytes (hb_bytes_t &dest_start) const + { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); } + }; + + enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; + + public: + composite_iter_t get_composite_iterator () const + { + if (type != COMPOSITE) return composite_iter_t (); + return CompositeGlyph (*header, bytes).get_iterator (); + } - *start_offset = offsets[glyph]; - *end_offset = offsets[glyph + 1]; + const Glyph trim_padding () const + { + switch (type) { + case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding (); + case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding (); + default: return bytes; } + } - if (*start_offset > *end_offset || *end_offset > glyf_table.get_length ()) - return false; + void drop_hints () + { + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return; + default: return; + } + } - return true; + void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const + { + switch (type) { + case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return; + case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return; + default: return; + } } - bool get_instruction_offsets (unsigned int start_offset, - unsigned int end_offset, - unsigned int *instruction_start /* OUT */, - unsigned int *instruction_end /* OUT */) const + /* Note: Recursively calls itself. + * all_points includes phantom points + */ + bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, + contour_point_vector_t &all_points /* OUT */, + bool phantom_only = false, + unsigned int depth = 0) const { - if (end_offset - start_offset < GlyphHeader::static_size) + if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; + contour_point_vector_t points; + + switch (type) { + case COMPOSITE: { - *instruction_start = 0; - *instruction_end = 0; - return true; /* Empty glyph; no instructions. */ + /* pseudo component points for each component in composite glyph */ + unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ()); + if (unlikely (!points.resize (num_points))) return false; + for (unsigned i = 0; i < points.length; i++) + points[i].init (); + break; } - const GlyphHeader &glyph_header = StructAtOffset (glyf_table, start_offset); - int16_t num_contours = (int16_t) glyph_header.numberOfContours; - if (num_contours < 0) + case SIMPLE: + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) + return false; + break; + } + + /* Init phantom points */ + if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; + hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); { - CompositeGlyphHeader::Iterator composite_it; - if (unlikely (!CompositeGlyphHeader::get_iterator ( - (const char*) this->glyf_table + start_offset, - end_offset - start_offset, &composite_it))) return false; - const CompositeGlyphHeader *last; - do { - last = composite_it.current; - } while (composite_it.move_to_next ()); - - if ((uint16_t) last->flags & CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS) - *instruction_start = ((char *) last - (char *) glyf_table->dataZ.arrayZ) + last->get_size (); - else - *instruction_start = end_offset; - *instruction_end = end_offset; - if (unlikely (*instruction_start > *instruction_end)) + for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init (); + int h_delta = (int) header->xMin - glyf_accelerator.hmtx->get_side_bearing (gid); + int v_orig = (int) header->yMax + glyf_accelerator.vmtx->get_side_bearing (gid); + unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid); + unsigned v_adv = glyf_accelerator.vmtx->get_advance (gid); + phantoms[PHANTOM_LEFT].x = h_delta; + phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; + phantoms[PHANTOM_TOP].y = v_orig; + phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; + } + +#ifndef HB_NO_VAR + if (unlikely (!glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()))) + return false; +#endif + + switch (type) { + case SIMPLE: + all_points.extend (points.as_array ()); + break; + case COMPOSITE: + { + unsigned int comp_index = 0; + for (auto &item : get_composite_iterator ()) { - DEBUG_MSG(SUBSET, nullptr, "Invalid instruction offset, %d is outside [%d, %d]", *instruction_start, start_offset, end_offset); - return false; + contour_point_vector_t comp_points; + if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_glyph_index ()) + .get_points (font, glyf_accelerator, comp_points, + phantom_only, depth + 1) + || comp_points.length < PHANTOM_COUNT)) + return false; + + /* Copy phantom points from component if USE_MY_METRICS flag set */ + if (item.is_use_my_metrics ()) + for (unsigned int i = 0; i < PHANTOM_COUNT; i++) + phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; + + /* Apply component transformation & translation */ + item.transform_points (comp_points); + + /* Apply translation from gvar */ + comp_points.translate (points[comp_index]); + + if (item.is_anchored ()) + { + unsigned int p1, p2; + item.get_anchor_points (p1, p2); + if (likely (p1 < all_points.length && p2 < comp_points.length)) + { + contour_point_t delta; + delta.init (all_points[p1].x - comp_points[p2].x, + all_points[p1].y - comp_points[p2].y); + + comp_points.translate (delta); + } + } + + all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); + + comp_index++; } + + all_points.extend (phantoms); + } break; + default: + all_points.extend (phantoms); } - else + + if (depth == 0) /* Apply at top level */ { - unsigned int instruction_length_offset = start_offset + GlyphHeader::static_size + 2 * num_contours; - if (unlikely (instruction_length_offset + 2 > end_offset)) + /* Undocumented rasterizer behavior: + * Shift points horizontally by the updated left side bearing + */ + contour_point_t delta; + delta.init (-phantoms[PHANTOM_LEFT].x, 0.f); + if (delta.x) all_points.translate (delta); + } + + return true; + } + + bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, + hb_glyph_extents_t *extents) const + { + if (type == EMPTY) return true; /* Empty glyph; zero extents. */ + return header->get_extents (font, glyf_accelerator, gid, extents); + } + + hb_bytes_t get_bytes () const { return bytes; } + + Glyph (hb_bytes_t bytes_ = hb_bytes_t (), + hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_), + header (bytes.as ()) + { + int num_contours = header->numberOfContours; + if (unlikely (num_contours == 0)) type = EMPTY; + else if (num_contours > 0) type = SIMPLE; + else type = COMPOSITE; /* negative numbers */ + } + + protected: + hb_bytes_t bytes; + hb_codepoint_t gid; + const GlyphHeader *header; + unsigned type; + }; + + struct accelerator_t + { + void init (hb_face_t *face_) + { + short_offset = false; + num_glyphs = 0; + loca_table = nullptr; + glyf_table = nullptr; +#ifndef HB_NO_VAR + gvar = nullptr; +#endif + hmtx = nullptr; + vmtx = nullptr; + face = face_; + const OT::head &head = *face->table.head; + if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) + /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ + return; + short_offset = 0 == head.indexToLocFormat; + + loca_table = hb_sanitize_context_t ().reference_table (face); + glyf_table = hb_sanitize_context_t ().reference_table (face); +#ifndef HB_NO_VAR + gvar = face->table.gvar; +#endif + hmtx = face->table.hmtx; + vmtx = face->table.vmtx; + + num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; + num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); + } + + void fini () + { + loca_table.destroy (); + glyf_table.destroy (); + } + + protected: + template + bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const + { + if (gid >= num_glyphs) return false; + + /* Making this alloc free is not that easy + https://github.com/harfbuzz/harfbuzz/issues/2095 + mostly because of gvar handling in VF fonts, + perhaps a separate path for non-VF fonts can be considered */ + contour_point_vector_t all_points; + + bool phantom_only = !consumer.is_consuming_contour_points (); + if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only))) + return false; + + if (consumer.is_consuming_contour_points ()) + { + for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index) + consumer.consume_point (all_points[point_index]); + consumer.points_end (); + } + + /* Where to write phantoms, nullptr if not requested */ + contour_point_t *phantoms = consumer.get_phantoms_sink (); + if (phantoms) + for (unsigned i = 0; i < PHANTOM_COUNT; ++i) + phantoms[i] = all_points[all_points.length - PHANTOM_COUNT + i]; + + return true; + } + +#ifndef HB_NO_VAR + struct points_aggregator_t + { + hb_font_t *font; + hb_glyph_extents_t *extents; + contour_point_t *phantoms; + + struct contour_bounds_t + { + contour_bounds_t () { min_x = min_y = FLT_MAX; max_x = max_y = -FLT_MAX; } + + void add (const contour_point_t &p) { - DEBUG_MSG(SUBSET, nullptr, "Glyph size is too short, missing field instructionLength."); - return false; + min_x = hb_min (min_x, p.x); + min_y = hb_min (min_y, p.y); + max_x = hb_max (max_x, p.x); + max_y = hb_max (max_y, p.y); } - const HBUINT16 &instruction_length = StructAtOffset (glyf_table, instruction_length_offset); - unsigned int start = instruction_length_offset + 2; - unsigned int end = start + (uint16_t) instruction_length; - if (unlikely (end > end_offset)) // Out of bounds of the current glyph + bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } + + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) { - DEBUG_MSG(SUBSET, nullptr, "The instructions array overruns the glyph's boundaries."); - return false; + if (unlikely (empty ())) + { + extents->width = 0; + extents->x_bearing = 0; + extents->height = 0; + extents->y_bearing = 0; + return; + } + extents->x_bearing = font->em_scalef_x (min_x); + extents->width = font->em_scalef_x (max_x - min_x); + extents->y_bearing = font->em_scalef_y (max_y); + extents->height = font->em_scalef_y (min_y - max_y); } - *instruction_start = start; - *instruction_end = end; + protected: + float min_x, min_y, max_x, max_y; + } bounds; + + points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_) + { + font = font_; + extents = extents_; + phantoms = phantoms_; + if (extents) bounds = contour_bounds_t (); } - return true; + + void consume_point (const contour_point_t &point) { bounds.add (point); } + void points_end () { bounds.get_extents (font, extents); } + + bool is_consuming_contour_points () { return extents; } + contour_point_t *get_phantoms_sink () { return phantoms; } + }; + + public: + unsigned + get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const + { + if (unlikely (gid >= num_glyphs)) return 0; + + bool success = false; + + contour_point_t phantoms[PHANTOM_COUNT]; + if (likely (font->num_coords == gvar->get_axis_count ())) + success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms)); + + if (unlikely (!success)) + return is_vertical ? vmtx->get_advance (gid) : hmtx->get_advance (gid); + + float result = is_vertical + ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y + : phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x; + return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); } - bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { + if (unlikely (gid >= num_glyphs)) return 0; + + hb_glyph_extents_t extents; + + contour_point_t phantoms[PHANTOM_COUNT]; + if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms)))) + return is_vertical ? vmtx->get_side_bearing (gid) : hmtx->get_side_bearing (gid); + + return is_vertical + ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing + : floorf (phantoms[PHANTOM_LEFT].x); + } +#endif + + public: + bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const + { + if (unlikely (gid >= num_glyphs)) return false; + +#ifndef HB_NO_VAR + if (font->num_coords && font->num_coords == gvar->get_axis_count ()) + return get_points (font, gid, points_aggregator_t (font, extents, nullptr)); +#endif + return glyph_for_gid (gid).get_extents (font, *this, extents); + } + + const Glyph + glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const + { + if (unlikely (gid >= num_glyphs)) return Glyph (); + unsigned int start_offset, end_offset; - if (!get_offsets (glyph, &start_offset, &end_offset)) - return false; - if (end_offset - start_offset < GlyphHeader::static_size) - return true; /* Empty glyph; zero extents. */ + if (short_offset) + { + const HBUINT16 *offsets = (const HBUINT16 *) loca_table->dataZ.arrayZ; + start_offset = 2 * offsets[gid]; + end_offset = 2 * offsets[gid + 1]; + } + else + { + const HBUINT32 *offsets = (const HBUINT32 *) loca_table->dataZ.arrayZ; + start_offset = offsets[gid]; + end_offset = offsets[gid + 1]; + } + + if (unlikely (start_offset > end_offset || end_offset > glyf_table.get_length ())) + return Glyph (); - const GlyphHeader &glyph_header = StructAtOffset (glyf_table, start_offset); + Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset, + end_offset - start_offset), gid); + return needs_padding_removal ? glyph.trim_padding () : glyph; + } - extents->x_bearing = MIN (glyph_header.xMin, glyph_header.xMax); - extents->y_bearing = MAX (glyph_header.yMin, glyph_header.yMax); - extents->width = MAX (glyph_header.xMin, glyph_header.xMax) - extents->x_bearing; - extents->height = MIN (glyph_header.yMin, glyph_header.yMax) - extents->y_bearing; + void + add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain, + unsigned int depth = 0) const + { + if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return; + /* Check if is already visited */ + if (gids_to_retain->has (gid)) return; - return true; + gids_to_retain->add (gid); + + for (auto &item : glyph_for_gid (gid).get_composite_iterator ()) + add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth); } +#ifdef HB_EXPERIMENTAL_API + struct path_builder_t + { + hb_font_t *font; + draw_helper_t *draw_helper; + + struct optional_point_t + { + optional_point_t () { has_data = false; } + optional_point_t (float x_, float y_) { x = x_; y = y_; has_data = true; } + + bool has_data; + float x; + float y; + + optional_point_t lerp (optional_point_t p, float t) + { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } + } first_oncurve, first_offcurve, last_offcurve; + + path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_) + { + font = font_; + draw_helper = &draw_helper_; + first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + } + + /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 + See also: + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html + * https://stackoverflow.com/a/20772557 */ + void consume_point (const contour_point_t &point) + { + /* Skip empty contours */ + if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data)) + return; + + bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE; + optional_point_t p (point.x, point.y); + if (!first_oncurve.has_data) + { + if (is_on_curve) + { + first_oncurve = p; + draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + } + else + { + if (first_offcurve.has_data) + { + optional_point_t mid = first_offcurve.lerp (p, .5f); + first_oncurve = mid; + last_offcurve = p; + draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + } + else + first_offcurve = p; + } + } + else + { + if (last_offcurve.has_data) + { + if (is_on_curve) + { + draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), + font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + last_offcurve = optional_point_t (); + } + else + { + optional_point_t mid = last_offcurve.lerp (p, .5f); + draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), + font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + last_offcurve = p; + } + } + else + { + if (is_on_curve) + draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + else + last_offcurve = p; + } + } + + if (point.is_end_point) + { + if (first_offcurve.has_data && last_offcurve.has_data) + { + optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); + draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), + font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + last_offcurve = optional_point_t (); + /* now check the rest */ + } + + if (first_offcurve.has_data && first_oncurve.has_data) + draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y), + font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + else if (last_offcurve.has_data && first_oncurve.has_data) + draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), + font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + else if (first_oncurve.has_data) + draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + + /* Getting ready for the next contour */ + first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + draw_helper->end_path (); + } + } + void points_end () {} + + bool is_consuming_contour_points () { return true; } + contour_point_t *get_phantoms_sink () { return nullptr; } + }; + + bool + get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const + { return get_points (font, gid, path_builder_t (font, draw_helper)); } +#endif + +#ifndef HB_NO_VAR + const gvar_accelerator_t *gvar; +#endif + const hmtx_accelerator_t *hmtx; + const vmtx_accelerator_t *vmtx; + private: bool short_offset; unsigned int num_glyphs; hb_blob_ptr_t loca_table; hb_blob_ptr_t glyf_table; + hb_face_t *face; + }; + + struct SubsetGlyph + { + hb_codepoint_t new_gid; + hb_codepoint_t old_gid; + Glyph source_glyph; + hb_bytes_t dest_start; /* region of source_glyph to copy first */ + hb_bytes_t dest_end; /* region of source_glyph to copy second */ + + bool serialize (hb_serialize_context_t *c, + const hb_subset_plan_t *plan) const + { + TRACE_SERIALIZE (this); + + hb_bytes_t dest_glyph = dest_start.copy (c); + dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); + unsigned int pad_length = padding (); + DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); + + HBUINT8 pad; + pad = 0; + while (pad_length > 0) + { + c->embed (pad); + pad_length--; + } + + if (unlikely (!dest_glyph.length)) return_trace (true); + + /* update components gids */ + for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) + { + hb_codepoint_t new_gid; + if (plan->new_gid_for_old_gid (_.get_glyph_index (), &new_gid)) + const_cast (_).set_glyph_index (new_gid); + } + + if (plan->drop_hints) Glyph (dest_glyph).drop_hints (); + + return_trace (true); + } + + void drop_hints_bytes () + { source_glyph.drop_hints_bytes (dest_start, dest_end); } + + unsigned int length () const { return dest_start.length + dest_end.length; } + /* pad to 2 to ensure 2-byte loca will be ok */ + unsigned int padding () const { return length () % 2; } + unsigned int padded_size () const { return length () + padding (); } }; protected: - UnsizedArrayOf dataZ; /* Glyphs data. */ + UnsizedArrayOf + dataZ; /* Glyphs data. */ public: - DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always - * check the size externally, allow Null() object of it by - * defining it MIN() instead. */ + DEFINE_SIZE_MIN (0); /* In reality, this is UNBOUNDED() type; but since we always + * check the size externally, allow Null() object of it by + * defining it _MIN instead. */ }; struct glyf_accelerator_t : glyf::accelerator_t {}; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh index d27d098b69f..201ffc50be7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh @@ -41,68 +41,31 @@ namespace OT { struct DeviceRecord { - struct SubsetView - { - const DeviceRecord *source_device_record; - unsigned int sizeDeviceRecord; - hb_subset_plan_t *subset_plan; - - void init (const DeviceRecord *source_device_record, - unsigned int sizeDeviceRecord, - hb_subset_plan_t *subset_plan) - { - this->source_device_record = source_device_record; - this->sizeDeviceRecord = sizeDeviceRecord; - this->subset_plan = subset_plan; - } - - unsigned int len () const - { return this->subset_plan->glyphs.length; } - - const HBUINT8* operator [] (unsigned int i) const - { - if (unlikely (i >= len ())) return nullptr; - hb_codepoint_t gid = this->subset_plan->glyphs [i]; - - if (gid >= sizeDeviceRecord - DeviceRecord::min_size) - return nullptr; - return &(this->source_device_record->widthsZ[gid]); - } - }; - - static unsigned int get_size (unsigned int count) + static unsigned int get_size (unsigned count) { return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); } - bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view) + template + bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it) { TRACE_SERIALIZE (this); - unsigned int size = get_size (subset_view.len ()); - if (unlikely (!c->allocate_size (size))) - { - DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.", - size); - return_trace (false); - } - - this->pixelSize.set (subset_view.source_device_record->pixelSize); - this->maxWidth.set (subset_view.source_device_record->maxWidth); - - for (unsigned int i = 0; i < subset_view.len (); i++) - { - const HBUINT8 *width = subset_view[i]; - if (!width) - { - DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i); - return_trace (false); - } - widthsZ[i].set (*width); - } + unsigned length = it.len (); + + if (unlikely (!c->extend (*this, length))) return_trace (false); + + this->pixelSize = pixelSize; + this->maxWidth = + + it + | hb_reduce (hb_max, 0u); + + + it + | hb_sink (widthsZ.as_array (length)); return_trace (true); } - bool sanitize (hb_sanitize_context_t *c, unsigned int sizeDeviceRecord) const + bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && @@ -132,62 +95,60 @@ struct hdmx return StructAtOffset (&this->firstDeviceRecord, i * sizeDeviceRecord); } - bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan) + template + bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min ((*this)))) return_trace (false); - this->version.set (source_hdmx->version); - this->numRecords.set (source_hdmx->numRecords); - this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->glyphs.length)); + this->version = version; + this->numRecords = it.len (); + this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0); - for (unsigned int i = 0; i < source_hdmx->numRecords; i++) - { - DeviceRecord::SubsetView subset_view; - subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan); + for (const hb_item_type& _ : +it) + c->start_embed ()->serialize (c, _.first, _.second); - if (!c->start_embed ()->serialize (c, subset_view)) - return_trace (false); - } - - return_trace (true); + return_trace (c->successful); } - static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan) + + bool subset (hb_subset_context_t *c) const { - return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->glyphs.length); + TRACE_SUBSET (this); + + hdmx *hdmx_prime = c->serializer->start_embed (); + if (unlikely (!hdmx_prime)) return_trace (false); + + auto it = + + hb_range ((unsigned) numRecords) + | hb_map ([c, this] (unsigned _) + { + const DeviceRecord *device_record = + &StructAtOffset (&firstDeviceRecord, + _ * sizeDeviceRecord); + auto row = + + hb_range (c->plan->num_output_glyphs ()) + | hb_map (c->plan->reverse_glyph_map) + | hb_map ([this, c, device_record] (hb_codepoint_t _) + { + if (c->plan->is_empty_glyph (_)) + return Null (HBUINT8); + return device_record->widthsZ.as_array (get_num_glyphs ()) [_]; + }) + ; + return hb_pair ((unsigned) device_record->pixelSize, +row); + }) + ; + + hdmx_prime->serialize (c->serializer, version, it); + return_trace (true); } - bool subset (hb_subset_plan_t *plan) const + unsigned get_num_glyphs () const { - size_t dest_size = get_subsetted_size (this, plan); - hdmx *dest = (hdmx *) malloc (dest_size); - if (unlikely (!dest)) - { - DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for hdmx subset output.", (unsigned long) dest_size); - return false; - } - - hb_serialize_context_t c (dest, dest_size); - hdmx *hdmx_prime = c.start_serialize (); - if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan)) - { - free (dest); - DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx."); - return false; - } - c.end_serialize (); - - hb_blob_t *hdmx_prime_blob = hb_blob_create ((const char *) dest, - dest_size, - HB_MEMORY_MODE_READONLY, - dest, - free); - bool result = plan->add_table (HB_OT_TAG_hdmx, hdmx_prime_blob); - hb_blob_destroy (hdmx_prime_blob); - - return result; + return sizeDeviceRecord - DeviceRecord::min_size; } bool sanitize (hb_sanitize_context_t *c) const @@ -200,10 +161,12 @@ struct hdmx } protected: - HBUINT16 version; /* Table version number (0) */ - HBUINT16 numRecords; /* Number of device records. */ - HBUINT32 sizeDeviceRecord; /* Size of a device record, 32-bit aligned. */ - DeviceRecord firstDeviceRecord; /* Array of device records. */ + HBUINT16 version; /* Table version number (0) */ + HBUINT16 numRecords; /* Number of device records. */ + HBUINT32 sizeDeviceRecord; + /* Size of a device record, 32-bit aligned. */ + DeviceRecord firstDeviceRecord; + /* Array of device records. */ public: DEFINE_SIZE_MIN (8); }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh index d7448d2dfce..3f4af706bc8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh @@ -54,6 +54,18 @@ struct head return 16 <= upem && upem <= 16384 ? upem : 1000; } + bool serialize (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace ((bool) c->embed (this)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace (serialize (c->serializer)); + } + enum mac_style_flag_t { BOLD = 1u<<0, ITALIC = 1u<<1, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh index 66879a085a0..37ef8744572 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hhea-table.hh @@ -45,6 +45,8 @@ namespace OT { template struct _hea { + bool has_data () const { return version.major; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -52,35 +54,38 @@ struct _hea } public: - FixedVersion<>version; /* 0x00010000u for version 1.0. */ - FWORD ascender; /* Typographic ascent. */ - FWORD descender; /* Typographic descent. */ - FWORD lineGap; /* Typographic line gap. */ - UFWORD advanceMax; /* Maximum advance width/height value in - * metrics table. */ - FWORD minLeadingBearing; /* Minimum left/top sidebearing value in - * metrics table. */ - FWORD minTrailingBearing; /* Minimum right/bottom sidebearing value; - * calculated as Min(aw - lsb - - * (xMax - xMin)) for horizontal. */ - FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)), - * vertical: minLeadingBearing+(yMax-yMin). */ - HBINT16 caretSlopeRise; /* Used to calculate the slope of the - * cursor (rise/run); 1 for vertical caret, - * 0 for horizontal.*/ - HBINT16 caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */ - HBINT16 caretOffset; /* The amount by which a slanted - * highlight on a glyph needs - * to be shifted to produce the - * best appearance. Set to 0 for - * non-slanted fonts. */ - HBINT16 reserved1; /* Set to 0. */ - HBINT16 reserved2; /* Set to 0. */ - HBINT16 reserved3; /* Set to 0. */ - HBINT16 reserved4; /* Set to 0. */ - HBINT16 metricDataFormat; /* 0 for current format. */ - HBUINT16 numberOfLongMetrics; /* Number of LongMetric entries in metric - * table. */ + FixedVersion<>version; /* 0x00010000u for version 1.0. */ + FWORD ascender; /* Typographic ascent. */ + FWORD descender; /* Typographic descent. */ + FWORD lineGap; /* Typographic line gap. */ + UFWORD advanceMax; /* Maximum advance width/height value in + * metrics table. */ + FWORD minLeadingBearing; + /* Minimum left/top sidebearing value in + * metrics table. */ + FWORD minTrailingBearing; + /* Minimum right/bottom sidebearing value; + * calculated as Min(aw - lsb - + * (xMax - xMin)) for horizontal. */ + FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)), + * vertical: minLeadingBearing+(yMax-yMin). */ + HBINT16 caretSlopeRise; /* Used to calculate the slope of the + * cursor (rise/run); 1 for vertical caret, + * 0 for horizontal.*/ + HBINT16 caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */ + HBINT16 caretOffset; /* The amount by which a slanted + * highlight on a glyph needs + * to be shifted to produce the + * best appearance. Set to 0 for + * non-slanted fonts. */ + HBINT16 reserved1; /* Set to 0. */ + HBINT16 reserved2; /* Set to 0. */ + HBINT16 reserved3; /* Set to 0. */ + HBINT16 reserved4; /* Set to 0. */ + HBINT16 metricDataFormat;/* 0 for current format. */ + HBUINT16 numberOfLongMetrics; + /* Number of LongMetric entries in metric + * table. */ public: DEFINE_SIZE_STATIC (36); }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh index dfb0f78d643..0a2973d8eb8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh @@ -29,8 +29,8 @@ #include "hb-open-type.hh" #include "hb-ot-hhea-table.hh" -#include "hb-ot-os2-table.hh" #include "hb-ot-var-hvar-table.hh" +#include "hb-ot-metrics.hh" /* * hmtx -- Horizontal Metrics @@ -42,6 +42,13 @@ #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x') +HB_INTERNAL int +_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); + +HB_INTERNAL unsigned +_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); + + namespace OT { @@ -53,6 +60,7 @@ struct LongMetric DEFINE_SIZE_STATIC (4); }; + template struct hmtxvmtx { @@ -66,7 +74,7 @@ struct hmtxvmtx bool subset_update_header (hb_subset_plan_t *plan, - unsigned int num_hmetrics) const + unsigned int num_hmetrics) const { hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (plan->source, H::tableTag); hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); @@ -78,7 +86,7 @@ struct hmtxvmtx unsigned int length; H *table = (H *) hb_blob_get_data (dest_blob, &length); - table->numberOfLongMetrics.set (num_hmetrics); + table->numberOfLongMetrics = num_hmetrics; bool result = plan->add_table (H::tableTag, dest_blob); hb_blob_destroy (dest_blob); @@ -86,100 +94,66 @@ struct hmtxvmtx return result; } - bool subset (hb_subset_plan_t *plan) const + template + void serialize (hb_serialize_context_t *c, + Iterator it, + unsigned num_advances) { - typename T::accelerator_t _mtx; - _mtx.init (plan->source); - - /* All the trailing glyphs with the same advance can use one LongMetric - * and just keep LSB */ - hb_vector_t &gids = plan->glyphs; - unsigned int num_advances = gids.length; - unsigned int last_advance = _mtx.get_advance (gids[num_advances - 1]); - while (num_advances > 1 && - last_advance == _mtx.get_advance (gids[num_advances - 2])) - { - num_advances--; - } - - /* alloc the new table */ - size_t dest_sz = num_advances * 4 - + (gids.length - num_advances) * 2; - void *dest = (void *) malloc (dest_sz); - if (unlikely (!dest)) + unsigned idx = 0; + for (auto _ : it) { - return false; - } - DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in src has %d advances, %d lsbs", HB_UNTAG(T::tableTag), _mtx.num_advances, _mtx.num_metrics - _mtx.num_advances); - DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, gids.length - num_advances, (unsigned int) dest_sz); - - const char *source_table = hb_blob_get_data (_mtx.table.get_blob (), nullptr); - // Copy everything over - LongMetric * old_metrics = (LongMetric *) source_table; - FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances); - char * dest_pos = (char *) dest; - - bool failed = false; - for (unsigned int i = 0; i < gids.length; i++) - { - /* the last metric or the one for gids[i] */ - LongMetric *src_metric = old_metrics + MIN ((hb_codepoint_t) _mtx.num_advances - 1, gids[i]); - if (gids[i] < _mtx.num_advances) + if (idx < num_advances) { - /* src is a LongMetric */ - if (i < num_advances) - { - /* dest is a LongMetric, copy it */ - *((LongMetric *) dest_pos) = *src_metric; - } - else - { - /* dest just sb */ - *((FWORD *) dest_pos) = src_metric->sb; - } + LongMetric lm; + lm.advance = _.first; + lm.sb = _.second; + if (unlikely (!c->embed (&lm))) return; } else { - if (gids[i] >= _mtx.num_metrics) - { - DEBUG_MSG(SUBSET, nullptr, "gid %d is >= number of source metrics %d", - gids[i], _mtx.num_metrics); - failed = true; - break; - } - FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances); - if (i < num_advances) - { - /* dest needs a full LongMetric */ - LongMetric *metric = (LongMetric *)dest_pos; - metric->advance = src_metric->advance; - metric->sb = src_sb; - } - else - { - /* dest just needs an sb */ - *((FWORD *) dest_pos) = src_sb; - } + FWORD *sb = c->allocate_size (FWORD::static_size); + if (unlikely (!sb)) return; + *sb = _.second; } - dest_pos += (i < num_advances ? 4 : 2); + idx++; } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + T *table_prime = c->serializer->start_embed (); + if (unlikely (!table_prime)) return_trace (false); + + accelerator_t _mtx; + _mtx.init (c->plan->source); + unsigned num_advances = _mtx.num_advances_for_subset (c->plan); + + auto it = + + hb_range (c->plan->num_output_glyphs ()) + | hb_map ([c, &_mtx] (unsigned _) + { + hb_codepoint_t old_gid; + if (!c->plan->old_gid_for_new_gid (_, &old_gid)) + return hb_pair (0u, 0); + return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid)); + }) + ; + + table_prime->serialize (c->serializer, it, num_advances); + _mtx.fini (); + if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ())) + return_trace (false); + // Amend header num hmetrics - if (failed || unlikely (!subset_update_header (plan, num_advances))) - { - free (dest); - return false; - } + if (unlikely (!subset_update_header (c->plan, num_advances))) + return_trace (false); - hb_blob_t *result = hb_blob_create ((const char *)dest, - dest_sz, - HB_MEMORY_MODE_READONLY, - dest, - free); - bool success = plan->add_table (T::tableTag, result); - hb_blob_destroy (result); - return success; + return_trace (true); } struct accelerator_t @@ -187,34 +161,13 @@ struct hmtxvmtx friend struct hmtxvmtx; void init (hb_face_t *face, - unsigned int default_advance_ = 0) + unsigned int default_advance_ = 0) { default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); - bool got_font_extents = false; - if (T::os2Tag != HB_TAG_NONE && face->table.OS2->is_typo_metrics ()) - { - ascender = abs (face->table.OS2->sTypoAscender); - descender = -abs (face->table.OS2->sTypoDescender); - line_gap = face->table.OS2->sTypoLineGap; - got_font_extents = (ascender | descender) != 0; - } + num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics; - hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table (face); - const H *_hea_table = _hea_blob->as (); - num_advances = _hea_table->numberOfLongMetrics; - if (!got_font_extents) - { - ascender = abs (_hea_table->ascender); - descender = -abs (_hea_table->descender); - line_gap = _hea_table->lineGap; - got_font_extents = (ascender | descender) != 0; - } - hb_blob_destroy (_hea_blob); - - has_font_extents = got_font_extents; - - table = hb_sanitize_context_t().reference_table (face, T::tableTag); + table = hb_sanitize_context_t ().reference_table (face, T::tableTag); /* Cap num_metrics() and num_advances() based on table length. */ unsigned int len = table.get_length (); @@ -231,7 +184,7 @@ struct hmtxvmtx table = hb_blob_get_empty (); } - var_table = hb_sanitize_context_t().reference_table (face, T::variationsTag); + var_table = hb_sanitize_context_t ().reference_table (face, T::variationsTag); } void fini () @@ -240,8 +193,7 @@ struct hmtxvmtx var_table.destroy (); } - /* TODO Add variations version. */ - unsigned int get_side_bearing (hb_codepoint_t glyph) const + int get_side_bearing (hb_codepoint_t glyph) const { if (glyph < num_advances) return table->longMetricZ[glyph].sb; @@ -253,6 +205,23 @@ struct hmtxvmtx return bearings[glyph - num_advances]; } + int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const + { + int side_bearing = get_side_bearing (glyph); + +#ifndef HB_NO_VAR + if (unlikely (glyph >= num_metrics) || !font->num_coords) + return side_bearing; + + if (var_table.get_length ()) + return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! + + return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); +#else + return side_bearing; +#endif + } + unsigned int get_advance (hb_codepoint_t glyph) const { if (unlikely (glyph >= num_metrics)) @@ -266,25 +235,52 @@ struct hmtxvmtx return default_advance; } - return table->longMetricZ[MIN (glyph, (uint32_t) num_advances - 1)].advance; + return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance; } unsigned int get_advance (hb_codepoint_t glyph, hb_font_t *font) const { unsigned int advance = get_advance (glyph); - if (likely (glyph < num_metrics)) + +#ifndef HB_NO_VAR + if (unlikely (glyph >= num_metrics) || !font->num_coords) + return advance; + + if (var_table.get_length ()) + return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?! + + return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); +#else + return advance; +#endif + } + + unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const + { + unsigned int num_advances = plan->num_output_glyphs (); + unsigned int last_advance = _advance_for_new_gid (plan, + num_advances - 1); + while (num_advances > 1 && + last_advance == _advance_for_new_gid (plan, + num_advances - 2)) { - advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?! + num_advances--; } - return advance; + + return num_advances; } - public: - bool has_font_extents; - int ascender; - int descender; - int line_gap; + private: + unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan, + hb_codepoint_t new_gid) const + { + hb_codepoint_t old_gid; + if (!plan->old_gid_for_new_gid (new_gid, &old_gid)) + return 0; + + return get_advance (old_gid); + } protected: unsigned int num_metrics; @@ -297,27 +293,29 @@ struct hmtxvmtx }; protected: - UnsizedArrayOflongMetricZ;/* Paired advance width and leading - * bearing values for each glyph. The - * value numOfHMetrics comes from - * the 'hhea' table. If the font is - * monospaced, only one entry need - * be in the array, but that entry is - * required. The last entry applies to - * all subsequent glyphs. */ -/*UnsizedArrayOf leadingBearingX;*//* Here the advance is assumed - * to be the same as the advance - * for the last entry above. The - * number of entries in this array is - * derived from numGlyphs (from 'maxp' - * table) minus numberOfLongMetrics. - * This generally is used with a run - * of monospaced glyphs (e.g., Kanji - * fonts or Courier fonts). Only one - * run is allowed and it must be at - * the end. This allows a monospaced - * font to vary the side bearing - * values for each glyph. */ + UnsizedArrayOf + longMetricZ; /* Paired advance width and leading + * bearing values for each glyph. The + * value numOfHMetrics comes from + * the 'hhea' table. If the font is + * monospaced, only one entry need + * be in the array, but that entry is + * required. The last entry applies to + * all subsequent glyphs. */ +/*UnsizedArrayOf leadingBearingX;*/ + /* Here the advance is assumed + * to be the same as the advance + * for the last entry above. The + * number of entries in this array is + * derived from numGlyphs (from 'maxp' + * table) minus numberOfLongMetrics. + * This generally is used with a run + * of monospaced glyphs (e.g., Kanji + * fonts or Courier fonts). Only one + * run is allowed and it must be at + * the end. This allows a monospaced + * font to vary the side bearing + * values for each glyph. */ public: DEFINE_SIZE_ARRAY (0, longMetricZ); }; @@ -325,12 +323,12 @@ struct hmtxvmtx struct hmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; - static constexpr hb_tag_t os2Tag = HB_OT_TAG_OS2; + static constexpr bool is_horizontal = true; }; struct vmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; - static constexpr hb_tag_t os2Tag = HB_TAG_NONE; + static constexpr bool is_horizontal = false; }; struct hmtx_accelerator_t : hmtx::accelerator_t {}; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh index 9d870ecfc8a..37ea1276ea6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-kern-table.hh @@ -47,9 +47,9 @@ struct KernSubTableFormat3 int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const { hb_array_t kernValue = kernValueZ.as_array (kernValueCount); - hb_array_t leftClass = StructAfter > (kernValue).as_array (glyphCount); - hb_array_t rightClass = StructAfter > (leftClass).as_array (glyphCount); - hb_array_t kernIndex = StructAfter > (rightClass).as_array (leftClassCount * rightClassCount); + hb_array_t leftClass = StructAfter> (kernValue).as_array (glyphCount); + hb_array_t rightClass = StructAfter> (leftClass).as_array (glyphCount); + hb_array_t kernIndex = StructAfter> (rightClass).as_array (leftClassCount * rightClassCount); unsigned int leftC = leftClass[left]; unsigned int rightC = rightClass[right]; @@ -86,21 +86,26 @@ struct KernSubTableFormat3 } protected: - KernSubTableHeader header; - HBUINT16 glyphCount; /* The number of glyphs in this font. */ - HBUINT8 kernValueCount; /* The number of kerning values. */ - HBUINT8 leftClassCount; /* The number of left-hand classes. */ - HBUINT8 rightClassCount;/* The number of right-hand classes. */ - HBUINT8 flags; /* Set to zero (reserved for future use). */ - UnsizedArrayOf kernValueZ; /* The kerning values. - * Length kernValueCount. */ + KernSubTableHeader + header; + HBUINT16 glyphCount; /* The number of glyphs in this font. */ + HBUINT8 kernValueCount; /* The number of kerning values. */ + HBUINT8 leftClassCount; /* The number of left-hand classes. */ + HBUINT8 rightClassCount;/* The number of right-hand classes. */ + HBUINT8 flags; /* Set to zero (reserved for future use). */ + UnsizedArrayOf + kernValueZ; /* The kerning values. + * Length kernValueCount. */ #if 0 - UnsizedArrayOfleftClass; /* The left-hand classes. - * Length glyphCount. */ - UnsizedArrayOfrightClass; /* The right-hand classes. - * Length glyphCount. */ - UnsizedArrayOfkernIndex; /* The indices into the kernValue array. - * Length leftClassCount * rightClassCount */ + UnsizedArrayOf + leftClass; /* The left-hand classes. + * Length glyphCount. */ + UnsizedArrayOf + rightClass; /* The right-hand classes. + * Length glyphCount. */ + UnsizedArrayOfkernIndex; + /* The indices into the kernValue array. + * Length leftClassCount * rightClassCount */ #endif public: DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ); @@ -121,16 +126,20 @@ struct KernSubTable } } - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { unsigned int subtable_type = get_type (); TRACE_DISPATCH (this, subtable_type); switch (subtable_type) { case 0: return_trace (c->dispatch (u.format0)); - case 1: return_trace (u.header.apple ? c->dispatch (u.format1) : c->default_return_value ()); +#ifndef HB_NO_AAT_SHAPE + case 1: return_trace (u.header.apple ? c->dispatch (u.format1, hb_forward (ds)...) : c->default_return_value ()); +#endif case 2: return_trace (c->dispatch (u.format2)); - case 3: return_trace (u.header.apple ? c->dispatch (u.format3) : c->default_return_value ()); +#ifndef HB_NO_AAT_SHAPE + case 3: return_trace (u.header.apple ? c->dispatch (u.format3, hb_forward (ds)...) : c->default_return_value ()); +#endif default: return_trace (c->default_return_value ()); } } @@ -163,8 +172,8 @@ struct KernOTSubTableHeader static constexpr bool apple = false; typedef AAT::ObsoleteTypes Types; - unsigned int tuple_count () const { return 0; } - bool is_horizontal () const { return (coverage & Horizontal); } + unsigned tuple_count () const { return 0; } + bool is_horizontal () const { return (coverage & Horizontal); } enum Coverage { @@ -218,8 +227,8 @@ struct KernAATSubTableHeader static constexpr bool apple = true; typedef AAT::ObsoleteTypes Types; - unsigned int tuple_count () const { return 0; } - bool is_horizontal () const { return !(coverage & Vertical); } + unsigned tuple_count () const { return 0; } + bool is_horizontal () const { return !(coverage & Vertical); } enum Coverage { @@ -242,8 +251,8 @@ struct KernAATSubTableHeader HBUINT8 coverage; /* Coverage bits. */ HBUINT8 format; /* Subtable format. */ HBUINT16 tupleIndex; /* The tuple index (used for variations fonts). - * This value specifies which tuple this subtable covers. - * Note: We don't implement. */ + * This value specifies which tuple this subtable covers. + * Note: We don't implement. */ public: DEFINE_SIZE_STATIC (8); }; @@ -271,14 +280,16 @@ struct kern { static constexpr hb_tag_t tableTag = HB_OT_TAG_kern; - bool has_data () const { return u.version32; } - unsigned int get_type () const { return u.major; } + bool has_data () const { return u.version32; } + unsigned get_type () const { return u.major; } bool has_state_machine () const { switch (get_type ()) { case 0: return u.ot.has_state_machine (); +#ifndef HB_NO_AAT_SHAPE case 1: return u.aat.has_state_machine (); +#endif default:return false; } } @@ -287,7 +298,9 @@ struct kern { switch (get_type ()) { case 0: return u.ot.has_cross_stream (); +#ifndef HB_NO_AAT_SHAPE case 1: return u.aat.has_cross_stream (); +#endif default:return false; } } @@ -296,7 +309,9 @@ struct kern { switch (get_type ()) { case 0: return u.ot.get_h_kerning (left, right); +#ifndef HB_NO_AAT_SHAPE case 1: return u.aat.get_h_kerning (left, right); +#endif default:return 0; } } @@ -304,14 +319,16 @@ struct kern bool apply (AAT::hb_aat_apply_context_t *c) const { return dispatch (c); } - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { unsigned int subtable_type = get_type (); TRACE_DISPATCH (this, subtable_type); switch (subtable_type) { - case 0: return_trace (c->dispatch (u.ot)); - case 1: return_trace (c->dispatch (u.aat)); + case 0: return_trace (c->dispatch (u.ot, hb_forward (ds)...)); +#ifndef HB_NO_AAT_SHAPE + case 1: return_trace (c->dispatch (u.aat, hb_forward (ds)...)); +#endif default: return_trace (c->default_return_value ()); } } @@ -328,7 +345,9 @@ struct kern HBUINT32 version32; HBUINT16 major; KernOT ot; +#ifndef HB_NO_AAT_SHAPE KernAAT aat; +#endif } u; public: DEFINE_SIZE_UNION (4, version32); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh index fe30e278795..f8cdb046910 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh @@ -1,7 +1,7 @@ /* - * Copyright © 2016 Elie Roux + * Copyright © 2016 Elie Roux * Copyright © 2018 Google, Inc. - * Copyright © 2018 Ebrahim Byagowi + * Copyright © 2018-2019 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -32,9 +32,6 @@ #include "hb-open-type.hh" #include "hb-ot-layout-common.hh" -/* To be removed */ -typedef hb_tag_t hb_ot_layout_baseline_t; - namespace OT { /* @@ -76,7 +73,7 @@ struct BaseCoordFormat2 protected: HBUINT16 format; /* Format identifier--format = 2 */ FWORD coordinate; /* X or Y value, in design units */ - GlyphID referenceGlyph; /* Glyph ID of control glyph */ + HBGlyphID referenceGlyph; /* Glyph ID of control glyph */ HBUINT16 coordPoint; /* Index of contour point on the * reference glyph */ public: @@ -116,9 +113,11 @@ struct BaseCoordFormat3 struct BaseCoord { - hb_position_t get_coord (hb_font_t *font, + bool has_data () const { return u.format; } + + hb_position_t get_coord (hb_font_t *font, const VariationStore &var_store, - hb_direction_t direction) const + hb_direction_t direction) const { switch (u.format) { case 1: return u.format1.get_coord (); @@ -142,10 +141,10 @@ struct BaseCoord protected: union { - HBUINT16 format; - BaseCoordFormat1 format1; - BaseCoordFormat2 format2; - BaseCoordFormat3 format3; + HBUINT16 format; + BaseCoordFormat1 format1; + BaseCoordFormat2 format2; + BaseCoordFormat3 format3; } u; public: DEFINE_SIZE_UNION (2, format); @@ -153,14 +152,9 @@ struct BaseCoord struct FeatMinMaxRecord { - static int cmp (const void *key_, const void *entry_) - { - hb_tag_t key = * (hb_tag_t *) key_; - const FeatMinMaxRecord &entry = * (const FeatMinMaxRecord *) entry_; - return key < (unsigned int) entry.tag ? -1 : - key > (unsigned int) entry.tag ? 1 : - 0; - } + int cmp (hb_tag_t key) const { return tag.cmp (key); } + + bool has_data () const { return tag; } void get_min_max (const BaseCoord **min, const BaseCoord **max) const { @@ -195,17 +189,12 @@ struct FeatMinMaxRecord struct MinMax { void get_min_max (hb_tag_t feature_tag, - const BaseCoord **min, - const BaseCoord **max) const + const BaseCoord **min, + const BaseCoord **max) const { - /* TODO Replace hb_bsearch() with .bsearch(). */ - const FeatMinMaxRecord *minMaxCoord = (const FeatMinMaxRecord *) - hb_bsearch (&feature_tag, featMinMaxRecords.arrayZ, - featMinMaxRecords.len, - FeatMinMaxRecord::static_size, - FeatMinMaxRecord::cmp); - if (minMaxCoord) - minMaxCoord->get_min_max (min, max); + const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag); + if (minMaxCoord.has_data ()) + minMaxCoord.get_min_max (min, max); else { if (likely (min)) *min = &(this+minCoord); @@ -271,17 +260,11 @@ struct BaseValues struct BaseLangSysRecord { - static int cmp (const void *key_, const void *entry_) - { - hb_tag_t key = * (hb_tag_t *) key_; - const BaseLangSysRecord &entry = * (const BaseLangSysRecord *) entry_; - return key < (unsigned int) entry.baseLangSysTag ? -1 : - key > (unsigned int) entry.baseLangSysTag ? 1 : - 0; - } + int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); } + + bool has_data () const { return baseLangSysTag; } - const MinMax &get_min_max () const - { return this+minMax; } + const MinMax &get_min_max () const { return this+minMax; } bool sanitize (hb_sanitize_context_t *c, const void *base) const { @@ -303,19 +286,14 @@ struct BaseScript { const MinMax &get_min_max (hb_tag_t language_tag) const { - /* TODO Replace hb_bsearch() with .bsearch(). */ - const BaseLangSysRecord* record = (const BaseLangSysRecord *) - hb_bsearch (&language_tag, baseLangSysRecords.arrayZ, - baseLangSysRecords.len, - BaseLangSysRecord::static_size, - BaseLangSysRecord::cmp); - return record ? record->get_min_max () : this+defaultMinMax; + const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag); + return record.has_data () ? record.get_min_max () : this+defaultMinMax; } const BaseCoord &get_base_coord (int baseline_tag_index) const { return (this+baseValues).get_base_coord (baseline_tag_index); } - bool is_empty () const { return !baseValues; } + bool has_data () const { return baseValues; } bool sanitize (hb_sanitize_context_t *c) const { @@ -345,14 +323,9 @@ struct BaseScript struct BaseScriptList; struct BaseScriptRecord { - static int cmp (const void *key_, const void *entry_) - { - hb_tag_t key = * (hb_tag_t *) key_; - const BaseScriptRecord &entry = * (const BaseScriptRecord *) entry_; - return key < (unsigned int) entry.baseScriptTag ? -1 : - key > (unsigned int) entry.baseScriptTag ? 1 : - 0; - } + int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); } + + bool has_data () const { return baseScriptTag; } const BaseScript &get_base_script (const BaseScriptList *list) const { return list+baseScript; } @@ -376,22 +349,11 @@ struct BaseScriptRecord struct BaseScriptList { - const BaseScriptRecord *find_record (hb_tag_t script) const - { - /* TODO Replace hb_bsearch() with .bsearch(). */ - return (const BaseScriptRecord *) hb_bsearch (&script, baseScriptRecords.arrayZ, - baseScriptRecords.len, - BaseScriptRecord::static_size, - BaseScriptRecord::cmp); - } - - /* TODO: Or client should handle fallback? */ const BaseScript &get_base_script (hb_tag_t script) const { - const BaseScriptRecord *record = find_record (script); - if (!record) record = find_record ((hb_script_t) HB_TAG ('D','F','L','T')); - - return record ? record->get_base_script (this) : Null (BaseScript); + const BaseScriptRecord *record = &baseScriptRecords.bsearch (script); + if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T')); + return record->has_data () ? record->get_base_script (this) : Null (BaseScript); } bool sanitize (hb_sanitize_context_t *c) const @@ -411,15 +373,20 @@ struct BaseScriptList struct Axis { - bool get_baseline (hb_ot_layout_baseline_t baseline, - hb_tag_t script_tag, - hb_tag_t language_tag, - const BaseCoord **coord) const + bool get_baseline (hb_tag_t baseline_tag, + hb_tag_t script_tag, + hb_tag_t language_tag, + const BaseCoord **coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (base_script.is_empty ()) return false; + if (!base_script.has_data ()) return false; - if (likely (coord)) *coord = &base_script.get_base_coord ((this+baseTagList).bsearch (baseline)); + if (likely (coord)) + { + unsigned int tag_index = 0; + (this+baseTagList).bfind (baseline_tag, &tag_index); + *coord = &base_script.get_base_coord (tag_index); + } return true; } @@ -431,7 +398,7 @@ struct Axis const BaseCoord **max_coord) const { const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag); - if (base_script.is_empty ()) return false; + if (!base_script.has_data ()) return false; base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord); @@ -447,7 +414,7 @@ struct Axis } protected: - OffsetTo > + OffsetTo> baseTagList; /* Offset to BaseTagList table, from beginning * of Axis table (may be NULL) * Array of 4-byte baseline identification tags — must @@ -472,20 +439,21 @@ struct BASE const VariationStore &get_var_store () const { return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; } - bool get_baseline (hb_font_t *font, - hb_ot_layout_baseline_t baseline, - hb_direction_t direction, - hb_tag_t script_tag, - hb_tag_t language_tag, - hb_position_t *base) const + bool get_baseline (hb_font_t *font, + hb_tag_t baseline_tag, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *base) const { - const BaseCoord *base_coord; - if (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord)) + const BaseCoord *base_coord = nullptr; + if (unlikely (!get_axis (direction).get_baseline (baseline_tag, script_tag, language_tag, &base_coord) || + !base_coord || !base_coord->has_data ())) return false; - if (likely (base && base_coord)) *base = base_coord->get_coord (font, - get_var_store (), - direction); + if (likely (base)) + *base = base_coord->get_coord (font, get_var_store (), direction); + return true; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh index 7618057ed1c..56773e68e36 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh @@ -33,6 +33,7 @@ #include "hb-ot-layout.hh" #include "hb-open-type.hh" #include "hb-set.hh" +#include "hb-bimap.hh" #ifndef HB_MAX_NESTING_LEVEL @@ -59,6 +60,18 @@ #define HB_MAX_LANGSYS 2000 #endif +#ifndef HB_MAX_FEATURES +#define HB_MAX_FEATURES 750 +#endif + +#ifndef HB_MAX_FEATURE_INDICES +#define HB_MAX_FEATURE_INDICES 1500 +#endif + +#ifndef HB_MAX_LOOKUP_INDICES +#define HB_MAX_LOOKUP_INDICES 20000 +#endif + namespace OT { @@ -66,6 +79,213 @@ namespace OT { #define NOT_COVERED ((unsigned int) -1) +template +static inline void Coverage_serialize (hb_serialize_context_t *c, + Iterator it); + +template +static inline void ClassDef_serialize (hb_serialize_context_t *c, + Iterator it); + +static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, + const hb_set_t &glyphset, + const hb_map_t &gid_klass_map, + hb_sorted_vector_t &glyphs, + const hb_set_t &klasses, + hb_map_t *klass_map /*INOUT*/); + +struct hb_subset_layout_context_t : + hb_dispatch_context_t +{ + const char *get_name () { return "SUBSET_LAYOUT"; } + static return_t default_return_value () { return hb_empty_t (); } + + bool visitScript () + { + return script_count++ < HB_MAX_SCRIPTS; + } + + bool visitLangSys () + { + return langsys_count++ < HB_MAX_LANGSYS; + } + + bool visitFeatureIndex (int count) + { + feature_index_count += count; + return feature_index_count < HB_MAX_FEATURE_INDICES; + } + + bool visitLookupIndex() + { + lookup_index_count++; + return lookup_index_count < HB_MAX_LOOKUP_INDICES; + } + + hb_subset_context_t *subset_context; + const hb_tag_t table_tag; + const hb_map_t *lookup_index_map; + const hb_map_t *feature_index_map; + + hb_subset_layout_context_t (hb_subset_context_t *c_, + hb_tag_t tag_, + hb_map_t *lookup_map_, + hb_map_t *feature_map_) : + subset_context (c_), + table_tag (tag_), + lookup_index_map (lookup_map_), + feature_index_map (feature_map_), + script_count (0), + langsys_count (0), + feature_index_count (0), + lookup_index_count (0) + {} + + private: + unsigned script_count; + unsigned langsys_count; + unsigned feature_index_count; + unsigned lookup_index_count; +}; + +struct hb_collect_variation_indices_context_t : + hb_dispatch_context_t +{ + template + return_t dispatch (const T &obj) { obj.collect_variation_indices (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } + + hb_set_t *layout_variation_indices; + const hb_set_t *glyph_set; + const hb_map_t *gpos_lookups; + + hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_, + const hb_set_t *glyph_set_, + const hb_map_t *gpos_lookups_) : + layout_variation_indices (layout_variation_indices_), + glyph_set (glyph_set_), + gpos_lookups (gpos_lookups_) {} +}; + +template +struct subset_offset_array_t +{ + subset_offset_array_t (hb_subset_context_t *subset_context_, + OutputArray& out_, + const void *base_) : subset_context (subset_context_), + out (out_), base (base_) {} + + template + bool operator () (T&& offset) + { + auto *o = out.serialize_append (subset_context->serializer); + if (unlikely (!o)) return false; + auto snap = subset_context->serializer->snapshot (); + bool ret = o->serialize_subset (subset_context, offset, base); + if (!ret) + { + out.pop (); + subset_context->serializer->revert (snap); + } + return ret; + } + + private: + hb_subset_context_t *subset_context; + OutputArray &out; + const void *base; +}; + + +template +struct subset_offset_array_arg_t +{ + subset_offset_array_arg_t (hb_subset_context_t *subset_context_, + OutputArray& out_, + const void *base_, + Arg &&arg_) : subset_context (subset_context_), out (out_), + base (base_), arg (arg_) {} + + template + bool operator () (T&& offset) + { + auto *o = out.serialize_append (subset_context->serializer); + if (unlikely (!o)) return false; + auto snap = subset_context->serializer->snapshot (); + bool ret = o->serialize_subset (subset_context, offset, base, arg); + if (!ret) + { + out.pop (); + subset_context->serializer->revert (snap); + } + return ret; + } + + private: + hb_subset_context_t *subset_context; + OutputArray &out; + const void *base; + Arg &&arg; +}; + +/* + * Helper to subset an array of offsets. Subsets the thing pointed to by each offset + * and discards the offset in the array if the subset operation results in an empty + * thing. + */ +struct +{ + template + subset_offset_array_t + operator () (hb_subset_context_t *subset_context, OutputArray& out, + const void *base) const + { return subset_offset_array_t (subset_context, out, base); } + + /* Variant with one extra argument passed to serialize_subset */ + template + subset_offset_array_arg_t + operator () (hb_subset_context_t *subset_context, OutputArray& out, + const void *base, Arg &&arg) const + { return subset_offset_array_arg_t (subset_context, out, base, arg); } +} +HB_FUNCOBJ (subset_offset_array); + +template +struct subset_record_array_t +{ + subset_record_array_t (hb_subset_layout_context_t *c_, OutputArray* out_, + const void *base_) : subset_layout_context (c_), + out (out_), base (base_) {} + + template + void + operator () (T&& record) + { + auto snap = subset_layout_context->subset_context->serializer->snapshot (); + bool ret = record.subset (subset_layout_context, base); + if (!ret) subset_layout_context->subset_context->serializer->revert (snap); + else out->len++; + } + + private: + hb_subset_layout_context_t *subset_layout_context; + OutputArray *out; + const void *base; +}; + +/* + * Helper to subset a RecordList/record array. Subsets each Record in the array and + * discards the record if the subset operation returns false. + */ +struct +{ + template + subset_record_array_t + operator () (hb_subset_layout_context_t *c, OutputArray* out, + const void *base) const + { return subset_record_array_t (c, out, base); } +} +HB_FUNCOBJ (subset_record_array); /* * @@ -88,6 +308,15 @@ struct Record { int cmp (hb_tag_t a) const { return tag.cmp (a); } + bool subset (hb_subset_layout_context_t *c, const void *base) const + { + TRACE_SUBSET (this); + auto *out = c->subset_context->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag); + return_trace (ret); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -104,7 +333,7 @@ struct Record }; template -struct RecordArrayOf : SortedArrayOf > +struct RecordArrayOf : SortedArrayOf> { const OffsetTo& get_offset (unsigned int i) const { return (*this)[i].offset; } @@ -116,11 +345,12 @@ struct RecordArrayOf : SortedArrayOf > unsigned int *record_count /* IN/OUT */, hb_tag_t *record_tags /* OUT */) const { - if (record_count) { - const Record *arr = this->sub_array (start_offset, record_count); - unsigned int count = *record_count; - for (unsigned int i = 0; i < count; i++) - record_tags[i] = arr[i].tag; + if (record_count) + { + + this->sub_array (start_offset, record_count) + | hb_map (&Record::tag) + | hb_sink (hb_array (record_tags, *record_count)) + ; } return this->len; } @@ -136,14 +366,16 @@ struct RecordListOf : RecordArrayOf const Type& operator [] (unsigned int i) const { return this+this->get_offset (i); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const { TRACE_SUBSET (this); - struct RecordListOf *out = c->serializer->embed (*this); - if (unlikely (!out)) return_trace (false); - unsigned int count = this->len; - for (unsigned int i = 0; i < count; i++) - out->get_offset (i).serialize_subset (c, (*this)[i], out); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + + this->iter () + | hb_apply (subset_record_array (l, out, this)) + ; return_trace (true); } @@ -154,11 +386,31 @@ struct RecordListOf : RecordArrayOf } }; +struct Feature; + +struct RecordListOfFeature : RecordListOf +{ + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + unsigned count = this->len; + + hb_zip (*this, hb_range (count)) + | hb_filter (l->feature_index_map, hb_second) + | hb_map (hb_first) + | hb_apply (subset_record_array (l, out, this)) + ; + return_trace (true); + } +}; struct RangeRecord { int cmp (hb_codepoint_t g) const - { return g < start ? -1 : g <= end ? 0 : +1; } + { return g < first ? -1 : g <= last ? 0 : +1; } bool sanitize (hb_sanitize_context_t *c) const { @@ -167,14 +419,14 @@ struct RangeRecord } bool intersects (const hb_set_t *glyphs) const - { return glyphs->intersects (start, end); } + { return glyphs->intersects (first, last); } template - bool add_coverage (set_t *glyphs) const - { return glyphs->add_range (start, end); } + bool collect_coverage (set_t *glyphs) const + { return glyphs->add_range (first, last); } - GlyphID start; /* First GlyphID in the range */ - GlyphID end; /* Last GlyphID in the range */ + HBGlyphID first; /* First GlyphID in the range */ + HBGlyphID last; /* Last GlyphID in the range */ HBUINT16 value; /* Value */ public: DEFINE_SIZE_STATIC (6); @@ -184,15 +436,38 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord); struct IndexArray : ArrayOf { + bool intersects (const hb_map_t *indexes) const + { return hb_any (*this, indexes); } + + template + void serialize (hb_serialize_context_t *c, + hb_subset_layout_context_t *l, + Iterator it) + { + if (!it) return; + if (unlikely (!c->extend_min ((*this)))) return; + + for (const auto _ : it) + { + if (!l->visitLookupIndex()) break; + + Index i; + i = _; + c->copy (i); + this->len++; + } + } + unsigned int get_indexes (unsigned int start_offset, unsigned int *_count /* IN/OUT */, unsigned int *_indexes /* OUT */) const { - if (_count) { - const HBUINT16 *arr = this->sub_array (start_offset, _count); - unsigned int count = *_count; - for (unsigned int i = 0; i < count; i++) - _indexes[i] = arr[i]; + if (_count) + { + + this->sub_array (start_offset, _count) + | hb_sink (hb_array (_indexes, *_count)) + ; } return this->len; } @@ -204,11 +479,6 @@ struct IndexArray : ArrayOf }; -struct Script; -struct LangSys; -struct Feature; - - struct LangSys { unsigned int get_feature_count () const @@ -227,13 +497,49 @@ struct LangSys { if (reqFeatureIndex == 0xFFFFu) return Index::NOT_FOUND_INDEX; - return reqFeatureIndex;; + return reqFeatureIndex; } - bool subset (hb_subset_context_t *c) const + LangSys* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace (c->embed (*this)); + } + + bool operator == (const LangSys& o) const + { + if (featureIndex.len != o.featureIndex.len || + reqFeatureIndex != o.reqFeatureIndex) + return false; + + for (const auto _ : + hb_zip (featureIndex, o.featureIndex)) + if (_.first != _.second) return false; + + return true; + } + + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l, + const Tag *tag = nullptr) const { TRACE_SUBSET (this); - return_trace (c->serializer->embed (*this)); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex) ? l->feature_index_map->get (reqFeatureIndex) : 0xFFFFu; + + if (!l->visitFeatureIndex (featureIndex.len)) + return_trace (false); + + auto it = + + hb_iter (featureIndex) + | hb_filter (l->feature_index_map) + | hb_map (l->feature_index_map) + ; + + bool ret = bool (it); + out->featureIndex.serialize (c->serializer, l, it); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c, @@ -275,16 +581,46 @@ struct Script bool has_default_lang_sys () const { return defaultLangSys != 0; } const LangSys& get_default_lang_sys () const { return this+defaultLangSys; } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l, + const Tag *tag) const { TRACE_SUBSET (this); - struct Script *out = c->serializer->embed (*this); - if (unlikely (!out)) return_trace (false); - out->defaultLangSys.serialize_subset (c, this+defaultLangSys, out); - unsigned int count = langSys.len; - for (unsigned int i = 0; i < count; i++) - out->langSys.arrayZ[i].offset.serialize_subset (c, this+langSys[i].offset, out); - return_trace (true); + if (!l->visitScript ()) return_trace (false); + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + bool defaultLang = false; + if (has_default_lang_sys ()) + { + c->serializer->push (); + const LangSys& ls = this+defaultLangSys; + bool ret = ls.subset (c, l); + if (!ret && tag && *tag != HB_TAG ('D', 'F', 'L', 'T')) + { + c->serializer->pop_discard (); + out->defaultLangSys = 0; + } + else + { + c->serializer->add_link (out->defaultLangSys, c->serializer->pop_pack ()); + defaultLang = true; + } + } + + + langSys.iter () + | hb_filter ([=] (const Record& record) {return l->visitLangSys (); }) + | hb_filter ([&] (const Record& record) + { + const LangSys& d = this+defaultLangSys; + const LangSys& l = this+record.offset; + return !(l == d); + }) + | hb_apply (subset_record_array (l, &(out->langSys), this)) + ; + + return_trace (bool (out->langSys.len) || defaultLang || l->table_tag == HB_OT_TAG_GSUB); } bool sanitize (hb_sanitize_context_t *c, @@ -381,6 +717,12 @@ struct FeatureParamsSize return_trace (true); } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace ((bool) c->serializer->embed (*this)); + } + HBUINT16 designSize; /* Represents the design size in 720/inch * units (decipoints). The design size entry * must be non-zero. When there is a design @@ -431,6 +773,12 @@ struct FeatureParamsStylisticSet return_trace (c->check_struct (this)); } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace ((bool) c->serializer->embed (*this)); + } + HBUINT16 version; /* (set to 0): This corresponds to a “minor” * version number. Additional data may be * added to the end of this Feature Parameters @@ -457,6 +805,27 @@ struct FeatureParamsStylisticSet /* https://docs.microsoft.com/en-us/typography/opentype/spec/features_ae#cv01-cv99 */ struct FeatureParamsCharacterVariants { + unsigned + get_characters (unsigned start_offset, unsigned *char_count, hb_codepoint_t *chars) const + { + if (char_count) + { + + characters.sub_array (start_offset, char_count) + | hb_sink (hb_array (chars, *char_count)) + ; + } + return characters.len; + } + + unsigned get_size () const + { return min_size + characters.len * HBUINT24::static_size; } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + return_trace ((bool) c->serializer->embed (*this)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -500,6 +869,9 @@ struct FeatureParams { bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const { +#ifdef HB_NO_LAYOUT_FEATURE_PARAMS + return true; +#endif TRACE_SANITIZE (this); if (tag == HB_TAG ('s','i','z','e')) return_trace (u.size.sanitize (c)); @@ -510,26 +882,39 @@ struct FeatureParams return_trace (true); } + bool subset (hb_subset_context_t *c, const Tag* tag) const + { + TRACE_SUBSET (this); + if (!tag) return_trace (false); + if (*tag == HB_TAG ('s','i','z','e')) + return_trace (u.size.subset (c)); + if ((*tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ + return_trace (u.stylisticSet.subset (c)); + if ((*tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ + return_trace (u.characterVariants.subset (c)); + return_trace (false); + } + +#ifndef HB_NO_LAYOUT_FEATURE_PARAMS const FeatureParamsSize& get_size_params (hb_tag_t tag) const { if (tag == HB_TAG ('s','i','z','e')) return u.size; return Null (FeatureParamsSize); } - const FeatureParamsStylisticSet& get_stylistic_set_params (hb_tag_t tag) const { if ((tag & 0xFFFF0000u) == HB_TAG ('s','s','\0','\0')) /* ssXX */ return u.stylisticSet; return Null (FeatureParamsStylisticSet); } - const FeatureParamsCharacterVariants& get_character_variants_params (hb_tag_t tag) const { if ((tag & 0xFFFF0000u) == HB_TAG ('c','v','\0','\0')) /* cvXX */ return u.characterVariants; return Null (FeatureParamsCharacterVariants); } +#endif private: union { @@ -538,7 +923,7 @@ struct FeatureParams FeatureParamsCharacterVariants characterVariants; } u; public: - DEFINE_SIZE_STATIC (17); + DEFINE_SIZE_MIN (0); }; struct Feature @@ -557,13 +942,28 @@ struct Feature const FeatureParams &get_feature_params () const { return this+featureParams; } - bool subset (hb_subset_context_t *c) const + bool intersects_lookup_indexes (const hb_map_t *lookup_indexes) const + { return lookupIndex.intersects (lookup_indexes); } + + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l, + const Tag *tag = nullptr) const { TRACE_SUBSET (this); - struct Feature *out = c->serializer->embed (*this); - if (unlikely (!out)) return_trace (false); - out->featureParams.set (0); /* TODO(subset) FeatureParams. */ - return_trace (true); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + bool subset_featureParams = out->featureParams.serialize_subset (c, featureParams, this, tag); + + auto it = + + hb_iter (lookupIndex) + | hb_filter (l->lookup_index_map) + | hb_map (l->lookup_index_map) + ; + + out->lookupIndex.serialize (c->serializer, l, it); + return_trace (bool (it) || subset_featureParams + || (tag && *tag == HB_TAG ('p', 'r', 'e', 'f'))); } bool sanitize (hb_sanitize_context_t *c, @@ -584,25 +984,25 @@ struct Feature * Adobe tools, only the 'size' feature had FeatureParams defined. */ - OffsetTo orig_offset = featureParams; + if (likely (featureParams.is_null ())) + return_trace (true); + + unsigned int orig_offset = featureParams; if (unlikely (!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))) return_trace (false); - if (likely (orig_offset.is_null ())) - return_trace (true); - if (featureParams == 0 && closure && closure->tag == HB_TAG ('s','i','z','e') && closure->list_base && closure->list_base < this) { - unsigned int new_offset_int = (unsigned int) orig_offset - + unsigned int new_offset_int = orig_offset - (((char *) this) - ((char *) closure->list_base)); OffsetTo new_offset; - /* Check that it did not overflow. */ - new_offset.set (new_offset_int); + /* Check that it would not overflow. */ + new_offset = new_offset_int; if (new_offset == new_offset_int && - c->try_set (&featureParams, new_offset) && + c->try_set (&featureParams, new_offset_int) && !featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE)) return_trace (false); } @@ -648,16 +1048,19 @@ struct Lookup { unsigned int get_subtable_count () const { return subTable.len; } - template - const TSubTable& get_subtable (unsigned int i) const - { return this+CastR > (subTable)[i]; } - template const OffsetArrayOf& get_subtables () const - { return CastR > (subTable); } + { return reinterpret_cast &> (subTable); } template OffsetArrayOf& get_subtables () - { return CastR > (subTable); } + { return reinterpret_cast &> (subTable); } + + template + const TSubTable& get_subtable (unsigned int i) const + { return this+get_subtables ()[i]; } + template + TSubTable& get_subtable (unsigned int i) + { return this+get_subtables ()[i]; } unsigned int get_size () const { @@ -683,14 +1086,14 @@ struct Lookup return flag; } - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { unsigned int lookup_type = get_type (); TRACE_DISPATCH (this, lookup_type); unsigned int count = get_subtable_count (); for (unsigned int i = 0; i < count; i++) { - typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type); + typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type, hb_forward (ds)...); if (c->stop_sublookup_iteration (r)) return_trace (r); } @@ -704,95 +1107,73 @@ struct Lookup { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - lookupType.set (lookup_type); - lookupFlag.set (lookup_props & 0xFFFFu); + lookupType = lookup_type; + lookupFlag = lookup_props & 0xFFFFu; if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false); if (lookupFlag & LookupFlag::UseMarkFilteringSet) { if (unlikely (!c->extend (*this))) return_trace (false); HBUINT16 &markFilteringSet = StructAfter (subTable); - markFilteringSet.set (lookup_props >> 16); + markFilteringSet = lookup_props >> 16; } return_trace (true); } - /* Older compilers need this to NOT be locally defined in a function. */ - template - struct SubTableSubsetWrapper - { - SubTableSubsetWrapper (const TSubTable &subtable_, - unsigned int lookup_type_) : - subtable (subtable_), - lookup_type (lookup_type_) {} - - bool subset (hb_subset_context_t *c) const - { return subtable.dispatch (c, lookup_type); } - - private: - const TSubTable &subtable; - unsigned int lookup_type; - }; - template bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - struct Lookup *out = c->serializer->embed (*this); - if (unlikely (!out)) return_trace (false); - - /* Subset the actual subtables. */ - /* TODO Drop empty ones, either by calling intersects() beforehand, - * or just dropping null offsets after. */ - const OffsetArrayOf& subtables = get_subtables (); - OffsetArrayOf& out_subtables = out->get_subtables (); - unsigned int count = subTable.len; - for (unsigned int i = 0; i < count; i++) - { - SubTableSubsetWrapper wrapper (this+subtables[i], get_type ()); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + out->lookupType = lookupType; + out->lookupFlag = lookupFlag; - out_subtables[i].serialize_subset (c, wrapper, out); - } + const hb_set_t *glyphset = c->plan->glyphset (); + unsigned int lookup_type = get_type (); + + hb_iter (get_subtables ()) + | hb_filter ([this, glyphset, lookup_type] (const OffsetTo &_) { return (this+_).intersects (glyphset, lookup_type); }) + | hb_apply (subset_offset_array (c, out->get_subtables (), this, lookup_type)) + ; return_trace (true); } - /* Older compilers need this to NOT be locally defined in a function. */ - template - struct SubTableSanitizeWrapper : TSubTable - { - bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) const - { return this->dispatch (c, lookup_type); } - }; - template bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!(c->check_struct (this) && subTable.sanitize (c))) return_trace (false); + + unsigned subtables = get_subtable_count (); + if (unlikely (!c->visit_subtables (subtables))) return_trace (false); + if (lookupFlag & LookupFlag::UseMarkFilteringSet) { const HBUINT16 &markFilteringSet = StructAfter (subTable); if (!markFilteringSet.sanitize (c)) return_trace (false); } - if (unlikely (!CastR > > (subTable) - .sanitize (c, this, get_type ()))) + if (unlikely (!get_subtables ().sanitize (c, this, get_type ()))) return_trace (false); - if (unlikely (get_type () == TSubTable::Extension)) + if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ())) { /* The spec says all subtables of an Extension lookup should * have the same type, which shall not be the Extension type * itself (but we already checked for that). - * This is specially important if one has a reverse type! */ + * This is specially important if one has a reverse type! + * + * We only do this if sanitizer edit_count is zero. Otherwise, + * some of the subtables might have become insane after they + * were sanity-checked by the edits of subsequent subtables. + * https://bugs.chromium.org/p/chromium/issues/detail?id=960331 + */ unsigned int type = get_subtable (0).u.extension.get_type (); - unsigned int count = get_subtable_count (); - for (unsigned int i = 1; i < count; i++) + for (unsigned int i = 1; i < subtables; i++) if (get_subtable (i).u.extension.get_type () != type) return_trace (false); } return_trace (true); - return_trace (true); } private: @@ -800,7 +1181,7 @@ struct Lookup HBUINT16 lookupFlag; /* Lookup qualifiers */ ArrayOf subTable; /* Array of SubTables */ -/*HBUINT16 markFilteringSetX[VAR];*//* Index (base 0) into GDEF mark glyph sets +/*HBUINT16 markFilteringSetX[HB_VAR_ARRAY];*//* Index (base 0) into GDEF mark glyph sets * structure. This field is only present if bit * UseMarkFilteringSet of lookup flags is set. */ public: @@ -809,6 +1190,32 @@ struct Lookup typedef OffsetListOf LookupList; +template +struct LookupOffsetList : OffsetListOf +{ + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + unsigned count = this->len; + + hb_zip (*this, hb_range (count)) + | hb_filter (l->lookup_index_map, hb_second) + | hb_map (hb_first) + | hb_apply (subset_offset_array (c, *out, this)) + ; + return_trace (true); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (OffsetListOf::sanitize (c, this)); + } +}; + /* * Coverage Table @@ -826,8 +1233,9 @@ struct CoverageFormat1 return i; } - bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs) + template + bool serialize (hb_serialize_context_t *c, Iterator glyphs) { TRACE_SERIALIZE (this); return_trace (glyphArray.serialize (c, glyphs)); @@ -852,20 +1260,20 @@ struct CoverageFormat1 { return glyphs->has (glyphArray[index]); } template - bool add_coverage (set_t *glyphs) const - { - return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); - } + bool collect_coverage (set_t *glyphs) const + { return glyphs->add_sorted_array (glyphArray.arrayZ, glyphArray.len); } public: /* Older compilers need this to be public. */ - struct Iter { + struct iter_t + { void init (const struct CoverageFormat1 &c_) { c = &c_; i = 0; } void fini () {} - bool more () { return i < c->glyphArray.len; } + bool more () const { return i < c->glyphArray.len; } void next () { i++; } - hb_codepoint_t get_glyph () { return c->glyphArray[i]; } - unsigned int get_coverage () { return i; } + hb_codepoint_t get_glyph () const { return c->glyphArray[i]; } + bool operator != (const iter_t& o) const + { return i != o.i || c != o.c; } private: const struct CoverageFormat1 *c; @@ -875,7 +1283,7 @@ struct CoverageFormat1 protected: HBUINT16 coverageFormat; /* Format identifier--format = 1 */ - SortedArrayOf + SortedArrayOf glyphArray; /* Array of GlyphIDs--in numerical order */ public: DEFINE_SIZE_ARRAY (4, glyphArray); @@ -889,43 +1297,53 @@ struct CoverageFormat2 unsigned int get_coverage (hb_codepoint_t glyph_id) const { const RangeRecord &range = rangeRecord.bsearch (glyph_id); - return likely (range.start <= range.end) ? - (unsigned int) range.value + (glyph_id - range.start) : - NOT_COVERED; + return likely (range.first <= range.last) + ? (unsigned int) range.value + (glyph_id - range.first) + : NOT_COVERED; } - bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs) + template + bool serialize (hb_serialize_context_t *c, Iterator glyphs) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!glyphs.length)) + if (unlikely (!glyphs)) { - rangeRecord.len.set (0); + rangeRecord.len = 0; return_trace (true); } - unsigned int num_ranges = 1; - for (unsigned int i = 1; i < glyphs.length; i++) - if (glyphs[i - 1] + 1 != glyphs[i]) + /* TODO(iter) Write more efficiently? */ + + unsigned num_ranges = 0; + hb_codepoint_t last = (hb_codepoint_t) -2; + for (auto g: glyphs) + { + if (last + 1 != g) num_ranges++; - rangeRecord.len.set (num_ranges); - if (unlikely (!c->extend (rangeRecord))) return_trace (false); + last = g; + } + + if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false); - unsigned int range = 0; - rangeRecord[range].start = glyphs[0]; - rangeRecord[range].value.set (0); - for (unsigned int i = 1; i < glyphs.length; i++) + unsigned count = 0; + unsigned range = (unsigned) -1; + last = (hb_codepoint_t) -2; + for (auto g: glyphs) { - if (glyphs[i - 1] + 1 != glyphs[i]) + if (last + 1 != g) { range++; - rangeRecord[range].start = glyphs[i]; - rangeRecord[range].value.set (i); + rangeRecord[range].first = g; + rangeRecord[range].value = count; } - rangeRecord[range].end = glyphs[i]; + rangeRecord[range].last = g; + last = g; + count++; } + return_trace (true); } @@ -951,7 +1369,7 @@ struct CoverageFormat2 for (i = 0; i < count; i++) { const RangeRecord &range = rangeRecord[i]; if (range.value <= index && - index < (unsigned int) range.value + (range.end - range.start) && + index < (unsigned int) range.value + (range.last - range.first) && range.intersects (glyphs)) return true; else if (index < range.value) @@ -961,57 +1379,61 @@ struct CoverageFormat2 } template - bool add_coverage (set_t *glyphs) const + bool collect_coverage (set_t *glyphs) const { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) - if (unlikely (!rangeRecord[i].add_coverage (glyphs))) + if (unlikely (!rangeRecord[i].collect_coverage (glyphs))) return false; return true; } public: /* Older compilers need this to be public. */ - struct Iter + struct iter_t { void init (const CoverageFormat2 &c_) { c = &c_; coverage = 0; i = 0; - j = c->rangeRecord.len ? c->rangeRecord[0].start : 0; - if (unlikely (c->rangeRecord[0].start > c->rangeRecord[0].end)) + j = c->rangeRecord.len ? c->rangeRecord[0].first : 0; + if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last)) { /* Broken table. Skip. */ i = c->rangeRecord.len; } } void fini () {} - bool more () { return i < c->rangeRecord.len; } + bool more () const { return i < c->rangeRecord.len; } void next () { - if (j >= c->rangeRecord[i].end) + if (j >= c->rangeRecord[i].last) { i++; if (more ()) { - hb_codepoint_t old = j; - j = c->rangeRecord[i].start; - if (unlikely (j <= old)) + unsigned int old = coverage; + j = c->rangeRecord[i].first; + coverage = c->rangeRecord[i].value; + if (unlikely (coverage != old + 1)) { - /* Broken table. Skip. Important to avoid DoS. */ + /* Broken table. Skip. Important to avoid DoS. + * Also, our callers depend on coverage being + * consecutive and monotonically increasing, + * ie. iota(). */ i = c->rangeRecord.len; return; } - coverage = c->rangeRecord[i].value; } return; } coverage++; j++; } - hb_codepoint_t get_glyph () { return j; } - unsigned int get_coverage () { return coverage; } + hb_codepoint_t get_glyph () const { return j; } + bool operator != (const iter_t& o) const + { return i != o.i || j != o.j || c != o.c; } private: const struct CoverageFormat2 *c; @@ -1032,6 +1454,15 @@ struct CoverageFormat2 struct Coverage { + /* Has interface. */ + static constexpr unsigned SENTINEL = NOT_COVERED; + typedef unsigned int value_t; + value_t operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + /* Predicate. */ + bool operator () (hb_codepoint_t k) const { return has (k); } + + unsigned int get (hb_codepoint_t k) const { return get_coverage (k); } unsigned int get_coverage (hb_codepoint_t glyph_id) const { switch (u.format) { @@ -1041,17 +1472,24 @@ struct Coverage } } - bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs) + template + bool serialize (hb_serialize_context_t *c, Iterator glyphs) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - unsigned int num_ranges = 1; - for (unsigned int i = 1; i < glyphs.length; i++) - if (glyphs[i - 1] + 1 != glyphs[i]) + unsigned count = 0; + unsigned num_ranges = 0; + hb_codepoint_t last = (hb_codepoint_t) -2; + for (auto g: glyphs) + { + if (last + 1 != g) num_ranges++; - u.format.set (glyphs.length * 2 < num_ranges * 3 ? 1 : 2); + last = g; + count++; + } + u.format = count <= num_ranges * 3 ? 1 : 2; switch (u.format) { @@ -1061,6 +1499,23 @@ struct Coverage } } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto it = + + iter () + | hb_filter (glyphset) + | hb_map_retains_sorting (glyph_map) + ; + + bool ret = bool (it); + Coverage_serialize (c->serializer, it); + return_trace (ret); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1095,19 +1550,20 @@ struct Coverage /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template - bool add_coverage (set_t *glyphs) const + bool collect_coverage (set_t *glyphs) const { switch (u.format) { - case 1: return u.format1.add_coverage (glyphs); - case 2: return u.format2.add_coverage (glyphs); + case 1: return u.format1.collect_coverage (glyphs); + case 2: return u.format2.collect_coverage (glyphs); default:return false; } } - struct Iter + struct iter_t : hb_iter_with_fallback_t { - Iter (const Coverage &c_) + static constexpr bool is_sorted_iterator = true; + iter_t (const Coverage &c_ = Null (Coverage)) { memset (this, 0, sizeof (*this)); format = c_.u.format; @@ -1118,7 +1574,7 @@ struct Coverage default: return; } } - bool more () + bool __more__ () const { switch (format) { @@ -1127,7 +1583,7 @@ struct Coverage default:return false; } } - void next () + void __next__ () { switch (format) { @@ -1136,7 +1592,10 @@ struct Coverage default: break; } } - hb_codepoint_t get_glyph () + typedef hb_codepoint_t __item_t__; + __item_t__ __item__ () const { return get_glyph (); } + + hb_codepoint_t get_glyph () const { switch (format) { @@ -1145,23 +1604,25 @@ struct Coverage default:return 0; } } - unsigned int get_coverage () + bool operator != (const iter_t& o) const { + if (format != o.format) return true; switch (format) { - case 1: return u.format1.get_coverage (); - case 2: return u.format2.get_coverage (); - default:return -1; + case 1: return u.format1 != o.u.format1; + case 2: return u.format2 != o.u.format2; + default:return false; } } private: unsigned int format; union { - CoverageFormat2::Iter format2; /* Put this one first since it's larger; helps shut up compiler. */ - CoverageFormat1::Iter format1; + CoverageFormat2::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */ + CoverageFormat1::iter_t format1; } u; }; + iter_t iter () const { return iter_t (*this); } protected: union { @@ -1173,15 +1634,56 @@ struct Coverage DEFINE_SIZE_UNION (2, format); }; +template +static inline void +Coverage_serialize (hb_serialize_context_t *c, + Iterator it) +{ c->start_embed ()->serialize (c, it); } + +static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, + const hb_set_t &glyphset, + const hb_map_t &gid_klass_map, + hb_sorted_vector_t &glyphs, + const hb_set_t &klasses, + hb_map_t *klass_map /*INOUT*/) +{ + if (!klass_map) + { + ClassDef_serialize (c, hb_zip (glyphs.iter (), + glyphs.iter () + | hb_map (gid_klass_map))); + return; + } + + /* any glyph not assigned a class value falls into Class zero (0), + * if any glyph assigned to class 0, remapping must start with 0->0*/ + if (glyphset.get_population () > gid_klass_map.get_population ()) + klass_map->set (0, 0); + + unsigned idx = klass_map->has (0) ? 1 : 0; + for (const unsigned k: klasses.iter ()) + { + if (klass_map->has (k)) continue; + klass_map->set (k, idx); + idx++; + } + + auto it = + + glyphs.iter () + | hb_map_retains_sorting ([&] (const HBGlyphID& gid) -> hb_pair_t + { + unsigned new_klass = klass_map->get (gid_klass_map[gid]); + return hb_pair ((hb_codepoint_t)gid, new_klass); + }) + ; + + c->propagate_error (glyphs, klasses); + ClassDef_serialize (c, it); +} /* * Class Definition Table */ -static inline void ClassDef_serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - hb_array_t klasses); - struct ClassDefFormat1 { friend struct ClassDef; @@ -1192,54 +1694,64 @@ struct ClassDefFormat1 return classValue[(unsigned int) (glyph_id - startGlyph)]; } + template bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - hb_array_t klasses) + Iterator it) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!glyphs.length)) + if (unlikely (!it)) { - startGlyph.set (0); - classValue.len.set (0); + startGlyph = 0; + classValue.len = 0; return_trace (true); } - hb_codepoint_t glyph_min = glyphs[0]; - hb_codepoint_t glyph_max = glyphs[glyphs.length - 1]; - - startGlyph.set (glyph_min); - classValue.len.set (glyph_max - glyph_min + 1); - if (unlikely (!c->extend (classValue))) return_trace (false); - - for (unsigned int i = 0; i < glyphs.length; i++) - classValue[glyphs[i] - glyph_min] = klasses[i]; + hb_codepoint_t glyph_min = (*it).first; + hb_codepoint_t glyph_max = + it + | hb_map (hb_first) + | hb_reduce (hb_max, 0u); + unsigned glyph_count = glyph_max - glyph_min + 1; + startGlyph = glyph_min; + if (unlikely (!classValue.serialize (c, glyph_count))) return_trace (false); + for (const hb_pair_t gid_klass_pair : + it) + { + unsigned idx = gid_klass_pair.first - glyph_min; + classValue[idx] = gid_klass_pair.second; + } return_trace (true); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + hb_map_t *klass_map = nullptr /*OUT*/) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset; + const hb_set_t &glyphset = *c->plan->_glyphset_gsub; const hb_map_t &glyph_map = *c->plan->glyph_map; - hb_vector_t glyphs; - hb_vector_t klasses; + + hb_sorted_vector_t glyphs; + hb_set_t orig_klasses; + hb_map_t gid_org_klass_map; hb_codepoint_t start = startGlyph; hb_codepoint_t end = start + classValue.len; - for (hb_codepoint_t g = start; g < end; g++) + for (const hb_codepoint_t gid : + hb_range (start, end) + | hb_filter (glyphset)) { - unsigned int value = classValue[g - start]; - if (!value) continue; - if (!glyphset.has (g)) continue; - glyphs.push()->set (glyph_map[g]); - klasses.push()->set (value); + unsigned klass = classValue[gid - start]; + if (!klass) continue; + + glyphs.push (glyph_map[gid]); + gid_org_klass_map.set (glyph_map[gid], klass); + orig_klasses.add (klass); } - c->serializer->propagate_error (glyphs, klasses); - ClassDef_serialize (c->serializer, glyphs, klasses); - return_trace (glyphs.length); + + ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map, + glyphs, orig_klasses, klass_map); + return_trace ((bool) glyphs); } bool sanitize (hb_sanitize_context_t *c) const @@ -1249,7 +1761,7 @@ struct ClassDefFormat1 } template - bool add_coverage (set_t *glyphs) const + bool collect_coverage (set_t *glyphs) const { unsigned int start = 0; unsigned int count = classValue.len; @@ -1272,7 +1784,7 @@ struct ClassDefFormat1 } template - bool add_class (set_t *glyphs, unsigned int klass) const + bool collect_class (set_t *glyphs, unsigned int klass) const { unsigned int count = classValue.len; for (unsigned int i = 0; i < count; i++) @@ -1311,7 +1823,7 @@ struct ClassDefFormat1 protected: HBUINT16 classFormat; /* Format identifier--format = 1 */ - GlyphID startGlyph; /* First GlyphID of the classValueArray */ + HBGlyphID startGlyph; /* First GlyphID of the classValueArray */ ArrayOf classValue; /* Array of Class Values--one per GlyphID */ public: @@ -1328,69 +1840,90 @@ struct ClassDefFormat2 return rangeRecord.bsearch (glyph_id).value; } + template bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - hb_array_t klasses) + Iterator it) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - if (unlikely (!glyphs.length)) + if (unlikely (!it)) { - rangeRecord.len.set (0); + rangeRecord.len = 0; return_trace (true); } - unsigned int num_ranges = 1; - for (unsigned int i = 1; i < glyphs.length; i++) - if (glyphs[i - 1] + 1 != glyphs[i] || - klasses[i - 1] != klasses[i]) - num_ranges++; - rangeRecord.len.set (num_ranges); - if (unlikely (!c->extend (rangeRecord))) return_trace (false); + unsigned num_ranges = 1; + hb_codepoint_t prev_gid = (*it).first; + unsigned prev_klass = (*it).second; + + RangeRecord range_rec; + range_rec.first = prev_gid; + range_rec.last = prev_gid; + range_rec.value = prev_klass; - unsigned int range = 0; - rangeRecord[range].start = glyphs[0]; - rangeRecord[range].value.set (klasses[0]); - for (unsigned int i = 1; i < glyphs.length; i++) + RangeRecord *record = c->copy (range_rec); + if (unlikely (!record)) return_trace (false); + + for (const auto gid_klass_pair : + (++it)) { - if (glyphs[i - 1] + 1 != glyphs[i] || - klasses[i - 1] != klasses[i]) + hb_codepoint_t cur_gid = gid_klass_pair.first; + unsigned cur_klass = gid_klass_pair.second; + + if (cur_gid != prev_gid + 1 || + cur_klass != prev_klass) { - range++; - rangeRecord[range].start = glyphs[i]; - rangeRecord[range].value = klasses[i]; + if (unlikely (!record)) break; + record->last = prev_gid; + num_ranges++; + + range_rec.first = cur_gid; + range_rec.last = cur_gid; + range_rec.value = cur_klass; + + record = c->copy (range_rec); } - rangeRecord[range].end = glyphs[i]; + + prev_klass = cur_klass; + prev_gid = cur_gid; } + + if (likely (record)) record->last = prev_gid; + rangeRecord.len = num_ranges; return_trace (true); } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + hb_map_t *klass_map = nullptr /*OUT*/) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset; + const hb_set_t &glyphset = *c->plan->_glyphset_gsub; const hb_map_t &glyph_map = *c->plan->glyph_map; - hb_vector_t glyphs; - hb_vector_t klasses; - unsigned int count = rangeRecord.len; - for (unsigned int i = 0; i < count; i++) + hb_sorted_vector_t glyphs; + hb_set_t orig_klasses; + hb_map_t gid_org_klass_map; + + unsigned count = rangeRecord.len; + for (unsigned i = 0; i < count; i++) { - unsigned int value = rangeRecord[i].value; - if (!value) continue; - hb_codepoint_t start = rangeRecord[i].start; - hb_codepoint_t end = rangeRecord[i].end + 1; + unsigned klass = rangeRecord[i].value; + if (!klass) continue; + hb_codepoint_t start = rangeRecord[i].first; + hb_codepoint_t end = rangeRecord[i].last + 1; for (hb_codepoint_t g = start; g < end; g++) { if (!glyphset.has (g)) continue; - glyphs.push ()->set (glyph_map[g]); - klasses.push ()->set (value); + glyphs.push (glyph_map[g]); + gid_org_klass_map.set (glyph_map[g], klass); + orig_klasses.add (klass); } } - c->serializer->propagate_error (glyphs, klasses); - ClassDef_serialize (c->serializer, glyphs, klasses); - return_trace (glyphs.length); + + ClassDef_remap_and_serialize (c->serializer, glyphset, gid_org_klass_map, + glyphs, orig_klasses, klass_map); + return_trace ((bool) glyphs); } bool sanitize (hb_sanitize_context_t *c) const @@ -1400,24 +1933,24 @@ struct ClassDefFormat2 } template - bool add_coverage (set_t *glyphs) const + bool collect_coverage (set_t *glyphs) const { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) if (rangeRecord[i].value) - if (unlikely (!rangeRecord[i].add_coverage (glyphs))) + if (unlikely (!rangeRecord[i].collect_coverage (glyphs))) return false; return true; } template - bool add_class (set_t *glyphs, unsigned int klass) const + bool collect_class (set_t *glyphs, unsigned int klass) const { unsigned int count = rangeRecord.len; for (unsigned int i = 0; i < count; i++) { if (rangeRecord[i].value == klass) - if (unlikely (!rangeRecord[i].add_coverage (glyphs))) + if (unlikely (!rangeRecord[i].collect_coverage (glyphs))) return false; } return true; @@ -1443,9 +1976,9 @@ struct ClassDefFormat2 { if (!hb_set_next (glyphs, &g)) break; - if (g < rangeRecord[i].start) + if (g < rangeRecord[i].first) return true; - g = rangeRecord[i].end; + g = rangeRecord[i].last; } if (g != HB_SET_VALUE_INVALID && hb_set_next (glyphs, &g)) return true; @@ -1468,6 +2001,15 @@ struct ClassDefFormat2 struct ClassDef { + /* Has interface. */ + static constexpr unsigned SENTINEL = 0; + typedef unsigned int value_t; + value_t operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + /* Projection. */ + hb_codepoint_t operator () (hb_codepoint_t k) const { return get (k); } + + unsigned int get (hb_codepoint_t k) const { return get_class (k); } unsigned int get_class (hb_codepoint_t glyph_id) const { switch (u.format) { @@ -1477,44 +2019,58 @@ struct ClassDef } } - bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - hb_array_t klasses) + template + bool serialize (hb_serialize_context_t *c, Iterator it) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); - unsigned int format = 2; - if (glyphs.length) + unsigned format = 2; + if (likely (it)) { - hb_codepoint_t glyph_min = glyphs[0]; - hb_codepoint_t glyph_max = glyphs[glyphs.length - 1]; + hb_codepoint_t glyph_min = (*it).first; + hb_codepoint_t glyph_max = + it + | hb_map (hb_first) + | hb_reduce (hb_max, 0u); + + unsigned num_ranges = 1; + hb_codepoint_t prev_gid = glyph_min; + unsigned prev_klass = (*it).second; - unsigned int num_ranges = 1; - for (unsigned int i = 1; i < glyphs.length; i++) - if (glyphs[i - 1] + 1 != glyphs[i] || - klasses[i - 1] != klasses[i]) + for (const auto gid_klass_pair : it) + { + hb_codepoint_t cur_gid = gid_klass_pair.first; + unsigned cur_klass = gid_klass_pair.second; + if (cur_gid == glyph_min || !cur_klass) continue; + if (cur_gid != prev_gid + 1 || + cur_klass != prev_klass) num_ranges++; - if (1 + (glyph_max - glyph_min + 1) < num_ranges * 3) + prev_gid = cur_gid; + prev_klass = cur_klass; + } + + if (1 + (glyph_max - glyph_min + 1) <= num_ranges * 3) format = 1; } - u.format.set (format); + u.format = format; switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, klasses)); - case 2: return_trace (u.format2.serialize (c, glyphs, klasses)); + case 1: return_trace (u.format1.serialize (c, it)); + case 2: return_trace (u.format2.serialize (c, it)); default:return_trace (false); } } - bool subset (hb_subset_context_t *c) const + bool subset (hb_subset_context_t *c, + hb_map_t *klass_map = nullptr /*OUT*/) const { TRACE_SUBSET (this); switch (u.format) { - case 1: return_trace (u.format1.subset (c)); - case 2: return_trace (u.format2.subset (c)); + case 1: return_trace (u.format1.subset (c, klass_map)); + case 2: return_trace (u.format2.subset (c, klass_map)); default:return_trace (false); } } @@ -1533,11 +2089,11 @@ struct ClassDef /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template - bool add_coverage (set_t *glyphs) const + bool collect_coverage (set_t *glyphs) const { switch (u.format) { - case 1: return u.format1.add_coverage (glyphs); - case 2: return u.format2.add_coverage (glyphs); + case 1: return u.format1.collect_coverage (glyphs); + case 2: return u.format2.collect_coverage (glyphs); default:return false; } } @@ -1545,11 +2101,11 @@ struct ClassDef /* Might return false if array looks unsorted. * Used for faster rejection of corrupt data. */ template - bool add_class (set_t *glyphs, unsigned int klass) const + bool collect_class (set_t *glyphs, unsigned int klass) const { switch (u.format) { - case 1: return u.format1.add_class (glyphs, klass); - case 2: return u.format2.add_class (glyphs, klass); + case 1: return u.format1.collect_class (glyphs, klass); + case 2: return u.format2.collect_class (glyphs, klass); default:return false; } } @@ -1581,10 +2137,10 @@ struct ClassDef DEFINE_SIZE_UNION (2, format); }; +template static inline void ClassDef_serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - hb_array_t klasses) -{ c->start_embed ()->serialize (c, glyphs, klasses); } + Iterator it) +{ c->start_embed ()->serialize (c, it); } /* @@ -1635,7 +2191,7 @@ struct VarRegionAxis struct VarRegionList { float evaluate (unsigned int region_index, - const int *coords, unsigned int coord_len) const + const int *coords, unsigned int coord_len) const { if (unlikely (region_index >= regionCount)) return 0.; @@ -1662,6 +2218,26 @@ struct VarRegionList axesZ.sanitize (c, (unsigned int) axisCount * (unsigned int) regionCount)); } + bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_bimap_t ®ion_map) + { + TRACE_SERIALIZE (this); + VarRegionList *out = c->allocate_min (); + if (unlikely (!out)) return_trace (false); + axisCount = src->axisCount; + regionCount = region_map.get_population (); + if (unlikely (!c->allocate_size (get_size () - min_size))) return_trace (false); + unsigned int region_count = src->get_region_count (); + for (unsigned int r = 0; r < regionCount; r++) + { + unsigned int backward = region_map.backward (r); + if (backward >= region_count) return_trace (false); + memcpy (&axesZ[axisCount * r], &src->axesZ[axisCount * backward], VarRegionAxis::static_size * axisCount); + } + + return_trace (true); + } + + unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; } unsigned int get_region_count () const { return regionCount; } protected: @@ -1685,8 +2261,8 @@ struct VarData { return itemCount * get_row_size (); } float get_delta (unsigned int inner, - const int *coords, unsigned int coord_count, - const VarRegionList ®ions) const + const int *coords, unsigned int coord_count, + const VarRegionList ®ions) const { if (unlikely (inner >= itemCount)) return 0.; @@ -1694,7 +2270,7 @@ struct VarData unsigned int count = regionIndices.len; unsigned int scount = shortCount; - const HBUINT8 *bytes = &StructAfter (regionIndices); + const HBUINT8 *bytes = get_delta_bytes (); const HBUINT8 *row = bytes + inner * (scount + count); float delta = 0.; @@ -1716,16 +2292,16 @@ struct VarData return delta; } - void get_scalars (int *coords, unsigned int coord_count, + void get_scalars (const int *coords, unsigned int coord_count, const VarRegionList ®ions, float *scalars /*OUT */, unsigned int num_scalars) const { - assert (num_scalars == regionIndices.len); - for (unsigned int i = 0; i < num_scalars; i++) - { - scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count); - } + unsigned count = hb_min (num_scalars, regionIndices.len); + for (unsigned int i = 0; i < count; i++) + scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count); + for (unsigned int i = count; i < num_scalars; i++) + scalars[i] = 0.f; } bool sanitize (hb_sanitize_context_t *c) const @@ -1734,11 +2310,117 @@ struct VarData return_trace (c->check_struct (this) && regionIndices.sanitize (c) && shortCount <= regionIndices.len && - c->check_range (&StructAfter (regionIndices), + c->check_range (get_delta_bytes (), itemCount, get_row_size ())); } + bool serialize (hb_serialize_context_t *c, + const VarData *src, + const hb_inc_bimap_t &inner_map, + const hb_bimap_t ®ion_map) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + itemCount = inner_map.get_next_value (); + + /* Optimize short count */ + unsigned short ri_count = src->regionIndices.len; + enum delta_size_t { kZero=0, kByte, kShort }; + hb_vector_t delta_sz; + hb_vector_t ri_map; /* maps old index to new index */ + delta_sz.resize (ri_count); + ri_map.resize (ri_count); + unsigned int new_short_count = 0; + unsigned int r; + for (r = 0; r < ri_count; r++) + { + delta_sz[r] = kZero; + for (unsigned int i = 0; i < inner_map.get_next_value (); i++) + { + unsigned int old = inner_map.backward (i); + int16_t delta = src->get_item_delta (old, r); + if (delta < -128 || 127 < delta) + { + delta_sz[r] = kShort; + new_short_count++; + break; + } + else if (delta != 0) + delta_sz[r] = kByte; + } + } + unsigned int short_index = 0; + unsigned int byte_index = new_short_count; + unsigned int new_ri_count = 0; + for (r = 0; r < ri_count; r++) + if (delta_sz[r]) + { + ri_map[r] = (delta_sz[r] == kShort)? short_index++ : byte_index++; + new_ri_count++; + } + + shortCount = new_short_count; + regionIndices.len = new_ri_count; + + unsigned int size = regionIndices.get_size () - HBUINT16::static_size/*regionIndices.len*/ + (get_row_size () * itemCount); + if (unlikely (!c->allocate_size (size))) + return_trace (false); + + for (r = 0; r < ri_count; r++) + if (delta_sz[r]) regionIndices[ri_map[r]] = region_map[src->regionIndices[r]]; + + for (unsigned int i = 0; i < itemCount; i++) + { + unsigned int old = inner_map.backward (i); + for (unsigned int r = 0; r < ri_count; r++) + if (delta_sz[r]) set_item_delta (i, ri_map[r], src->get_item_delta (old, r)); + } + + return_trace (true); + } + + void collect_region_refs (hb_inc_bimap_t ®ion_map, const hb_inc_bimap_t &inner_map) const + { + for (unsigned int r = 0; r < regionIndices.len; r++) + { + unsigned int region = regionIndices[r]; + if (region_map.has (region)) continue; + for (unsigned int i = 0; i < inner_map.get_next_value (); i++) + if (get_item_delta (inner_map.backward (i), r) != 0) + { + region_map.add (region); + break; + } + } + } + + protected: + const HBUINT8 *get_delta_bytes () const + { return &StructAfter (regionIndices); } + + HBUINT8 *get_delta_bytes () + { return &StructAfter (regionIndices); } + + int16_t get_item_delta (unsigned int item, unsigned int region) const + { + if ( item >= itemCount || unlikely (region >= regionIndices.len)) return 0; + const HBINT8 *p = (const HBINT8 *)get_delta_bytes () + item * get_row_size (); + if (region < shortCount) + return ((const HBINT16 *)p)[region]; + else + return (p + HBINT16::static_size * shortCount)[region - shortCount]; + } + + void set_item_delta (unsigned int item, unsigned int region, int16_t delta) + { + HBINT8 *p = (HBINT8 *)get_delta_bytes () + item * get_row_size (); + if (region < shortCount) + ((HBINT16 *)p)[region] = delta; + else + (p + HBINT16::static_size * shortCount)[region - shortCount] = delta; + } + protected: HBUINT16 itemCount; HBUINT16 shortCount; @@ -1753,8 +2435,12 @@ struct VariationStore float get_delta (unsigned int outer, unsigned int inner, const int *coords, unsigned int coord_count) const { +#ifdef HB_NO_VAR + return 0.f; +#endif + if (unlikely (outer >= dataSets.len)) - return 0.; + return 0.f; return (this+dataSets[outer]).get_delta (inner, coords, coord_count, @@ -1771,6 +2457,10 @@ struct VariationStore bool sanitize (hb_sanitize_context_t *c) const { +#ifdef HB_NO_VAR + return true; +#endif + TRACE_SANITIZE (this); return_trace (c->check_struct (this) && format == 1 && @@ -1778,18 +2468,98 @@ struct VariationStore dataSets.sanitize (c, this)); } + bool serialize (hb_serialize_context_t *c, + const VariationStore *src, + const hb_array_t &inner_maps) + { + TRACE_SERIALIZE (this); + unsigned int set_count = 0; + for (unsigned int i = 0; i < inner_maps.length; i++) + if (inner_maps[i].get_population () > 0) set_count++; + + unsigned int size = min_size + HBUINT32::static_size * set_count; + if (unlikely (!c->allocate_size (size))) return_trace (false); + format = 1; + + hb_inc_bimap_t region_map; + for (unsigned int i = 0; i < inner_maps.length; i++) + (src+src->dataSets[i]).collect_region_refs (region_map, inner_maps[i]); + region_map.sort (); + + if (unlikely (!regions.serialize (c, this) + .serialize (c, &(src+src->regions), region_map))) return_trace (false); + + /* TODO: The following code could be simplified when + * OffsetListOf::subset () can take a custom param to be passed to VarData::serialize () + */ + dataSets.len = set_count; + unsigned int set_index = 0; + for (unsigned int i = 0; i < inner_maps.length; i++) + { + if (inner_maps[i].get_population () == 0) continue; + if (unlikely (!dataSets[set_index++].serialize (c, this) + .serialize (c, &(src+src->dataSets[i]), inner_maps[i], region_map))) + return_trace (false); + } + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + VariationStore *varstore_prime = c->serializer->start_embed (); + if (unlikely (!varstore_prime)) return_trace (false); + + const hb_set_t *variation_indices = c->plan->layout_variation_indices; + if (variation_indices->is_empty ()) return_trace (false); + + hb_vector_t inner_maps; + inner_maps.resize ((unsigned) dataSets.len); + for (unsigned i = 0; i < inner_maps.length; i++) + inner_maps[i].init (); + + for (unsigned idx : c->plan->layout_variation_indices->iter ()) + { + uint16_t major = idx >> 16; + uint16_t minor = idx & 0xFFFF; + + if (major >= inner_maps.length) + { + for (unsigned i = 0; i < inner_maps.length; i++) + inner_maps[i].fini (); + return_trace (false); + } + inner_maps[major].add (minor); + } + varstore_prime->serialize (c->serializer, this, inner_maps.as_array ()); + + for (unsigned i = 0; i < inner_maps.length; i++) + inner_maps[i].fini (); + return_trace (bool (varstore_prime->dataSets)); + } + unsigned int get_region_index_count (unsigned int ivs) const { return (this+dataSets[ivs]).get_region_index_count (); } void get_scalars (unsigned int ivs, - int *coords, unsigned int coord_count, + const int *coords, unsigned int coord_count, float *scalars /*OUT*/, unsigned int num_scalars) const { +#ifdef HB_NO_VAR + for (unsigned i = 0; i < num_scalars; i++) + scalars[i] = 0.f; + return; +#endif + (this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions, &scalars[0], num_scalars); } + unsigned int get_sub_table_count () const { return dataSets.len; } + protected: HBUINT16 format; LOffsetTo regions; @@ -1806,6 +2576,14 @@ struct ConditionFormat1 { friend struct Condition; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (true); + } + private: bool evaluate (const int *coords, unsigned int coord_len) const { @@ -1838,6 +2616,17 @@ struct Condition } } + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1868,6 +2657,18 @@ struct ConditionSet return true; } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + + conditions.iter () + | hb_apply (subset_offset_array (c, out->conditions, this)) + ; + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1884,6 +2685,30 @@ struct FeatureTableSubstitutionRecord { friend struct FeatureTableSubstitution; + void collect_lookups (const void *base, hb_set_t *lookup_indexes /* OUT */) const + { + return (base+feature).add_lookup_indexes_to (lookup_indexes); + } + + void closure_features (const void *base, + const hb_map_t *lookup_indexes, + hb_set_t *feature_indexes /* OUT */) const + { + if ((base+feature).intersects_lookup_indexes (lookup_indexes)) + feature_indexes->add (featureIndex); + } + + bool subset (hb_subset_layout_context_t *c, const void *base) const + { + TRACE_SUBSET (this); + auto *out = c->subset_context->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + out->featureIndex = c->feature_index_map->get (featureIndex); + bool ret = out->feature.serialize_subset (c->subset_context, feature, base, c); + return_trace (ret); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -1911,6 +2736,39 @@ struct FeatureTableSubstitution return nullptr; } + void collect_lookups (const hb_set_t *feature_indexes, + hb_set_t *lookup_indexes /* OUT */) const + { + + hb_iter (substitutions) + | hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex) + | hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r) + { r.collect_lookups (this, lookup_indexes); }) + ; + } + + void closure_features (const hb_map_t *lookup_indexes, + hb_set_t *feature_indexes /* OUT */) const + { + for (const FeatureTableSubstitutionRecord& record : substitutions) + record.closure_features (this, lookup_indexes, feature_indexes); + } + + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + out->version.major = version.major; + out->version.minor = version.minor; + + + substitutions.iter () + | hb_apply (subset_record_array (l, &(out->substitutions), this)) + ; + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1931,6 +2789,32 @@ struct FeatureVariationRecord { friend struct FeatureVariations; + void collect_lookups (const void *base, + const hb_set_t *feature_indexes, + hb_set_t *lookup_indexes /* OUT */) const + { + return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes); + } + + void closure_features (const void *base, + const hb_map_t *lookup_indexes, + hb_set_t *feature_indexes /* OUT */) const + { + (base+substitutions).closure_features (lookup_indexes, feature_indexes); + } + + bool subset (hb_subset_layout_context_t *c, const void *base) const + { + TRACE_SUBSET (this); + auto *out = c->subset_context->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + out->conditions.serialize_subset (c->subset_context, conditions, base); + out->substitutions.serialize_subset (c->subset_context, substitutions, base, c); + + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -1952,7 +2836,7 @@ struct FeatureVariations static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu; bool find_index (const int *coords, unsigned int coord_len, - unsigned int *index) const + unsigned int *index) const { unsigned int count = varRecords.len; for (unsigned int i = 0; i < count; i++) @@ -1975,10 +2859,40 @@ struct FeatureVariations return (this+record.substitutions).find_substitute (feature_index); } - bool subset (hb_subset_context_t *c) const + FeatureVariations* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace (c->embed (*this)); + } + + void collect_lookups (const hb_set_t *feature_indexes, + hb_set_t *lookup_indexes /* OUT */) const + { + for (const FeatureVariationRecord& r : varRecords) + r.collect_lookups (this, feature_indexes, lookup_indexes); + } + + void closure_features (const hb_map_t *lookup_indexes, + hb_set_t *feature_indexes /* OUT */) const + { + for (const FeatureVariationRecord& record : varRecords) + record.closure_features (this, lookup_indexes, feature_indexes); + } + + bool subset (hb_subset_context_t *c, + hb_subset_layout_context_t *l) const { TRACE_SUBSET (this); - return_trace (c->serializer->embed (*this)); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); + + out->version.major = version.major; + out->version.minor = version.minor; + + + varRecords.iter () + | hb_apply (subset_record_array (l, &(out->varRecords), this)) + ; + return_trace (bool (out->varRecords)); } bool sanitize (hb_sanitize_context_t *c) const @@ -2014,6 +2928,8 @@ struct HintingDevice hb_position_t get_y_delta (hb_font_t *font) const { return get_delta (font->y_ppem, font->y_scale); } + public: + unsigned int get_size () const { unsigned int f = deltaFormat; @@ -2027,6 +2943,12 @@ struct HintingDevice return_trace (c->check_struct (this) && c->check_range (this, this->get_size ())); } + HintingDevice* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace (c->embed (this)); + } + private: int get_delta (unsigned int ppem, int scale) const @@ -2088,6 +3010,32 @@ struct VariationDevice hb_position_t get_y_delta (hb_font_t *font, const VariationStore &store) const { return font->em_scalef_y (get_delta (font, store)); } + VariationDevice* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const + { + TRACE_SERIALIZE (this); + auto snap = c->snapshot (); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); + if (!layout_variation_idx_map || layout_variation_idx_map->is_empty ()) return_trace (out); + + unsigned org_idx = (outerIndex << 16) + innerIndex; + if (!layout_variation_idx_map->has (org_idx)) + { + c->revert (snap); + return_trace (nullptr); + } + unsigned new_idx = layout_variation_idx_map->get (org_idx); + out->outerIndex = new_idx >> 16; + out->innerIndex = new_idx & 0xFFFF; + return_trace (out); + } + + void record_variation_index (hb_set_t *layout_variation_indices) const + { + unsigned var_idx = (outerIndex << 16) + innerIndex; + layout_variation_indices->add (var_idx); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -2126,10 +3074,14 @@ struct Device { switch (u.b.format) { +#ifndef HB_NO_HINTING case 1: case 2: case 3: return u.hinting.get_x_delta (font); +#endif +#ifndef HB_NO_VAR case 0x8000: return u.variation.get_x_delta (font, store); +#endif default: return 0; } @@ -2139,9 +3091,13 @@ struct Device switch (u.b.format) { case 1: case 2: case 3: +#ifndef HB_NO_HINTING return u.hinting.get_y_delta (font); +#endif +#ifndef HB_NO_VAR case 0x8000: return u.variation.get_y_delta (font, store); +#endif default: return 0; } @@ -2152,20 +3108,64 @@ struct Device TRACE_SANITIZE (this); if (!u.b.format.sanitize (c)) return_trace (false); switch (u.b.format) { +#ifndef HB_NO_HINTING case 1: case 2: case 3: return_trace (u.hinting.sanitize (c)); +#endif +#ifndef HB_NO_VAR case 0x8000: return_trace (u.variation.sanitize (c)); +#endif default: return_trace (true); } } + Device* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map=nullptr) const + { + TRACE_SERIALIZE (this); + switch (u.b.format) { +#ifndef HB_NO_HINTING + case 1: + case 2: + case 3: + return_trace (reinterpret_cast (u.hinting.copy (c))); +#endif +#ifndef HB_NO_VAR + case 0x8000: + return_trace (reinterpret_cast (u.variation.copy (c, layout_variation_idx_map))); +#endif + default: + return_trace (nullptr); + } + } + + void collect_variation_indices (hb_set_t *layout_variation_indices) const + { + switch (u.b.format) { +#ifndef HB_NO_HINTING + case 1: + case 2: + case 3: + return; +#endif +#ifndef HB_NO_VAR + case 0x8000: + u.variation.record_variation_index (layout_variation_indices); + return; +#endif + default: + return; + } + } + protected: union { DeviceHeader b; HintingDevice hinting; +#ifndef HB_NO_VAR VariationDevice variation; +#endif } u; public: DEFINE_SIZE_UNION (6, b); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gdef-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gdef-table.hh index 533c95a41e6..201a6c980fc 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gdef-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gdef-table.hh @@ -41,8 +41,18 @@ namespace OT { * Attachment List Table */ -typedef ArrayOf AttachPoint; /* Array of contour point indices--in - * increasing numerical order */ +/* Array of contour point indices--in increasing numerical order */ +struct AttachPoint : ArrayOf +{ + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out)) return_trace (false); + + return_trace (out->serialize (c->serializer, + iter ())); + } +}; struct AttachList { @@ -63,15 +73,36 @@ struct AttachList if (point_count) { - hb_array_t array = points.sub_array (start_offset, point_count); - unsigned int count = array.length; - for (unsigned int i = 0; i < count; i++) - point_array[i] = array[i]; + + points.sub_array (start_offset, point_count) + | hb_sink (hb_array (point_array, *point_count)) + ; } return points.len; } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, attachPoint) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -96,6 +127,13 @@ struct AttachList struct CaretValueFormat1 { friend struct CaretValue; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (true); + } private: hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const @@ -119,6 +157,13 @@ struct CaretValueFormat1 struct CaretValueFormat2 { friend struct CaretValue; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (true); + } private: hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const @@ -153,6 +198,19 @@ struct CaretValueFormat3 font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + + return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out), + hb_serialize_context_t::Head, c->plan->layout_variation_idx_map)); + } + + void collect_variation_indices (hb_set_t *layout_variation_indices) const + { (this+deviceTable).collect_variation_indices (layout_variation_indices); } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -173,9 +231,9 @@ struct CaretValueFormat3 struct CaretValue { hb_position_t get_caret_value (hb_font_t *font, - hb_direction_t direction, - hb_codepoint_t glyph_id, - const VariationStore &var_store) const + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store) const { switch (u.format) { case 1: return u.format1.get_caret_value (font, direction); @@ -185,6 +243,32 @@ struct CaretValue } } + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + TRACE_DISPATCH (this, u.format); + if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, hb_forward (ds)...)); + case 3: return_trace (c->dispatch (u.format3, hb_forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + void collect_variation_indices (hb_set_t *layout_variation_indices) const + { + switch (u.format) { + case 1: + case 2: + return; + case 3: + u.format3.collect_variation_indices (layout_variation_indices); + return; + default: return; + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -210,25 +294,45 @@ struct CaretValue struct LigGlyph { - unsigned int get_lig_carets (hb_font_t *font, - hb_direction_t direction, - hb_codepoint_t glyph_id, - const VariationStore &var_store, - unsigned int start_offset, - unsigned int *caret_count /* IN/OUT */, - hb_position_t *caret_array /* OUT */) const + unsigned get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store, + unsigned start_offset, + unsigned *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const { if (caret_count) { - hb_array_t > array = carets.sub_array (start_offset, caret_count); - unsigned int count = array.length; - for (unsigned int i = 0; i < count; i++) - caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store); + + carets.sub_array (start_offset, caret_count) + | hb_map (hb_add (this)) + | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); }) + | hb_sink (hb_array (caret_array, *caret_count)) + ; } return carets.len; } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + + hb_iter (carets) + | hb_apply (subset_offset_array (c, out->carets, this)) + ; + + return_trace (bool (out->carets)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const OffsetTo& offset : carets.iter ()) + (this+offset).collect_variation_indices (c->layout_variation_indices); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -265,6 +369,38 @@ struct LigCaretList return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array); } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, ligGlyph) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+coverage, ligGlyph) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); }) + ; + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -288,6 +424,34 @@ struct MarkGlyphSetsFormat1 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + bool ret = true; + for (const LOffsetTo& offset : coverage.iter ()) + { + auto *o = out->coverage.serialize_append (c->serializer); + if (unlikely (!o)) + { + ret = false; + break; + } + + //not using o->serialize_subset (c, offset, this, out) here because + //OTS doesn't allow null offset. + //See issue: https://github.com/khaledhosny/ots/issues/172 + c->serializer->push (); + c->dispatch (this+offset); + c->serializer->add_link (*o, c->serializer->pop_pack ()); + } + + return_trace (ret && out->coverage.len); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -296,7 +460,7 @@ struct MarkGlyphSetsFormat1 protected: HBUINT16 format; /* Format identifier--format = 1 */ - ArrayOf > + ArrayOf> coverage; /* Array of long offsets to mark set * coverage tables */ public: @@ -313,6 +477,15 @@ struct MarkGlyphSets } } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + switch (u.format) { + case 1: return_trace (u.format1.subset (c)); + default:return_trace (false); + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -356,7 +529,7 @@ struct GDEF unsigned int get_glyph_class (hb_codepoint_t glyph) const { return (this+glyphClassDef).get_class (glyph); } void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const - { (this+glyphClassDef).add_class (glyphs, klass); } + { (this+glyphClassDef).collect_class (glyphs, klass); } bool has_mark_attachment_types () const { return markAttachClassDef != 0; } unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const @@ -386,7 +559,7 @@ struct GDEF bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; } const VariationStore &get_var_store () const - { return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); } + { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); } /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing * glyph class and other bits, and high 8-bit the mark attachment type (if any). @@ -409,15 +582,15 @@ struct GDEF } } - HB_INTERNAL bool is_blacklisted (hb_blob_t *blob, + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, hb_face_t *face) const; struct accelerator_t { void init (hb_face_t *face) { - this->table = hb_sanitize_context_t().reference_table (face); - if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face))) + this->table = hb_sanitize_context_t ().reference_table (face); + if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face))) { hb_blob_destroy (this->table.get_blob ()); this->table = hb_blob_get_empty (); @@ -436,24 +609,66 @@ struct GDEF (version.to_int () >= 0x00010003u ? varStore.static_size : 0); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { (this+ligCaretList).collect_variation_indices (c); } + + void remap_layout_variation_indices (const hb_set_t *layout_variation_indices, + hb_map_t *layout_variation_idx_map /* OUT */) const + { + if (version.to_int () < 0x00010003u || !varStore) return; + if (layout_variation_indices->is_empty ()) return; + + unsigned new_major = 0, new_minor = 0; + unsigned last_major = (layout_variation_indices->get_min ()) >> 16; + for (unsigned idx : layout_variation_indices->iter ()) + { + uint16_t major = idx >> 16; + if (major >= (this+varStore).get_sub_table_count ()) break; + if (major != last_major) + { + new_minor = 0; + ++new_major; + } + + unsigned new_idx = (new_major << 16) + new_minor; + layout_variation_idx_map->set (idx, new_idx); + ++new_minor; + last_major = major; + } + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - struct GDEF *out = c->serializer->embed (*this); + auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); - out->glyphClassDef.serialize_subset (c, this+glyphClassDef, out); - out->attachList.set (0);//TODO(subset) serialize_subset (c, this+attachList, out); - out->ligCaretList.set (0);//TODO(subset) serialize_subset (c, this+ligCaretList, out); - out->markAttachClassDef.serialize_subset (c, this+markAttachClassDef, out); + bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this); + bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this); + bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); + bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this); + bool subset_markglyphsetsdef = true; if (version.to_int () >= 0x00010002u) - out->markGlyphSetsDef.set (0);// TODO(subset) serialize_subset (c, this+markGlyphSetsDef, out); + { + subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); + if (!subset_markglyphsetsdef && + version.to_int () == 0x00010002u) + out->version.minor = 0; + } + bool subset_varstore = true; if (version.to_int () >= 0x00010003u) - out->varStore.set (0);// TODO(subset) serialize_subset (c, this+varStore, out); + { + subset_varstore = out->varStore.serialize_subset (c, varStore, this); + if (!subset_varstore && version.to_int () == 0x00010003u) + out->version.minor = 2; + } - return_trace (true); + return_trace (subset_glyphclassdef || subset_attachlist || + subset_ligcaretlist || subset_markattachclassdef || + (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) || + (out->version.to_int () >= 0x00010003u && subset_varstore)); } bool sanitize (hb_sanitize_context_t *c) const diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh index 2a516500581..eddae150e5f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gpos-table.hh @@ -34,6 +34,11 @@ namespace OT { +struct MarkArray; +static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, + const MarkArray &mark_array, + const hb_set_t &glyphset, + hb_map_t* klass_mapping /* INOUT */); /* buffer **position** var allocations */ #define attach_chain() var.i16[0] /* glyph to which this attaches to, relative to current glyphs; negative for going back, positive for forward. */ @@ -74,14 +79,14 @@ struct ValueFormat : HBUINT16 /* All fields are options. Only those available advance the value pointer. */ #if 0 - HBINT16 xPlacement; /* Horizontal adjustment for + HBINT16 xPlacement; /* Horizontal adjustment for * placement--in design units */ - HBINT16 yPlacement; /* Vertical adjustment for + HBINT16 yPlacement; /* Vertical adjustment for * placement--in design units */ - HBINT16 xAdvance; /* Horizontal adjustment for + HBINT16 xAdvance; /* Horizontal adjustment for * advance--in design units (only used * for horizontal writing) */ - HBINT16 yAdvance; /* Vertical adjustment for advance--in + HBINT16 yAdvance; /* Vertical adjustment for advance--in * design units (only used for vertical * writing) */ OffsetTo xPlaDevice; /* Offset to Device table for @@ -101,10 +106,10 @@ struct ValueFormat : HBUINT16 unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } unsigned int get_size () const { return get_len () * Value::static_size; } - bool apply_value (hb_ot_apply_context_t *c, - const void *base, - const Value *values, - hb_glyph_position_t &glyph_pos) const + bool apply_value (hb_ot_apply_context_t *c, + const void *base, + const Value *values, + hb_glyph_position_t &glyph_pos) const { bool ret = false; unsigned int format = *this; @@ -155,6 +160,60 @@ struct ValueFormat : HBUINT16 return ret; } + void serialize_copy (hb_serialize_context_t *c, const void *base, + const Value *values, const hb_map_t *layout_variation_idx_map) const + { + unsigned int format = *this; + if (!format) return; + + if (format & xPlacement) c->copy (*values++); + if (format & yPlacement) c->copy (*values++); + if (format & xAdvance) c->copy (*values++); + if (format & yAdvance) c->copy (*values++); + + if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); + if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); + if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); + if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *base, + const hb_array_t& values) const + { + unsigned format = *this; + unsigned i = 0; + if (format & xPlacement) i++; + if (format & yPlacement) i++; + if (format & xAdvance) i++; + if (format & yAdvance) i++; + if (format & xPlaDevice) + { + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + + if (format & ValueFormat::yPlaDevice) + { + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + + if (format & ValueFormat::xAdvDevice) + { + + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + + if (format & ValueFormat::yAdvDevice) + { + + (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + i++; + } + } + private: bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const { @@ -173,18 +232,42 @@ struct ValueFormat : HBUINT16 return true; } - static OffsetTo& get_device (Value* value) - { return *CastP > (value); } - static const OffsetTo& get_device (const Value* value, bool *worked=nullptr) + static inline OffsetTo& get_device (Value* value) + { + return *static_cast *> (value); + } + static inline const OffsetTo& get_device (const Value* value, bool *worked=nullptr) { if (worked) *worked |= bool (*value); - return *CastP > (value); + return *static_cast *> (value); + } + + bool copy_device (hb_serialize_context_t *c, const void *base, + const Value *src_value, const hb_map_t *layout_variation_idx_map) const + { + Value *dst_value = c->copy (*src_value); + + if (!dst_value) return false; + if (*dst_value == 0) return true; + + *dst_value = 0; + c->push (); + if ((base + get_device (src_value)).copy (c, layout_variation_idx_map)) + { + c->add_link (*dst_value, c->pop_pack ()); + return true; + } + else + { + c->pop_discard (); + return false; + } } - static const HBINT16& get_short (const Value* value, bool *worked=nullptr) + static inline const HBINT16& get_short (const Value* value, bool *worked=nullptr) { if (worked) *worked |= bool (*value); - return *CastP (value); + return *reinterpret_cast (value); } public: @@ -236,6 +319,13 @@ struct ValueFormat : HBUINT16 } }; +template +static void SinglePos_serialize (hb_serialize_context_t *c, + const void *src, + Iterator it, + ValueFormat valFormat, + const hb_map_t *layout_variation_idx_map); + struct AnchorFormat1 { @@ -253,6 +343,12 @@ struct AnchorFormat1 return_trace (c->check_struct (this)); } + AnchorFormat1* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace (c->embed (this)); + } + protected: HBUINT16 format; /* Format identifier--format = 1 */ FWORD xCoordinate; /* Horizontal value--in design units */ @@ -267,6 +363,13 @@ struct AnchorFormat2 float *x, float *y) const { hb_font_t *font = c->font; + +#ifdef HB_NO_HINTING + *x = font->em_fscale_x (xCoordinate); + *y = font->em_fscale_y (yCoordinate); + return; +#endif + unsigned int x_ppem = font->x_ppem; unsigned int y_ppem = font->y_ppem; hb_position_t cx = 0, cy = 0; @@ -284,6 +387,12 @@ struct AnchorFormat2 return_trace (c->check_struct (this)); } + AnchorFormat2* copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + return_trace (c->embed (this)); + } + protected: HBUINT16 format; /* Format identifier--format = 2 */ FWORD xCoordinate; /* Horizontal value--in design units */ @@ -314,6 +423,26 @@ struct AnchorFormat3 return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this)); } + AnchorFormat3* copy (hb_serialize_context_t *c, + const hb_map_t *layout_variation_idx_map) const + { + TRACE_SERIALIZE (this); + if (!layout_variation_idx_map) return_trace (nullptr); + + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); + + out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); + out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); + return_trace (out); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices); + (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices); + } + protected: HBUINT16 format; /* Format identifier--format = 3 */ FWORD xCoordinate; /* Horizontal value--in design units */ @@ -356,6 +485,29 @@ struct Anchor } } + Anchor* copy (hb_serialize_context_t *c, const hb_map_t *layout_variation_idx_map) const + { + TRACE_SERIALIZE (this); + switch (u.format) { + case 1: return_trace (reinterpret_cast (u.format1.copy (c))); + case 2: return_trace (reinterpret_cast (u.format2.copy (c))); + case 3: return_trace (reinterpret_cast (u.format3.copy (c, layout_variation_idx_map))); + default:return_trace (nullptr); + } + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + switch (u.format) { + case 1: case 2: + return; + case 3: + u.format3.collect_variation_indices (c); + return; + default: return; + } + } + protected: union { HBUINT16 format; /* Format identifier */ @@ -374,11 +526,46 @@ struct AnchorMatrix unsigned int cols, bool *found) const { *found = false; - if (unlikely (row >= rows || col >= cols)) return Null(Anchor); + if (unlikely (row >= rows || col >= cols)) return Null (Anchor); *found = !matrixZ[row * cols + col].is_null (); return this+matrixZ[row * cols + col]; } + template + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + Iterator index_iter) const + { + for (unsigned i : index_iter) + (this+matrixZ[i]).collect_variation_indices (c); + } + + template + bool serialize (hb_serialize_context_t *c, + unsigned num_rows, + AnchorMatrix const *offset_matrix, + const hb_map_t *layout_variation_idx_map, + Iterator index_iter) + { + TRACE_SERIALIZE (this); + if (!index_iter) return_trace (false); + if (unlikely (!c->extend_min ((*this)))) return_trace (false); + + this->rows = num_rows; + for (const unsigned i : index_iter) + { + auto *offset = c->embed (offset_matrix->matrixZ[i]); + if (!offset) return_trace (false); + offset->serialize_copy (c, offset_matrix->matrixZ[i], + offset_matrix, c->to_bias (this), + hb_serialize_context_t::Head, + layout_variation_idx_map); + } + + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const { TRACE_SANITIZE (this); @@ -392,8 +579,7 @@ struct AnchorMatrix } HBUINT16 rows; /* Number of rows */ - protected: - UnsizedArrayOf > + UnsizedArrayOf> matrixZ; /* Matrix of offsets to Anchor tables-- * from beginning of AnchorMatrix table */ public: @@ -405,12 +591,34 @@ struct MarkRecord { friend struct MarkArray; + unsigned get_class () const { return (unsigned) klass; } bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && markAnchor.sanitize (c, base)); } + MarkRecord *copy (hb_serialize_context_t *c, + const void *src_base, + unsigned dst_bias, + const hb_map_t *klass_mapping, + const hb_map_t *layout_variation_idx_map) const + { + TRACE_SERIALIZE (this); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); + + out->klass = klass_mapping->get (klass); + out->markAnchor.serialize_copy (c, markAnchor, src_base, dst_bias, hb_serialize_context_t::Head, layout_variation_idx_map); + return_trace (out); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *src_base) const + { + (src_base+markAnchor).collect_variation_indices (c); + } + protected: HBUINT16 klass; /* Class defined for this mark */ OffsetTo @@ -446,8 +654,8 @@ struct MarkArray : ArrayOf /* Array of MarkRecords--in Coverage ord glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y); hb_glyph_position_t &o = buffer->cur_pos(); - o.x_offset = round (base_x - mark_x); - o.y_offset = round (base_y - mark_y); + o.x_offset = roundf (base_x - mark_x); + o.y_offset = roundf (base_y - mark_y); o.attach_type() = ATTACH_TYPE_MARK; o.attach_chain() = (int) glyph_pos - (int) buffer->idx; buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; @@ -456,6 +664,21 @@ struct MarkArray : ArrayOf /* Array of MarkRecords--in Coverage ord return_trace (true); } + template + bool serialize (hb_serialize_context_t *c, + const hb_map_t *klass_mapping, + const hb_map_t *layout_variation_idx_map, + const void *base, + Iterator it) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (*this))) return_trace (false); + if (unlikely (!c->check_assign (len, it.len ()))) return_trace (false); + c->copy_all (it, base, c->to_bias (this), klass_mapping, layout_variation_idx_map); + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -471,8 +694,22 @@ struct SinglePosFormat1 bool intersects (const hb_set_t *glyphs) const { return (this+coverage).intersects (glyphs); } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if (!valueFormat.has_device ()) return; + + auto it = + + hb_iter (this+coverage) + | hb_filter (c->glyph_set) + ; + + if (!it) return; + valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ())); + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const - { if (unlikely (!(this+coverage).add_coverage (c->input))) return; } + { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } const Coverage &get_coverage () const { return this+coverage; } @@ -489,11 +726,48 @@ struct SinglePosFormat1 return_trace (true); } + template + void serialize (hb_serialize_context_t *c, + const void *src, + Iterator it, + ValueFormat valFormat, + const hb_map_t *layout_variation_idx_map) + { + auto out = c->extend_min (*this); + if (unlikely (!out)) return; + if (unlikely (!c->check_assign (valueFormat, valFormat))) return; + + + it + | hb_map (hb_second) + | hb_apply ([&] (hb_array_t _) + { valFormat.serialize_copy (c, src, &_, layout_variation_idx_map); }) + ; + + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; + + coverage.serialize (c, this).serialize (c, glyphs); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto it = + + hb_iter (this+coverage) + | hb_filter (glyphset) + | hb_map_retains_sorting (glyph_map) + | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ()))) + ; + + bool ret = bool (it); + SinglePos_serialize (c->serializer, this, it, valueFormat, c->plan->layout_variation_idx_map); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -523,8 +797,29 @@ struct SinglePosFormat2 bool intersects (const hb_set_t *glyphs) const { return (this+coverage).intersects (glyphs); } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if (!valueFormat.has_device ()) return; + + auto it = + + hb_zip (this+coverage, hb_range ((unsigned) valueCount)) + | hb_filter (c->glyph_set, hb_first) + ; + + if (!it) return; + + unsigned sub_length = valueFormat.get_len (); + const hb_array_t values_array = values.as_array (valueCount * sub_length); + + for (unsigned i : + it + | hb_map (hb_second)) + valueFormat.collect_variation_indices (c, this, values_array.sub_array (i * sub_length, sub_length)); + + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const - { if (unlikely (!(this+coverage).add_coverage (c->input))) return; } + { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } const Coverage &get_coverage () const { return this+coverage; } @@ -545,11 +840,56 @@ struct SinglePosFormat2 return_trace (true); } + template + void serialize (hb_serialize_context_t *c, + const void *src, + Iterator it, + ValueFormat valFormat, + const hb_map_t *layout_variation_idx_map) + { + auto out = c->extend_min (*this); + if (unlikely (!out)) return; + if (unlikely (!c->check_assign (valueFormat, valFormat))) return; + if (unlikely (!c->check_assign (valueCount, it.len ()))) return; + + + it + | hb_map (hb_second) + | hb_apply ([&] (hb_array_t _) + { valFormat.serialize_copy (c, src, &_, layout_variation_idx_map); }) + ; + + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; + + coverage.serialize (c, this).serialize (c, glyphs); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + unsigned sub_length = valueFormat.get_len (); + auto values_array = values.as_array (valueCount * sub_length); + + auto it = + + hb_zip (this+coverage, hb_range ((unsigned) valueCount)) + | hb_filter (glyphset, hb_first) + | hb_map_retains_sorting ([&] (const hb_pair_t& _) + { + return hb_pair (glyph_map[_.first], + values_array.sub_array (_.second * sub_length, + sub_length)); + }) + ; + + bool ret = bool (it); + SinglePos_serialize (c->serializer, this, it, valueFormat, c->plan->layout_variation_idx_map); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -576,14 +916,52 @@ struct SinglePosFormat2 struct SinglePos { - template - typename context_t::return_t dispatch (context_t *c) const + template + unsigned get_format (Iterator glyph_val_iter_pairs) + { + hb_array_t first_val_iter = hb_second (*glyph_val_iter_pairs); + + for (const auto iter : glyph_val_iter_pairs) + for (const auto _ : hb_zip (iter.second, first_val_iter)) + if (_.first != _.second) + return 2; + + return 1; + } + + + template + void serialize (hb_serialize_context_t *c, + const void *src, + Iterator glyph_val_iter_pairs, + ValueFormat valFormat, + const hb_map_t *layout_variation_idx_map) + { + if (unlikely (!c->extend_min (u.format))) return; + unsigned format = 2; + + if (glyph_val_iter_pairs) format = get_format (glyph_val_iter_pairs); + + u.format = format; + switch (u.format) { + case 1: u.format1.serialize (c, src, glyph_val_iter_pairs, valFormat, layout_variation_idx_map); + return; + case 2: u.format2.serialize (c, src, glyph_val_iter_pairs, valFormat, layout_variation_idx_map); + return; + default:return; + } + } + + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); - case 2: return_trace (c->dispatch (u.format2)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -596,13 +974,64 @@ struct SinglePos } u; }; +template +static void +SinglePos_serialize (hb_serialize_context_t *c, + const void *src, + Iterator it, + ValueFormat valFormat, + const hb_map_t *layout_variation_idx_map) +{ c->start_embed ()->serialize (c, src, it, valFormat, layout_variation_idx_map); } + struct PairValueRecord { friend struct PairSet; + int cmp (hb_codepoint_t k) const + { return secondGlyph.cmp (k); } + + struct serialize_closure_t + { + const void *base; + const ValueFormat *valueFormats; + unsigned len1; /* valueFormats[0].get_len() */ + const hb_map_t *glyph_map; + const hb_map_t *layout_variation_idx_map; + }; + + bool serialize (hb_serialize_context_t *c, + serialize_closure_t *closure) const + { + TRACE_SERIALIZE (this); + auto *out = c->start_embed (*this); + if (unlikely (!c->extend_min (out))) return_trace (false); + + out->secondGlyph = (*closure->glyph_map)[secondGlyph]; + + closure->valueFormats[0].serialize_copy (c, closure->base, &values[0], closure->layout_variation_idx_map); + closure->valueFormats[1].serialize_copy (c, closure->base, &values[closure->len1], closure->layout_variation_idx_map); + + return_trace (true); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat *valueFormats, + const void *base) const + { + unsigned record1_len = valueFormats[0].get_len (); + unsigned record2_len = valueFormats[1].get_len (); + const hb_array_t values_array = values.as_array (record1_len + record2_len); + + if (valueFormats[0].has_device ()) + valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len)); + + if (valueFormats[1].has_device ()) + valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len)); + } + protected: - GlyphID secondGlyph; /* GlyphID of second glyph in the + HBGlyphID secondGlyph; /* GlyphID of second glyph in the * pair--first glyph is listed in the * Coverage table */ ValueRecord values; /* Positioning data for the first glyph @@ -616,7 +1045,7 @@ struct PairSet friend struct PairPosFormat1; bool intersects (const hb_set_t *glyphs, - const ValueFormat *valueFormats) const + const ValueFormat *valueFormats) const { unsigned int len1 = valueFormats[0].get_len (); unsigned int len2 = valueFormats[1].get_len (); @@ -634,7 +1063,7 @@ struct PairSet } void collect_glyphs (hb_collect_glyphs_context_t *c, - const ValueFormat *valueFormats) const + const ValueFormat *valueFormats) const { unsigned int len1 = valueFormats[0].get_len (); unsigned int len2 = valueFormats[1].get_len (); @@ -644,9 +1073,27 @@ struct PairSet c->input->add_array (&record->secondGlyph, len, record_size); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat *valueFormats) const + { + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + unsigned record_size = HBUINT16::static_size * (1 + len1 + len2); + + const PairValueRecord *record = &firstPairValueRecord; + unsigned count = len; + for (unsigned i = 0; i < count; i++) + { + if (c->glyph_set->has (record->secondGlyph)) + { record->collect_variation_indices (c, valueFormats, this); } + + record = &StructAtOffset (record, record_size); + } + } + bool apply (hb_ot_apply_context_t *c, - const ValueFormat *valueFormats, - unsigned int pos) const + const ValueFormat *valueFormats, + unsigned int pos) const { TRACE_APPLY (this); hb_buffer_t *buffer = c->buffer; @@ -654,41 +1101,66 @@ struct PairSet unsigned int len2 = valueFormats[1].get_len (); unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - unsigned int count = len; + const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, + &firstPairValueRecord, + len, + record_size); + if (record) + { + /* Note the intentional use of "|" instead of short-circuit "||". */ + if (valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()) | + valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos])) + buffer->unsafe_to_break (buffer->idx, pos + 1); + if (len2) + pos++; + buffer->idx = pos; + return_trace (true); + } + return_trace (false); + } - /* Hand-coded bsearch. */ - if (unlikely (!count)) - return_trace (false); - hb_codepoint_t x = buffer->info[pos].codepoint; - int min = 0, max = (int) count - 1; - while (min <= max) + bool subset (hb_subset_context_t *c, + const ValueFormat valueFormats[2]) const + { + TRACE_SUBSET (this); + auto snap = c->serializer->snapshot (); + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->len = 0; + + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); + + PairValueRecord::serialize_closure_t closure = { - int mid = ((unsigned int) min + (unsigned int) max) / 2; - const PairValueRecord *record = &StructAtOffset (&firstPairValueRecord, record_size * mid); - hb_codepoint_t mid_x = record->secondGlyph; - if (x < mid_x) - max = mid - 1; - else if (x > mid_x) - min = mid + 1; - else - { - /* Note the intentional use of "|" instead of short-circuit "||". */ - if (valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()) | - valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos])) - buffer->unsafe_to_break (buffer->idx, pos + 1); - if (len2) - pos++; - buffer->idx = pos; - return_trace (true); - } + this, + valueFormats, + len1, + &glyph_map, + c->plan->layout_variation_idx_map + }; + + const PairValueRecord *record = &firstPairValueRecord; + unsigned count = len, num = 0; + for (unsigned i = 0; i < count; i++) + { + if (glyphset.has (record->secondGlyph) + && record->serialize (c->serializer, &closure)) num++; + record = &StructAtOffset (record, record_size); } - return_trace (false); + out->len = num; + if (!num) c->serializer->revert (snap); + return_trace (num); } struct sanitize_closure_t { - const void *base; const ValueFormat *valueFormats; unsigned int len1; /* valueFormats[0].get_len() */ unsigned int stride; /* 1 + len1 + len2 */ @@ -705,8 +1177,8 @@ struct PairSet unsigned int count = len; const PairValueRecord *record = &firstPairValueRecord; - return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) && - closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride)); + return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && + closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)); } protected: @@ -722,21 +1194,37 @@ struct PairPosFormat1 { bool intersects (const hb_set_t *glyphs) const { - unsigned int count = pairSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (glyphs->has (iter.get_glyph ()) && - (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat)) - return true; - } - return false; + return + + hb_zip (this+coverage, pairSet) + | hb_filter (*glyphs, hb_first) + | hb_map (hb_second) + | hb_map ([glyphs, this] (const OffsetTo &_) + { return (this+_).intersects (glyphs, valueFormat); }) + | hb_any + ; + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if ((!valueFormat[0].has_device ()) && (!valueFormat[1].has_device ())) return; + + auto it = + + hb_zip (this+coverage, pairSet) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + if (!it) return; + + it + | hb_map (hb_add (this)) + | hb_apply ([&] (const PairSet& _) { _.collect_variation_indices (c, valueFormat); }) + ; } void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+coverage).add_coverage (c->input))) return; + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; unsigned int count = pairSet.len; for (unsigned int i = 0; i < count; i++) (this+pairSet[i]).collect_glyphs (c, valueFormat); @@ -761,8 +1249,43 @@ struct PairPosFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + out->valueFormat[0] = valueFormat[0]; + out->valueFormat[1] = valueFormat[1]; + + hb_sorted_vector_t new_coverage; + + + hb_zip (this+coverage, pairSet) + | hb_filter (glyphset, hb_first) + | hb_filter ([this, c, out] (const OffsetTo& _) + { + auto *o = out->pairSet.serialize_append (c->serializer); + if (unlikely (!o)) return false; + auto snap = c->serializer->snapshot (); + bool ret = o->serialize_subset (c, _, this, valueFormat); + if (!ret) + { + out->pairSet.pop (); + c->serializer->revert (snap); + } + return ret; + }, + hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + out->coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ()); + + return_trace (bool (new_coverage)); } bool sanitize (hb_sanitize_context_t *c) const @@ -775,7 +1298,6 @@ struct PairPosFormat1 unsigned int len2 = valueFormat[1].get_len (); PairSet::sanitize_closure_t closure = { - this, valueFormat, len1, 1 + len1 + len2 @@ -810,10 +1332,43 @@ struct PairPosFormat2 (this+classDef2).intersects (glyphs); } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + if ((!valueFormat1.has_device ()) && (!valueFormat2.has_device ())) return; + + hb_set_t class1_set, class2_set; + for (const unsigned cp : c->glyph_set->iter ()) + { + unsigned klass1 = (this+classDef1).get (cp); + unsigned klass2 = (this+classDef2).get (cp); + class1_set.add (klass1); + class2_set.add (klass2); + } + + if (class1_set.is_empty () || class2_set.is_empty ()) return; + + unsigned len1 = valueFormat1.get_len (); + unsigned len2 = valueFormat2.get_len (); + const hb_array_t values_array = values.as_array ((unsigned)class1Count * (unsigned) class2Count * (len1 + len2)); + for (const unsigned class1_idx : class1_set.iter ()) + { + for (const unsigned class2_idx : class2_set.iter ()) + { + unsigned start_offset = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + if (valueFormat1.has_device ()) + valueFormat1.collect_variation_indices (c, this, values_array.sub_array (start_offset, len1)); + + if (valueFormat2.has_device ()) + valueFormat2.collect_variation_indices (c, this, values_array.sub_array (start_offset+len1, len2)); + } + } + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - if (unlikely (!(this+classDef2).add_coverage (c->input))) return; + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + if (unlikely (!(this+classDef2).collect_coverage (c->input))) return; } const Coverage &get_coverage () const { return this+coverage; } @@ -853,8 +1408,50 @@ struct PairPosFormat2 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + out->valueFormat1 = valueFormat1; + out->valueFormat2 = valueFormat2; + + hb_map_t klass1_map; + out->classDef1.serialize_subset (c, classDef1, this, &klass1_map); + out->class1Count = klass1_map.get_population (); + + hb_map_t klass2_map; + out->classDef2.serialize_subset (c, classDef2, this, &klass2_map); + out->class2Count = klass2_map.get_population (); + + unsigned len1 = valueFormat1.get_len (); + unsigned len2 = valueFormat2.get_len (); + + + hb_range ((unsigned) class1Count) + | hb_filter (klass1_map) + | hb_apply ([&] (const unsigned class1_idx) + { + + hb_range ((unsigned) class2Count) + | hb_filter (klass2_map) + | hb_apply ([&] (const unsigned class2_idx) + { + unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + valueFormat1.serialize_copy (c->serializer, this, &values[idx], c->plan->layout_variation_idx_map); + valueFormat2.serialize_copy (c->serializer, this, &values[idx + len1], c->plan->layout_variation_idx_map); + }) + ; + }) + ; + + const hb_set_t &glyphset = *c->plan->_glyphset_gsub; + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto it = + + hb_iter (this+coverage) + | hb_filter (glyphset) + | hb_map_retains_sorting (glyph_map) + ; + + out->coverage.serialize (c->serializer, out).serialize (c->serializer, it); + return_trace (out->class1Count && out->class2Count && bool (it)); } bool sanitize (hb_sanitize_context_t *c) const @@ -909,14 +1506,14 @@ struct PairPosFormat2 struct PairPos { - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); - case 2: return_trace (c->dispatch (u.format2)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -940,6 +1537,27 @@ struct EntryExitRecord return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base)); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const void *src_base) const + { + (src_base+entryAnchor).collect_variation_indices (c); + (src_base+exitAnchor).collect_variation_indices (c); + } + + EntryExitRecord* copy (hb_serialize_context_t *c, + const void *src_base, + const void *dst_base, + const hb_map_t *layout_variation_idx_map) const + { + TRACE_SERIALIZE (this); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); + + out->entryAnchor.serialize_copy (c, entryAnchor, src_base, c->to_bias (dst_base), hb_serialize_context_t::Head, layout_variation_idx_map); + out->exitAnchor.serialize_copy (c, exitAnchor, src_base, c->to_bias (dst_base), hb_serialize_context_t::Head, layout_variation_idx_map); + return_trace (out); + } + protected: OffsetTo entryAnchor; /* Offset to EntryAnchor table--from @@ -961,8 +1579,19 @@ struct CursivePosFormat1 bool intersects (const hb_set_t *glyphs) const { return (this+coverage).intersects (glyphs); } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+coverage, entryExitRecord) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const EntryExitRecord& record) { record.collect_variation_indices (c, this); }) + ; + } + void collect_glyphs (hb_collect_glyphs_context_t *c) const - { if (unlikely (!(this+coverage).add_coverage (c->input))) return; } + { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; } const Coverage &get_coverage () const { return this+coverage; } @@ -995,32 +1624,32 @@ struct CursivePosFormat1 /* Main-direction adjustment */ switch (c->direction) { case HB_DIRECTION_LTR: - pos[i].x_advance = round (exit_x) + pos[i].x_offset; + pos[i].x_advance = roundf (exit_x) + pos[i].x_offset; - d = round (entry_x) + pos[j].x_offset; + d = roundf (entry_x) + pos[j].x_offset; pos[j].x_advance -= d; pos[j].x_offset -= d; break; case HB_DIRECTION_RTL: - d = round (exit_x) + pos[i].x_offset; + d = roundf (exit_x) + pos[i].x_offset; pos[i].x_advance -= d; pos[i].x_offset -= d; - pos[j].x_advance = round (entry_x) + pos[j].x_offset; + pos[j].x_advance = roundf (entry_x) + pos[j].x_offset; break; case HB_DIRECTION_TTB: - pos[i].y_advance = round (exit_y) + pos[i].y_offset; + pos[i].y_advance = roundf (exit_y) + pos[i].y_offset; - d = round (entry_y) + pos[j].y_offset; + d = roundf (entry_y) + pos[j].y_offset; pos[j].y_advance -= d; pos[j].y_offset -= d; break; case HB_DIRECTION_BTT: - d = round (exit_y) + pos[i].y_offset; + d = roundf (exit_y) + pos[i].y_offset; pos[i].y_advance -= d; pos[i].y_offset -= d; - pos[j].y_advance = round (entry_y); + pos[j].y_advance = roundf (entry_y); break; case HB_DIRECTION_INVALID: default: @@ -1063,15 +1692,58 @@ struct CursivePosFormat1 else pos[child].x_offset = x_offset; + /* If parent was attached to child, break them free. + * https://github.com/harfbuzz/harfbuzz/issues/2469 + */ + if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain())) + pos[parent].attach_chain() = 0; + buffer->idx++; return_trace (true); } + template + void serialize (hb_serialize_context_t *c, + Iterator it, + const void *src_base, + const hb_map_t *layout_variation_idx_map) + { + if (unlikely (!c->extend_min ((*this)))) return; + this->format = 1; + this->entryExitRecord.len = it.len (); + + for (const EntryExitRecord& entry_record : + it + | hb_map (hb_second)) + c->copy (entry_record, src_base, this, layout_variation_idx_map); + + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; + + coverage.serialize (c, this).serialize (c, glyphs); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out)) return_trace (false); + + auto it = + + hb_zip (this+coverage, entryExitRecord) + | hb_filter (glyphset, hb_first) + | hb_map_retains_sorting ([&] (hb_pair_t p) -> hb_pair_t + { return hb_pair (glyph_map[p.first], p.second);}) + ; + + bool ret = bool (it); + out->serialize (c->serializer, it, this, c->plan->layout_variation_idx_map); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -1094,13 +1766,13 @@ struct CursivePosFormat1 struct CursivePos { - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -1118,16 +1790,73 @@ typedef AnchorMatrix BaseArray; /* base-major-- * mark-minor-- * ordered by class--zero-based. */ +static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, + const MarkArray &mark_array, + const hb_set_t &glyphset, + hb_map_t* klass_mapping /* INOUT */) +{ + hb_set_t orig_classes; + + + hb_zip (mark_coverage, mark_array) + | hb_filter (glyphset, hb_first) + | hb_map (hb_second) + | hb_map (&MarkRecord::get_class) + | hb_sink (orig_classes) + ; + + unsigned idx = 0; + for (auto klass : orig_classes.iter ()) + { + if (klass_mapping->has (klass)) continue; + klass_mapping->set (klass, idx); + idx++; + } +} + struct MarkBasePosFormat1 { bool intersects (const hb_set_t *glyphs) const - { return (this+markCoverage).intersects (glyphs) && - (this+baseCoverage).intersects (glyphs); } + { + return (this+markCoverage).intersects (glyphs) && + (this+baseCoverage).intersects (glyphs); + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); }) + ; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping); + + unsigned basecount = (this+baseArray).rows; + auto base_iter = + + hb_zip (this+baseCoverage, hb_range (basecount)) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + hb_sorted_vector_t base_indexes; + for (const unsigned row : base_iter) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (base_indexes) + ; + } + (this+baseArray).collect_variation_indices (c, base_indexes.iter ()); + } void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; - if (unlikely (!(this+baseCoverage).add_coverage (c->input))) return; + if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return; + if (unlikely (!(this+baseCoverage).collect_coverage (c->input))) return; } const Coverage &get_coverage () const { return this+markCoverage; } @@ -1175,8 +1904,70 @@ struct MarkBasePosFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, glyphset, &klass_mapping); + + if (!klass_mapping.get_population ()) return_trace (false); + out->classCount = klass_mapping.get_population (); + + auto mark_iter = + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (glyphset, hb_first) + ; + + hb_sorted_vector_t new_coverage; + + mark_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->markCoverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + out->markArray.serialize (c->serializer, out) + .serialize (c->serializer, &klass_mapping, c->plan->layout_variation_idx_map, &(this+markArray), + mark_iter + | hb_map (hb_second)); + + unsigned basecount = (this+baseArray).rows; + auto base_iter = + + hb_zip (this+baseCoverage, hb_range (basecount)) + | hb_filter (glyphset, hb_first) + ; + + new_coverage.reset (); + + base_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->baseCoverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + hb_sorted_vector_t base_indexes; + for (const unsigned row : + base_iter + | hb_map (hb_second)) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (base_indexes) + ; + } + out->baseArray.serialize (c->serializer, out) + .serialize (c->serializer, base_iter.len (), &(this+baseArray), c->plan->layout_variation_idx_map, base_indexes.iter ()); + + return_trace (true); } bool sanitize (hb_sanitize_context_t *c) const @@ -1210,13 +2001,13 @@ struct MarkBasePosFormat1 struct MarkBasePos { - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -1242,13 +2033,53 @@ typedef OffsetListOf LigatureArray; struct MarkLigPosFormat1 { bool intersects (const hb_set_t *glyphs) const - { return (this+markCoverage).intersects (glyphs) && - (this+ligatureCoverage).intersects (glyphs); } + { + return (this+markCoverage).intersects (glyphs) && + (this+ligatureCoverage).intersects (glyphs); + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+markCoverage, this+markArray) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+markArray)); }) + ; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+markCoverage, this+markArray, *c->glyph_set, &klass_mapping); + + unsigned ligcount = (this+ligatureArray).len; + auto lig_iter = + + hb_zip (this+ligatureCoverage, hb_range (ligcount)) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + const LigatureArray& lig_array = this+ligatureArray; + for (const unsigned i : lig_iter) + { + hb_sorted_vector_t lig_indexes; + unsigned row_count = lig_array[i].rows; + for (unsigned row : + hb_range (row_count)) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (lig_indexes) + ; + } + + lig_array[i].collect_variation_indices (c, lig_indexes.iter ()); + } + } void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+markCoverage).add_coverage (c->input))) return; - if (unlikely (!(this+ligatureCoverage).add_coverage (c->input))) return; + if (unlikely (!(this+markCoverage).collect_coverage (c->input))) return; + if (unlikely (!(this+ligatureCoverage).collect_coverage (c->input))) return; } const Coverage &get_coverage () const { return this+markCoverage; } @@ -1289,7 +2120,7 @@ struct MarkLigPosFormat1 unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur()); unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); if (lig_id && lig_id == mark_id && mark_comp > 0) - comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1; + comp_index = hb_min (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1; else comp_index = comp_count - 1; @@ -1335,13 +2166,13 @@ struct MarkLigPosFormat1 struct MarkLigPos { - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -1362,13 +2193,47 @@ typedef AnchorMatrix Mark2Array; /* mark2-major-- struct MarkMarkPosFormat1 { bool intersects (const hb_set_t *glyphs) const - { return (this+mark1Coverage).intersects (glyphs) && - (this+mark2Coverage).intersects (glyphs); } + { + return (this+mark1Coverage).intersects (glyphs) && + (this+mark2Coverage).intersects (glyphs); + } + + void closure_lookups (hb_closure_lookups_context_t *c) const {} + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+mark1Coverage, this+mark1Array) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_apply ([&] (const MarkRecord& record) { record.collect_variation_indices (c, &(this+mark1Array)); }) + ; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, *c->glyph_set, &klass_mapping); + + unsigned mark2_count = (this+mark2Array).rows; + auto mark2_iter = + + hb_zip (this+mark2Coverage, hb_range (mark2_count)) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + ; + + hb_sorted_vector_t mark2_indexes; + for (const unsigned row : mark2_iter) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (mark2_indexes) + ; + } + (this+mark2Array).collect_variation_indices (c, mark2_indexes.iter ()); + } void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+mark1Coverage).add_coverage (c->input))) return; - if (unlikely (!(this+mark2Coverage).add_coverage (c->input))) return; + if (unlikely (!(this+mark1Coverage).collect_coverage (c->input))) return; + if (unlikely (!(this+mark2Coverage).collect_coverage (c->input))) return; } const Coverage &get_coverage () const { return this+mark1Coverage; } @@ -1395,12 +2260,15 @@ struct MarkMarkPosFormat1 unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur()); unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]); - if (likely (id1 == id2)) { + if (likely (id1 == id2)) + { if (id1 == 0) /* Marks belonging to the same base. */ goto good; else if (comp1 == comp2) /* Marks belonging to the same ligature component. */ goto good; - } else { + } + else + { /* If ligature ids don't match, it may be the case that one of the marks * itself is a ligature. In which case match. */ if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2)) @@ -1420,8 +2288,70 @@ struct MarkMarkPosFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_map_t klass_mapping; + Markclass_closure_and_remap_indexes (this+mark1Coverage, this+mark1Array, glyphset, &klass_mapping); + + if (!klass_mapping.get_population ()) return_trace (false); + out->classCount = klass_mapping.get_population (); + + auto mark1_iter = + + hb_zip (this+mark1Coverage, this+mark1Array) + | hb_filter (glyphset, hb_first) + ; + + hb_sorted_vector_t new_coverage; + + mark1_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->mark1Coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + out->mark1Array.serialize (c->serializer, out) + .serialize (c->serializer, &klass_mapping, c->plan->layout_variation_idx_map, &(this+mark1Array), + mark1_iter + | hb_map (hb_second)); + + unsigned mark2count = (this+mark2Array).rows; + auto mark2_iter = + + hb_zip (this+mark2Coverage, hb_range (mark2count)) + | hb_filter (glyphset, hb_first) + ; + + new_coverage.reset (); + + mark2_iter + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + if (!out->mark2Coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ())) + return_trace (false); + + hb_sorted_vector_t mark2_indexes; + for (const unsigned row : + mark2_iter + | hb_map (hb_second)) + { + + hb_range ((unsigned) classCount) + | hb_filter (klass_mapping) + | hb_map ([&] (const unsigned col) { return row * (unsigned) classCount + col; }) + | hb_sink (mark2_indexes) + ; + } + out->mark2Array.serialize (c->serializer, out) + .serialize (c->serializer, mark2_iter.len (), &(this+mark2Array), c->plan->layout_variation_idx_map, mark2_indexes.iter ()); + + return_trace (true); } bool sanitize (hb_sanitize_context_t *c) const @@ -1457,13 +2387,13 @@ struct MarkMarkPosFormat1 struct MarkMarkPos { - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -1509,24 +2439,30 @@ struct PosLookupSubTable Extension = 9 }; - template - typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const + template + typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const { TRACE_DISPATCH (this, lookup_type); switch (lookup_type) { - case Single: return_trace (u.single.dispatch (c)); - case Pair: return_trace (u.pair.dispatch (c)); - case Cursive: return_trace (u.cursive.dispatch (c)); - case MarkBase: return_trace (u.markBase.dispatch (c)); - case MarkLig: return_trace (u.markLig.dispatch (c)); - case MarkMark: return_trace (u.markMark.dispatch (c)); - case Context: return_trace (u.context.dispatch (c)); - case ChainContext: return_trace (u.chainContext.dispatch (c)); - case Extension: return_trace (u.extension.dispatch (c)); + case Single: return_trace (u.single.dispatch (c, hb_forward (ds)...)); + case Pair: return_trace (u.pair.dispatch (c, hb_forward (ds)...)); + case Cursive: return_trace (u.cursive.dispatch (c, hb_forward (ds)...)); + case MarkBase: return_trace (u.markBase.dispatch (c, hb_forward (ds)...)); + case MarkLig: return_trace (u.markLig.dispatch (c, hb_forward (ds)...)); + case MarkMark: return_trace (u.markMark.dispatch (c, hb_forward (ds)...)); + case Context: return_trace (u.context.dispatch (c, hb_forward (ds)...)); + case ChainContext: return_trace (u.chainContext.dispatch (c, hb_forward (ds)...)); + case Extension: return_trace (u.extension.dispatch (c, hb_forward (ds)...)); default: return_trace (c->default_return_value ()); } } + bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c, lookup_type); + } + protected: union { SinglePos single; @@ -1571,21 +2507,40 @@ struct PosLookup : Lookup hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { return dispatch (c); } + hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const + { + if (c->is_lookup_visited (this_index)) + return hb_closure_lookups_context_t::default_return_value (); + + c->set_lookup_visited (this_index); + if (!intersects (c->glyphs)) + { + c->set_lookup_inactive (this_index); + return hb_closure_lookups_context_t::default_return_value (); + } + c->set_recurse_func (dispatch_closure_lookups_recurse_func); + + hb_closure_lookups_context_t::return_t ret = dispatch (c); + return ret; + } + template - void add_coverage (set_t *glyphs) const + void collect_coverage (set_t *glyphs) const { - hb_add_coverage_context_t c (glyphs); + hb_collect_coverage_context_t c (glyphs); dispatch (&c); } - static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); + static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); template static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); - template - typename context_t::return_t dispatch (context_t *c) const - { return Lookup::dispatch (c); } + HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index); + + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { return Lookup::dispatch (c, hb_forward (ds)...); } bool subset (hb_subset_context_t *c) const { return Lookup::subset (c); } @@ -1604,21 +2559,39 @@ struct GPOS : GSUBGPOS static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS; const PosLookup& get_lookup (unsigned int i) const - { return CastR (GSUBGPOS::get_lookup (i)); } + { return static_cast (GSUBGPOS::get_lookup (i)); } static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer); bool subset (hb_subset_context_t *c) const - { return GSUBGPOS::subset (c); } + { + hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_features); + return GSUBGPOS::subset (&l); + } bool sanitize (hb_sanitize_context_t *c) const { return GSUBGPOS::sanitize (c); } - HB_INTERNAL bool is_blacklisted (hb_blob_t *blob, + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, hb_face_t *face) const; + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++) + { + if (!c->gpos_lookups->has (i)) continue; + const PosLookup &l = get_lookup (i); + l.dispatch (c); + } + } + + void closure_lookups (hb_face_t *face, + const hb_set_t *glyphs, + hb_set_t *lookup_indexes /* IN/OUT */) const + { GSUBGPOS::closure_lookups (face, glyphs, lookup_indexes); } + typedef GSUBGPOS::accelerator_t accelerator_t; }; @@ -1732,14 +2705,21 @@ struct GPOS_accelerator_t : GPOS::accelerator_t {}; /* Out-of-class implementation for methods recursing */ +#ifndef HB_NO_OT_LAYOUT template -/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) +/*static*/ typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) { const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index); return l.dispatch (c); } -/*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) +/*static*/ inline hb_closure_lookups_context_t::return_t PosLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index) +{ + const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (this_index); + return l.closure_lookups (c, this_index); +} + +/*static*/ bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) { const PosLookup &l = c->face->table.GPOS.get_relaxed ()->table->get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; @@ -1751,6 +2731,7 @@ template c->set_lookup_props (saved_lookup_props); return ret; } +#endif } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh index 288c07b552e..de49c4e2084 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsub-table.hh @@ -34,10 +34,12 @@ namespace OT { +typedef hb_pair_t hb_codepoint_pair_t; + +template +static void SingleSubst_serialize (hb_serialize_context_t *c, + Iterator it); -static inline void SingleSubst_serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - hb_array_t substitutes); struct SingleSubstFormat1 { @@ -46,35 +48,30 @@ struct SingleSubstFormat1 void closure (hb_closure_context_t *c) const { - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - /* TODO Switch to range-based API to work around malicious fonts. - * https://github.com/harfbuzz/harfbuzz/issues/363 */ - hb_codepoint_t glyph_id = iter.get_glyph (); - if (c->glyphs->has (glyph_id)) - c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu); - } + unsigned d = deltaGlyphID; + + hb_iter (this+coverage) + | hb_filter (*c->glyphs) + | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; }) + | hb_sink (c->output) + ; } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - /* TODO Switch to range-based API to work around malicious fonts. - * https://github.com/harfbuzz/harfbuzz/issues/363 */ - hb_codepoint_t glyph_id = iter.get_glyph (); - c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu); - } + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + unsigned d = deltaGlyphID; + + hb_iter (this+coverage) + | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; }) + | hb_sink (c->output) + ; } const Coverage &get_coverage () const { return this+coverage; } bool would_apply (hb_would_apply_context_t *c) const - { - TRACE_WOULD_APPLY (this); - return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); - } + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } bool apply (hb_ot_apply_context_t *c) const { @@ -91,34 +88,41 @@ struct SingleSubstFormat1 return_trace (true); } + template bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - int delta) + Iterator glyphs, + unsigned delta) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false); - deltaGlyphID.set (delta); /* TODO(serialize) overflow? */ + c->check_assign (deltaGlyphID, delta); return_trace (true); } bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset; + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); const hb_map_t &glyph_map = *c->plan->glyph_map; - hb_vector_t from; - hb_vector_t to; + hb_codepoint_t delta = deltaGlyphID; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (!glyphset.has (iter.get_glyph ())) continue; - from.push ()->set (glyph_map[iter.get_glyph ()]); - to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]); - } - c->serializer->propagate_error (from, to); - SingleSubst_serialize (c->serializer, from, to); - return_trace (from.length); + + auto it = + + hb_iter (this+coverage) + | hb_filter (glyphset) + | hb_map_retains_sorting ([&] (hb_codepoint_t g) { + return hb_codepoint_pair_t (g, + (g + delta) & 0xFFFF); }) + | hb_filter (glyphset, hb_second) + | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t + { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) + ; + + bool ret = bool (it); + SingleSubst_serialize (c->serializer, it); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -132,8 +136,8 @@ struct SingleSubstFormat1 OffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - HBINT16 deltaGlyphID; /* Add to original GlyphID to get - * substitute GlyphID */ + HBUINT16 deltaGlyphID; /* Add to original GlyphID to get + * substitute GlyphID, modulo 0x10000 */ public: DEFINE_SIZE_STATIC (6); }; @@ -145,35 +149,28 @@ struct SingleSubstFormat2 void closure (hb_closure_context_t *c) const { - unsigned int count = substitute.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) - c->out->add (substitute[iter.get_coverage ()]); - } + + hb_zip (this+coverage, substitute) + | hb_filter (*c->glyphs, hb_first) + | hb_map (hb_second) + | hb_sink (c->output) + ; } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - unsigned int count = substitute.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - c->output->add (substitute[iter.get_coverage ()]); - } + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + hb_zip (this+coverage, substitute) + | hb_map (hb_second) + | hb_sink (c->output) + ; } const Coverage &get_coverage () const { return this+coverage; } bool would_apply (hb_would_apply_context_t *c) const - { - TRACE_WOULD_APPLY (this); - return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); - } + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } bool apply (hb_ot_apply_context_t *c) const { @@ -188,11 +185,21 @@ struct SingleSubstFormat2 return_trace (true); } + template bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - hb_array_t substitutes) + Iterator it) { TRACE_SERIALIZE (this); + auto substitutes = + + it + | hb_map (hb_second) + ; + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; if (unlikely (!c->extend_min (*this))) return_trace (false); if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false); if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false); @@ -202,19 +209,20 @@ struct SingleSubstFormat2 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset; + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); const hb_map_t &glyph_map = *c->plan->glyph_map; - hb_vector_t from; - hb_vector_t to; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (!glyphset.has (iter.get_glyph ())) continue; - from.push ()->set (glyph_map[iter.get_glyph ()]); - to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]); - } - c->serializer->propagate_error (from, to); - SingleSubst_serialize (c->serializer, from, to); - return_trace (from.length); + + auto it = + + hb_zip (this+coverage, substitute) + | hb_filter (glyphset, hb_first) + | hb_filter (glyphset, hb_second) + | hb_map_retains_sorting ([&] (hb_pair_t p) -> hb_codepoint_pair_t + { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) + ; + + bool ret = bool (it); + SingleSubst_serialize (c->serializer, it); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -228,7 +236,7 @@ struct SingleSubstFormat2 OffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - ArrayOf + ArrayOf substitute; /* Array of substitute * GlyphIDs--ordered by Coverage Index */ public: @@ -237,41 +245,44 @@ struct SingleSubstFormat2 struct SingleSubst { + + template bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - hb_array_t substitutes) + Iterator glyphs) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); - unsigned int format = 2; - int delta = 0; - if (glyphs.length) + unsigned format = 2; + unsigned delta = 0; + if (glyphs) { format = 1; - /* TODO(serialize) check for wrap-around */ - delta = substitutes[0] - glyphs[0]; - for (unsigned int i = 1; i < glyphs.length; i++) - if (delta != (int) (substitutes[i] - glyphs[i])) { - format = 2; - break; - } + auto get_delta = [=] (hb_codepoint_pair_t _) + { return (unsigned) (_.second - _.first) & 0xFFFF; }; + delta = get_delta (*glyphs); + if (!hb_all (++(+glyphs), delta, get_delta)) format = 2; } - u.format.set (format); + u.format = format; switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, delta)); - case 2: return_trace (u.format2.serialize (c, glyphs, substitutes)); + case 1: return_trace (u.format1.serialize (c, + + glyphs + | hb_map_retains_sorting (hb_first), + delta)); + case 2: return_trace (u.format2.serialize (c, glyphs)); default:return_trace (false); } } - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); - case 2: return_trace (c->dispatch (u.format2)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -284,20 +295,19 @@ struct SingleSubst } u; }; -static inline void +template +static void SingleSubst_serialize (hb_serialize_context_t *c, - hb_array_t glyphs, - hb_array_t substitutes) -{ c->start_embed ()->serialize (c, glyphs, substitutes); } + Iterator it) +{ c->start_embed ()->serialize (c, it); } struct Sequence { + bool intersects (const hb_set_t *glyphs) const + { return hb_all (substitute, glyphs); } + void closure (hb_closure_context_t *c) const - { - unsigned int count = substitute.len; - for (unsigned int i = 0; i < count; i++) - c->out->add (substitute[i]); - } + { c->output->add_array (substitute.arrayZ, substitute.len); } void collect_glyphs (hb_collect_glyphs_context_t *c) const { c->output->add_array (substitute.arrayZ, substitute.len); } @@ -334,11 +344,30 @@ struct Sequence return_trace (true); } + template bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs) + Iterator subst) { TRACE_SERIALIZE (this); - return_trace (substitute.serialize (c, glyphs)); + return_trace (substitute.serialize (c, subst)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + if (!intersects (&glyphset)) return_trace (false); + + auto it = + + hb_iter (substitute) + | hb_map (glyph_map) + ; + + auto *out = c->serializer->start_embed (*this); + return_trace (out->serialize (c->serializer, it)); } bool sanitize (hb_sanitize_context_t *c) const @@ -348,7 +377,7 @@ struct Sequence } protected: - ArrayOf + ArrayOf substitute; /* String of GlyphIDs to substitute */ public: DEFINE_SIZE_ARRAY (2, substitute); @@ -361,31 +390,30 @@ struct MultipleSubstFormat1 void closure (hb_closure_context_t *c) const { - unsigned int count = sequence.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) - (this+sequence[iter.get_coverage ()]).closure (c); - } + + hb_zip (this+coverage, sequence) + | hb_filter (*c->glyphs, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Sequence &_) { _.closure (c); }) + ; } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - unsigned int count = sequence.len; - for (unsigned int i = 0; i < count; i++) - (this+sequence[i]).collect_glyphs (c); + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + hb_zip (this+coverage, sequence) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); }) + ; } const Coverage &get_coverage () const { return this+coverage; } bool would_apply (hb_would_apply_context_t *c) const - { - TRACE_WOULD_APPLY (this); - return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); - } + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } bool apply (hb_ot_apply_context_t *c) const { @@ -398,9 +426,9 @@ struct MultipleSubstFormat1 } bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, + hb_sorted_array_t glyphs, hb_array_t substitute_len_list, - hb_array_t substitute_glyphs_list) + hb_array_t substitute_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); @@ -419,8 +447,24 @@ struct MultipleSubstFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, sequence) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->sequence, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); } bool sanitize (hb_sanitize_context_t *c) const @@ -444,27 +488,27 @@ struct MultipleSubstFormat1 struct MultipleSubst { bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, + hb_sorted_array_t glyphs, hb_array_t substitute_len_list, - hb_array_t substitute_glyphs_list) + hb_array_t substitute_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; - u.format.set (format); + u.format = format; switch (u.format) { case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list)); default:return_trace (false); } } - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -478,12 +522,11 @@ struct MultipleSubst struct AlternateSet { + bool intersects (const hb_set_t *glyphs) const + { return hb_any (alternates, glyphs); } + void closure (hb_closure_context_t *c) const - { - unsigned int count = alternates.len; - for (unsigned int i = 0; i < count; i++) - c->out->add (alternates[i]); - } + { c->output->add_array (alternates.arrayZ, alternates.len); } void collect_glyphs (hb_collect_glyphs_context_t *c) const { c->output->add_array (alternates.arrayZ, alternates.len); } @@ -502,7 +545,7 @@ struct AlternateSet unsigned int shift = hb_ctz (lookup_mask); unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); - /* If alt_index is MAX, randomize feature if it is the rand feature. */ + /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */ if (alt_index == HB_OT_MAP_MAX_VALUE && c->random) alt_index = c->random_number () % count + 1; @@ -513,11 +556,44 @@ struct AlternateSet return_trace (true); } + unsigned + get_alternates (unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { + if (alternates.len && alternate_count) + { + + alternates.sub_array (start_offset, alternate_count) + | hb_sink (hb_array (alternate_glyphs, *alternate_count)) + ; + } + return alternates.len; + } + + template bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs) + Iterator alts) { TRACE_SERIALIZE (this); - return_trace (alternates.serialize (c, glyphs)); + return_trace (alternates.serialize (c, alts)); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto it = + + hb_iter (alternates) + | hb_filter (glyphset) + | hb_map (glyph_map) + ; + + auto *out = c->serializer->start_embed (*this); + return_trace (out->serialize (c->serializer, it) && + out->alternates); } bool sanitize (hb_sanitize_context_t *c) const @@ -527,7 +603,7 @@ struct AlternateSet } protected: - ArrayOf + ArrayOf alternates; /* Array of alternate GlyphIDs--in * arbitrary order */ public: @@ -541,35 +617,38 @@ struct AlternateSubstFormat1 void closure (hb_closure_context_t *c) const { - unsigned int count = alternateSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) - (this+alternateSet[iter.get_coverage ()]).closure (c); - } + + hb_zip (this+coverage, alternateSet) + | hb_filter (c->glyphs, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const AlternateSet &_) { _.closure (c); }) + ; } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - unsigned int count = alternateSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c); - } + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + hb_zip (this+coverage, alternateSet) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); }) + ; } const Coverage &get_coverage () const { return this+coverage; } bool would_apply (hb_would_apply_context_t *c) const - { - TRACE_WOULD_APPLY (this); - return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); - } + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } + + unsigned + get_glyph_alternates (hb_codepoint_t gid, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const + { return (this+alternateSet[(this+coverage).get_coverage (gid)]) + .get_alternates (start_offset, alternate_count, alternate_glyphs); } bool apply (hb_ot_apply_context_t *c) const { @@ -582,9 +661,9 @@ struct AlternateSubstFormat1 } bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, + hb_sorted_array_t glyphs, hb_array_t alternate_len_list, - hb_array_t alternate_glyphs_list) + hb_array_t alternate_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); @@ -603,8 +682,24 @@ struct AlternateSubstFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, alternateSet) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); } bool sanitize (hb_sanitize_context_t *c) const @@ -628,27 +723,27 @@ struct AlternateSubstFormat1 struct AlternateSubst { bool serialize (hb_serialize_context_t *c, - hb_array_t glyphs, + hb_sorted_array_t glyphs, hb_array_t alternate_len_list, - hb_array_t alternate_glyphs_list) + hb_array_t alternate_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; - u.format.set (format); + u.format = format; switch (u.format) { case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list)); default:return_trace (false); } } - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -664,40 +759,30 @@ struct AlternateSubst struct Ligature { bool intersects (const hb_set_t *glyphs) const - { - unsigned int count = component.lenP1; - for (unsigned int i = 1; i < count; i++) - if (!glyphs->has (component[i])) - return false; - return true; - } + { return hb_all (component, glyphs); } void closure (hb_closure_context_t *c) const { - unsigned int count = component.lenP1; - for (unsigned int i = 1; i < count; i++) - if (!c->glyphs->has (component[i])) - return; - c->out->add (ligGlyph); + if (!intersects (c->glyphs)) return; + c->output->add (ligGlyph); } void collect_glyphs (hb_collect_glyphs_context_t *c) const { - c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0); + c->input->add_array (component.arrayZ, component.get_length ()); c->output->add (ligGlyph); } bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (this); if (c->len != component.lenP1) - return_trace (false); + return false; for (unsigned int i = 1; i < c->len; i++) if (likely (c->glyphs[i] != component[i])) - return_trace (false); + return false; - return_trace (true); + return true; } bool apply (hb_ot_apply_context_t *c) const @@ -739,9 +824,11 @@ struct Ligature return_trace (true); } + template bool serialize (hb_serialize_context_t *c, - GlyphID ligature, - hb_array_t components /* Starting from second */) + hb_codepoint_t ligature, + Iterator components /* Starting from second */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); @@ -750,6 +837,25 @@ struct Ligature return_trace (true); } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false); + + auto it = + + hb_iter (component) + | hb_map (glyph_map) + ; + + auto *out = c->serializer->start_embed (*this); + return_trace (out->serialize (c->serializer, + glyph_map[ligGlyph], + it)); + } + public: bool sanitize (hb_sanitize_context_t *c) const { @@ -758,8 +864,8 @@ struct Ligature } protected: - GlyphID ligGlyph; /* GlyphID of ligature to substitute */ - HeadlessArrayOf + HBGlyphID ligGlyph; /* GlyphID of ligature to substitute */ + HeadlessArrayOf component; /* Array of component GlyphIDs--start * with the second component--ordered * in writing direction */ @@ -771,38 +877,38 @@ struct LigatureSet { bool intersects (const hb_set_t *glyphs) const { - unsigned int num_ligs = ligature.len; - for (unsigned int i = 0; i < num_ligs; i++) - if ((this+ligature[i]).intersects (glyphs)) - return true; - return false; + return + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); }) + | hb_any + ; } void closure (hb_closure_context_t *c) const { - unsigned int num_ligs = ligature.len; - for (unsigned int i = 0; i < num_ligs; i++) - (this+ligature[i]).closure (c); + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Ligature &_) { _.closure (c); }) + ; } void collect_glyphs (hb_collect_glyphs_context_t *c) const { - unsigned int num_ligs = ligature.len; - for (unsigned int i = 0; i < num_ligs; i++) - (this+ligature[i]).collect_glyphs (c); + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); }) + ; } bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (this); - unsigned int num_ligs = ligature.len; - for (unsigned int i = 0; i < num_ligs; i++) - { - const Ligature &lig = this+ligature[i]; - if (lig.would_apply (c)) - return_trace (true); - } - return_trace (false); + return + + hb_iter (ligature) + | hb_map (hb_add (this)) + | hb_map ([c] (const Ligature &_) { return _.would_apply (c); }) + | hb_any + ; } bool apply (hb_ot_apply_context_t *c) const @@ -819,16 +925,16 @@ struct LigatureSet } bool serialize (hb_serialize_context_t *c, - hb_array_t ligatures, + hb_array_t ligatures, hb_array_t component_count_list, - hb_array_t &component_list /* Starting from second for each ligature */) + hb_array_t &component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false); for (unsigned int i = 0; i < ligatures.length; i++) { - unsigned int component_count = MAX (component_count_list[i] - 1, 0); + unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0); if (unlikely (!ligature[i].serialize (c, this) .serialize (c, ligatures[i], @@ -839,6 +945,19 @@ struct LigatureSet return_trace (true); } + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + + hb_iter (ligature) + | hb_filter (subset_offset_array (c, out->ligature, this)) + | hb_drain + ; + return_trace (bool (out->ligature)); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -857,59 +976,55 @@ struct LigatureSubstFormat1 { bool intersects (const hb_set_t *glyphs) const { - unsigned int count = ligatureSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (glyphs->has (iter.get_glyph ()) && - (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs)) - return true; - } - return false; + return + + hb_zip (this+coverage, ligatureSet) + | hb_filter (*glyphs, hb_first) + | hb_map (hb_second) + | hb_map ([this, glyphs] (const OffsetTo &_) + { return (this+_).intersects (glyphs); }) + | hb_any + ; } void closure (hb_closure_context_t *c) const { - unsigned int count = ligatureSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) - (this+ligatureSet[iter.get_coverage ()]).closure (c); - } + + hb_zip (this+coverage, ligatureSet) + | hb_filter (*c->glyphs, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigatureSet &_) { _.closure (c); }) + ; } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+coverage).add_coverage (c->input))) return; - unsigned int count = ligatureSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c); - } + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; + + + hb_zip (this+coverage, ligatureSet) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); }) + ; } const Coverage &get_coverage () const { return this+coverage; } bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (this); unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); - if (likely (index == NOT_COVERED)) return_trace (false); + if (likely (index == NOT_COVERED)) return false; const LigatureSet &lig_set = this+ligatureSet[index]; - return_trace (lig_set.would_apply (c)); + return lig_set.would_apply (c); } bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); const LigatureSet &lig_set = this+ligatureSet[index]; @@ -917,11 +1032,11 @@ struct LigatureSubstFormat1 } bool serialize (hb_serialize_context_t *c, - hb_array_t first_glyphs, + hb_sorted_array_t first_glyphs, hb_array_t ligature_per_first_glyph_count_list, - hb_array_t ligatures_list, + hb_array_t ligatures_list, hb_array_t component_count_list, - hb_array_t component_list /* Starting from second for each ligature */) + hb_array_t component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (*this))) return_trace (false); @@ -943,8 +1058,24 @@ struct LigatureSubstFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, ligatureSet) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->ligatureSet, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); } bool sanitize (hb_sanitize_context_t *c) const @@ -968,16 +1099,16 @@ struct LigatureSubstFormat1 struct LigatureSubst { bool serialize (hb_serialize_context_t *c, - hb_array_t first_glyphs, + hb_sorted_array_t first_glyphs, hb_array_t ligature_per_first_glyph_count_list, - hb_array_t ligatures_list, + hb_array_t ligatures_list, hb_array_t component_count_list, - hb_array_t component_list /* Starting from second for each ligature */) + hb_array_t component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; - u.format.set (format); + u.format = format; switch (u.format) { case 1: return_trace (u.format1.serialize (c, first_glyphs, @@ -989,13 +1120,13 @@ struct LigatureSubst } } - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -1015,7 +1146,6 @@ struct ChainContextSubst : ChainContext {}; struct ExtensionSubst : Extension { typedef struct SubstLookupSubTable SubTable; - bool is_reverse () const; }; @@ -1027,7 +1157,7 @@ struct ReverseChainSingleSubstFormat1 if (!(this+coverage).intersects (glyphs)) return false; - const OffsetArrayOf &lookahead = StructAfter > (backtrack); + const OffsetArrayOf &lookahead = StructAfter> (backtrack); unsigned int count; @@ -1046,47 +1176,36 @@ struct ReverseChainSingleSubstFormat1 void closure (hb_closure_context_t *c) const { - const OffsetArrayOf &lookahead = StructAfter > (backtrack); + if (!intersects (c->glyphs)) return; - unsigned int count; - - count = backtrack.len; - for (unsigned int i = 0; i < count; i++) - if (!(this+backtrack[i]).intersects (c->glyphs)) - return; - - count = lookahead.len; - for (unsigned int i = 0; i < count; i++) - if (!(this+lookahead[i]).intersects (c->glyphs)) - return; + const OffsetArrayOf &lookahead = StructAfter> (backtrack); + const ArrayOf &substitute = StructAfter> (lookahead); - const ArrayOf &substitute = StructAfter > (lookahead); - count = substitute.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) - c->out->add (substitute[iter.get_coverage ()]); - } + + hb_zip (this+coverage, substitute) + | hb_filter (*c->glyphs, hb_first) + | hb_map (hb_second) + | hb_sink (c->output) + ; } + void closure_lookups (hb_closure_lookups_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - if (unlikely (!(this+coverage).add_coverage (c->input))) return; + if (unlikely (!(this+coverage).collect_coverage (c->input))) return; unsigned int count; count = backtrack.len; for (unsigned int i = 0; i < count; i++) - if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return; + if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return; - const OffsetArrayOf &lookahead = StructAfter > (backtrack); + const OffsetArrayOf &lookahead = StructAfter> (backtrack); count = lookahead.len; for (unsigned int i = 0; i < count; i++) - if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return; + if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return; - const ArrayOf &substitute = StructAfter > (lookahead); + const ArrayOf &substitute = StructAfter> (lookahead); count = substitute.len; c->output->add_array (substitute.arrayZ, substitute.len); } @@ -1094,10 +1213,7 @@ struct ReverseChainSingleSubstFormat1 const Coverage &get_coverage () const { return this+coverage; } bool would_apply (hb_would_apply_context_t *c) const - { - TRACE_WOULD_APPLY (this); - return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); - } + { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; } bool apply (hb_ot_apply_context_t *c) const { @@ -1105,13 +1221,15 @@ struct ReverseChainSingleSubstFormat1 if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL)) return_trace (false); /* No chaining to this type */ - unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); + unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - const OffsetArrayOf &lookahead = StructAfter > (backtrack); - const ArrayOf &substitute = StructAfter > (lookahead); + const OffsetArrayOf &lookahead = StructAfter> (backtrack); + const ArrayOf &substitute = StructAfter> (lookahead); + + if (unlikely (index >= substitute.len)) return_trace (false); - unsigned int start_index = 0, end_index = 0; + unsigned int start_index = 0, end_index = 0; if (match_backtrack (c, backtrack.len, (HBUINT16 *) backtrack.arrayZ, match_coverage, this, @@ -1144,10 +1262,10 @@ struct ReverseChainSingleSubstFormat1 TRACE_SANITIZE (this); if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) return_trace (false); - const OffsetArrayOf &lookahead = StructAfter > (backtrack); + const OffsetArrayOf &lookahead = StructAfter> (backtrack); if (!lookahead.sanitize (c, this)) return_trace (false); - const ArrayOf &substitute = StructAfter > (lookahead); + const ArrayOf &substitute = StructAfter> (lookahead); return_trace (substitute.sanitize (c)); } @@ -1164,7 +1282,7 @@ struct ReverseChainSingleSubstFormat1 lookaheadX; /* Array of coverage tables * in lookahead sequence, in glyph * sequence order */ - ArrayOf + ArrayOf substituteX; /* Array of substitute * GlyphIDs--ordered by Coverage Index */ public: @@ -1173,13 +1291,13 @@ struct ReverseChainSingleSubstFormat1 struct ReverseChainSingleSubst { - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -1213,23 +1331,29 @@ struct SubstLookupSubTable ReverseChainSingle = 8 }; - template - typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const + template + typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const { TRACE_DISPATCH (this, lookup_type); switch (lookup_type) { - case Single: return_trace (u.single.dispatch (c)); - case Multiple: return_trace (u.multiple.dispatch (c)); - case Alternate: return_trace (u.alternate.dispatch (c)); - case Ligature: return_trace (u.ligature.dispatch (c)); - case Context: return_trace (u.context.dispatch (c)); - case ChainContext: return_trace (u.chainContext.dispatch (c)); - case Extension: return_trace (u.extension.dispatch (c)); - case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c)); + case Single: return_trace (u.single.dispatch (c, hb_forward (ds)...)); + case Multiple: return_trace (u.multiple.dispatch (c, hb_forward (ds)...)); + case Alternate: return_trace (u.alternate.dispatch (c, hb_forward (ds)...)); + case Ligature: return_trace (u.ligature.dispatch (c, hb_forward (ds)...)); + case Context: return_trace (u.context.dispatch (c, hb_forward (ds)...)); + case ChainContext: return_trace (u.chainContext.dispatch (c, hb_forward (ds)...)); + case Extension: return_trace (u.extension.dispatch (c, hb_forward (ds)...)); + case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, hb_forward (ds)...)); default: return_trace (c->default_return_value ()); } } + bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const + { + hb_intersects_context_t c (glyphs); + return dispatch (&c, lookup_type); + } + protected: union { SingleSubst single; @@ -1253,14 +1377,14 @@ struct SubstLookup : Lookup const SubTable& get_subtable (unsigned int i) const { return Lookup::get_subtable (i); } - static bool lookup_type_is_reverse (unsigned int lookup_type) + static inline bool lookup_type_is_reverse (unsigned int lookup_type) { return lookup_type == SubTable::ReverseChainSingle; } bool is_reverse () const { unsigned int type = get_type (); if (unlikely (type == SubTable::Extension)) - return CastR (get_subtable(0)).is_reverse (); + return reinterpret_cast (get_subtable (0)).is_reverse (); return lookup_type_is_reverse (type); } @@ -1290,6 +1414,24 @@ struct SubstLookup : Lookup return ret; } + hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const + { + if (c->is_lookup_visited (this_index)) + return hb_closure_lookups_context_t::default_return_value (); + + c->set_lookup_visited (this_index); + if (!intersects (c->glyphs)) + { + c->set_lookup_inactive (this_index); + return hb_closure_lookups_context_t::default_return_value (); + } + + c->set_recurse_func (dispatch_closure_lookups_recurse_func); + + hb_closure_lookups_context_t::return_t ret = dispatch (c); + return ret; + } + hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const { c->set_recurse_func (dispatch_recurse_func); @@ -1297,90 +1439,93 @@ struct SubstLookup : Lookup } template - void add_coverage (set_t *glyphs) const + void collect_coverage (set_t *glyphs) const { - hb_add_coverage_context_t c (glyphs); + hb_collect_coverage_context_t c (glyphs); dispatch (&c); } bool would_apply (hb_would_apply_context_t *c, const hb_ot_layout_lookup_accelerator_t *accel) const { - TRACE_WOULD_APPLY (this); - if (unlikely (!c->len)) return_trace (false); - if (!accel->may_have (c->glyphs[0])) return_trace (false); - return_trace (dispatch (c)); + if (unlikely (!c->len)) return false; + if (!accel->may_have (c->glyphs[0])) return false; + return dispatch (c); } - static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); + static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index); SubTable& serialize_subtable (hb_serialize_context_t *c, - unsigned int i) + unsigned int i) { return get_subtables ()[i].serialize (c, this); } bool serialize_single (hb_serialize_context_t *c, uint32_t lookup_props, - hb_array_t glyphs, - hb_array_t substitutes) + hb_sorted_array_t glyphs, + hb_array_t substitutes) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false); - return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes)); + return_trace (serialize_subtable (c, 0).u.single. + serialize (c, hb_zip (glyphs, substitutes))); } bool serialize_multiple (hb_serialize_context_t *c, uint32_t lookup_props, - hb_array_t glyphs, + hb_sorted_array_t glyphs, hb_array_t substitute_len_list, - hb_array_t substitute_glyphs_list) + hb_array_t substitute_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); - return_trace (serialize_subtable (c, 0).u.multiple.serialize (c, - glyphs, - substitute_len_list, - substitute_glyphs_list)); + return_trace (serialize_subtable (c, 0).u.multiple. + serialize (c, + glyphs, + substitute_len_list, + substitute_glyphs_list)); } bool serialize_alternate (hb_serialize_context_t *c, uint32_t lookup_props, - hb_array_t glyphs, + hb_sorted_array_t glyphs, hb_array_t alternate_len_list, - hb_array_t alternate_glyphs_list) + hb_array_t alternate_glyphs_list) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false); - return_trace (serialize_subtable (c, 0).u.alternate.serialize (c, - glyphs, - alternate_len_list, - alternate_glyphs_list)); + return_trace (serialize_subtable (c, 0).u.alternate. + serialize (c, + glyphs, + alternate_len_list, + alternate_glyphs_list)); } bool serialize_ligature (hb_serialize_context_t *c, uint32_t lookup_props, - hb_array_t first_glyphs, + hb_sorted_array_t first_glyphs, hb_array_t ligature_per_first_glyph_count_list, - hb_array_t ligatures_list, + hb_array_t ligatures_list, hb_array_t component_count_list, - hb_array_t component_list /* Starting from second for each ligature */) + hb_array_t component_list /* Starting from second for each ligature */) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false); - return_trace (serialize_subtable (c, 0).u.ligature.serialize (c, - first_glyphs, - ligature_per_first_glyph_count_list, - ligatures_list, - component_count_list, - component_list)); + return_trace (serialize_subtable (c, 0).u.ligature. + serialize (c, + first_glyphs, + ligature_per_first_glyph_count_list, + ligatures_list, + component_count_list, + component_list)); } template - static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); + static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); - static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index) + static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index) { if (!c->should_visit_lookup (lookup_index)) - return HB_VOID; + return hb_empty_t (); hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index); @@ -1392,9 +1537,11 @@ struct SubstLookup : Lookup return ret; } - template - typename context_t::return_t dispatch (context_t *c) const - { return Lookup::dispatch (c); } + HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index); + + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { return Lookup::dispatch (c, hb_forward (ds)...); } bool subset (hb_subset_context_t *c) const { return Lookup::subset (c); } @@ -1413,17 +1560,25 @@ struct GSUB : GSUBGPOS static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB; const SubstLookup& get_lookup (unsigned int i) const - { return CastR (GSUBGPOS::get_lookup (i)); } + { return static_cast (GSUBGPOS::get_lookup (i)); } bool subset (hb_subset_context_t *c) const - { return GSUBGPOS::subset (c); } + { + hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_features); + return GSUBGPOS::subset (&l); + } bool sanitize (hb_sanitize_context_t *c) const { return GSUBGPOS::sanitize (c); } - HB_INTERNAL bool is_blacklisted (hb_blob_t *blob, + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, hb_face_t *face) const; + void closure_lookups (hb_face_t *face, + const hb_set_t *glyphs, + hb_set_t *lookup_indexes /* IN/OUT */) const + { GSUBGPOS::closure_lookups (face, glyphs, lookup_indexes); } + typedef GSUBGPOS::accelerator_t accelerator_t; }; @@ -1433,22 +1588,25 @@ struct GSUB_accelerator_t : GSUB::accelerator_t {}; /* Out-of-class implementation for methods recursing */ +#ifndef HB_NO_OT_LAYOUT /*static*/ inline bool ExtensionSubst::is_reverse () const { - unsigned int type = get_type (); - if (unlikely (type == SubTable::Extension)) - return CastR (get_subtable()).is_reverse (); - return SubstLookup::lookup_type_is_reverse (type); + return SubstLookup::lookup_type_is_reverse (get_type ()); } - template -/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) +/*static*/ typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) { const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); return l.dispatch (c); } -/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) +/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index) +{ + const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index); + return l.closure_lookups (c, this_index); +} + +/*static*/ bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index) { const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index); unsigned int saved_lookup_props = c->lookup_props; @@ -1460,6 +1618,8 @@ template c->set_lookup_props (saved_lookup_props); return ret; } +#endif + } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh index 11d757a4512..1e7d76dd47b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-gsubgpos.hh @@ -42,30 +42,26 @@ namespace OT { struct hb_intersects_context_t : - hb_dispatch_context_t + hb_dispatch_context_t { - const char *get_name () { return "INTERSECTS"; } template return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); } static return_t default_return_value () { return false; } bool stop_sublookup_iteration (return_t r) const { return r; } const hb_set_t *glyphs; - unsigned int debug_depth; hb_intersects_context_t (const hb_set_t *glyphs_) : - glyphs (glyphs_), - debug_depth (0) {} + glyphs (glyphs_) {} }; struct hb_closure_context_t : - hb_dispatch_context_t + hb_dispatch_context_t { - const char *get_name () { return "CLOSURE"; } typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); template - return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } - static return_t default_return_value () { return HB_VOID; } + return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } void recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) @@ -76,26 +72,35 @@ struct hb_closure_context_t : nesting_level_left++; } + bool lookup_limit_exceeded () + { return lookup_count > HB_MAX_LOOKUP_INDICES; } + bool should_visit_lookup (unsigned int lookup_index) { + if (lookup_count++ > HB_MAX_LOOKUP_INDICES) + return false; + if (is_lookup_done (lookup_index)) return false; + done_lookups->set (lookup_index, glyphs->get_population ()); return true; } bool is_lookup_done (unsigned int lookup_index) { + if (done_lookups->in_error ()) + return true; + /* Have we visited this lookup with the current set of glyphs? */ return done_lookups->get (lookup_index) == glyphs->get_population (); } hb_face_t *face; hb_set_t *glyphs; - hb_set_t out[1]; + hb_set_t output[1]; recurse_func_t recurse_func; unsigned int nesting_level_left; - unsigned int debug_depth; hb_closure_context_t (hb_face_t *face_, hb_set_t *glyphs_, @@ -105,8 +110,9 @@ struct hb_closure_context_t : glyphs (glyphs_), recurse_func (nullptr), nesting_level_left (nesting_level_left_), - debug_depth (0), - done_lookups (done_lookups_) {} + done_lookups (done_lookups_), + lookup_count (0) + {} ~hb_closure_context_t () { flush (); } @@ -114,19 +120,87 @@ struct hb_closure_context_t : void flush () { - hb_set_union (glyphs, out); - hb_set_clear (out); + hb_set_del_range (output, face->get_num_glyphs (), hb_set_get_max (output)); /* Remove invalid glyphs. */ + hb_set_union (glyphs, output); + hb_set_clear (output); } private: hb_map_t *done_lookups; + unsigned int lookup_count; }; +struct hb_closure_lookups_context_t : + hb_dispatch_context_t +{ + typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index); + template + return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } + void recurse (unsigned lookup_index) + { + if (unlikely (nesting_level_left == 0 || !recurse_func)) + return; + + /* Return if new lookup was recursed to before. */ + if (is_lookup_visited (lookup_index)) + return; + + set_lookup_visited (lookup_index); + nesting_level_left--; + recurse_func (this, lookup_index); + nesting_level_left++; + } + + void set_lookup_visited (unsigned lookup_index) + { visited_lookups->add (lookup_index); } + + void set_lookup_inactive (unsigned lookup_index) + { inactive_lookups->add (lookup_index); } + + bool lookup_limit_exceeded () + { return lookup_count > HB_MAX_LOOKUP_INDICES; } + + bool is_lookup_visited (unsigned lookup_index) + { + if (lookup_count++ > HB_MAX_LOOKUP_INDICES) + return true; + + if (visited_lookups->in_error ()) + return true; + + return visited_lookups->has (lookup_index); + } + + hb_face_t *face; + const hb_set_t *glyphs; + recurse_func_t recurse_func; + unsigned int nesting_level_left; + + hb_closure_lookups_context_t (hb_face_t *face_, + const hb_set_t *glyphs_, + hb_set_t *visited_lookups_, + hb_set_t *inactive_lookups_, + unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) : + face (face_), + glyphs (glyphs_), + recurse_func (nullptr), + nesting_level_left (nesting_level_left_), + visited_lookups (visited_lookups_), + inactive_lookups (inactive_lookups_), + lookup_count (0) {} + + void set_recurse_func (recurse_func_t func) { recurse_func = func; } + + private: + hb_set_t *visited_lookups; + hb_set_t *inactive_lookups; + unsigned int lookup_count; +}; struct hb_would_apply_context_t : - hb_dispatch_context_t + hb_dispatch_context_t { - const char *get_name () { return "WOULD_APPLY"; } template return_t dispatch (const T &obj) { return obj.would_apply (this); } static return_t default_return_value () { return false; } @@ -136,7 +210,6 @@ struct hb_would_apply_context_t : const hb_codepoint_t *glyphs; unsigned int len; bool zero_context; - unsigned int debug_depth; hb_would_apply_context_t (hb_face_t *face_, const hb_codepoint_t *glyphs_, @@ -145,19 +218,16 @@ struct hb_would_apply_context_t : face (face_), glyphs (glyphs_), len (len_), - zero_context (zero_context_), - debug_depth (0) {} + zero_context (zero_context_) {} }; - struct hb_collect_glyphs_context_t : - hb_dispatch_context_t + hb_dispatch_context_t { - const char *get_name () { return "COLLECT_GLYPHS"; } typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); template - return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } - static return_t default_return_value () { return HB_VOID; } + return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } void recurse (unsigned int lookup_index) { if (unlikely (nesting_level_left == 0 || !recurse_func)) @@ -204,7 +274,6 @@ struct hb_collect_glyphs_context_t : recurse_func_t recurse_func; hb_set_t *recursed_lookups; unsigned int nesting_level_left; - unsigned int debug_depth; hb_collect_glyphs_context_t (hb_face_t *face_, hb_set_t *glyphs_before, /* OUT. May be NULL */ @@ -219,8 +288,7 @@ struct hb_collect_glyphs_context_t : output (glyphs_output ? glyphs_output : hb_set_get_empty ()), recurse_func (nullptr), recursed_lookups (hb_set_create ()), - nesting_level_left (nesting_level_left_), - debug_depth (0) {} + nesting_level_left (nesting_level_left_) {} ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); } void set_recurse_func (recurse_func_t func) { recurse_func = func; } @@ -229,26 +297,23 @@ struct hb_collect_glyphs_context_t : template -struct hb_add_coverage_context_t : - hb_dispatch_context_t, const Coverage &, HB_DEBUG_GET_COVERAGE> +struct hb_collect_coverage_context_t : + hb_dispatch_context_t, const Coverage &> { - const char *get_name () { return "GET_COVERAGE"; } - typedef const Coverage &return_t; + typedef const Coverage &return_t; // Stoopid that we have to dupe this here. template return_t dispatch (const T &obj) { return obj.get_coverage (); } - static return_t default_return_value () { return Null(Coverage); } + static return_t default_return_value () { return Null (Coverage); } bool stop_sublookup_iteration (return_t r) const { - r.add_coverage (set); + r.collect_coverage (set); return false; } - hb_add_coverage_context_t (set_t *set_) : - set (set_), - debug_depth (0) {} + hb_collect_coverage_context_t (set_t *set_) : + set (set_) {} set_t *set; - unsigned int debug_depth; }; @@ -276,7 +341,7 @@ struct hb_ot_apply_context_t : void set_mask (hb_mask_t mask_) { mask = mask_; } void set_syllable (uint8_t syllable_) { syllable = syllable_; } void set_match_func (match_func_t match_func_, - const void *match_data_) + const void *match_data_) { match_func = match_func_; match_data = match_data_; } enum may_match_t { @@ -286,7 +351,7 @@ struct hb_ot_apply_context_t : }; may_match_t may_match (const hb_glyph_info_t &info, - const HBUINT16 *glyph_data) const + const HBUINT16 *glyph_data) const { if (!(info.mask & mask) || (syllable && syllable != info.syllable ())) @@ -355,7 +420,7 @@ struct hb_ot_apply_context_t : } void reset (unsigned int start_index_, - unsigned int num_items_) + unsigned int num_items_) { idx = start_index_; num_items = num_items_; @@ -363,7 +428,11 @@ struct hb_ot_apply_context_t : matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); } - void reject () { num_items++; match_glyph_data--; } + void reject () + { + num_items++; + if (match_glyph_data) match_glyph_data--; + } matcher_t::may_skip_t may_skip (const hb_glyph_info_t &info) const @@ -387,7 +456,7 @@ struct hb_ot_apply_context_t : skip == matcher_t::SKIP_NO)) { num_items--; - match_glyph_data++; + if (match_glyph_data) match_glyph_data++; return true; } @@ -414,7 +483,7 @@ struct hb_ot_apply_context_t : skip == matcher_t::SKIP_NO)) { num_items--; - match_glyph_data++; + if (match_glyph_data) match_glyph_data++; return true; } @@ -467,7 +536,6 @@ struct hb_ot_apply_context_t : unsigned int lookup_index; unsigned int lookup_props; unsigned int nesting_level_left; - unsigned int debug_depth; bool has_glyph_classes; bool auto_zwnj; @@ -478,12 +546,18 @@ struct hb_ot_apply_context_t : hb_ot_apply_context_t (unsigned int table_index_, - hb_font_t *font_, - hb_buffer_t *buffer_) : + hb_font_t *font_, + hb_buffer_t *buffer_) : iter_input (), iter_context (), font (font_), face (font->face), buffer (buffer_), recurse_func (nullptr), - gdef (*face->table.GDEF->table), + gdef ( +#ifndef HB_NO_OT_LAYOUT + *face->table.GDEF->table +#else + Null (GDEF) +#endif + ), var_store (gdef.get_var_store ()), direction (buffer_->props.direction), lookup_mask (1), @@ -491,7 +565,6 @@ struct hb_ot_apply_context_t : lookup_index ((unsigned int) -1), lookup_props (0), nesting_level_left (HB_MAX_NESTING_LEVEL), - debug_depth (0), has_glyph_classes (gdef.has_glyph_classes ()), auto_zwnj (true), auto_zwj (true), @@ -595,13 +668,13 @@ struct hb_ot_apply_context_t : buffer->cur().codepoint = glyph_index; } void replace_glyph_with_ligature (hb_codepoint_t glyph_index, - unsigned int class_guess) const + unsigned int class_guess) const { _set_glyph_props (glyph_index, class_guess, true); buffer->replace_glyph (glyph_index); } void output_glyph_for_component (hb_codepoint_t glyph_index, - unsigned int class_guess) const + unsigned int class_guess) const { _set_glyph_props (glyph_index, class_guess, false, true); buffer->output_glyph (glyph_index); @@ -610,10 +683,10 @@ struct hb_ot_apply_context_t : struct hb_get_subtables_context_t : - hb_dispatch_context_t + hb_dispatch_context_t { template - static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c) + static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c) { const Type *typed_obj = (const Type *) obj; return typed_obj->apply (c); @@ -629,7 +702,7 @@ struct hb_get_subtables_context_t : obj = &obj_; apply_func = apply_func_; digest.init (); - obj_.get_coverage ().add_coverage (&digest); + obj_.get_coverage ().collect_coverage (&digest); } bool apply (OT::hb_ot_apply_context_t *c) const @@ -646,22 +719,19 @@ struct hb_get_subtables_context_t : typedef hb_vector_t array_t; /* Dispatch interface. */ - const char *get_name () { return "GET_SUBTABLES"; } template return_t dispatch (const T &obj) { hb_applicable_t *entry = array.push(); entry->init (obj, apply_to); - return HB_VOID; + return hb_empty_t (); } - static return_t default_return_value () { return HB_VOID; } + static return_t default_return_value () { return hb_empty_t (); } hb_get_subtables_context_t (array_t &array_) : - array (array_), - debug_depth (0) {} + array (array_) {} array_t &array; - unsigned int debug_depth; }; @@ -700,15 +770,14 @@ static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 & return (data+coverage).intersects (glyphs); } -static inline bool intersects_array (const hb_set_t *glyphs, - unsigned int count, - const HBUINT16 values[], - intersects_func_t intersects_func, - const void *intersects_data) +static inline bool array_is_subset_of (const hb_set_t *glyphs, + unsigned int count, + const HBUINT16 values[], + intersects_func_t intersects_func, + const void *intersects_data) { - for (unsigned int i = 0; i < count; i++) - if (likely (!intersects_func (glyphs, values[i], intersects_data))) - return false; + for (const HBUINT16 &_ : + hb_iter (values, count)) + if (!intersects_func (glyphs, _, intersects_data)) return false; return true; } @@ -720,12 +789,12 @@ static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data) { const ClassDef &class_def = *reinterpret_cast(data); - class_def.add_class (glyphs, value); + class_def.collect_class (glyphs, value); } static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data) { const OffsetTo &coverage = (const OffsetTo&)value; - (data+coverage).add_coverage (glyphs); + (data+coverage).collect_coverage (glyphs); } static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, hb_set_t *glyphs, @@ -734,8 +803,10 @@ static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, collect_glyphs_func_t collect_func, const void *collect_data) { - for (unsigned int i = 0; i < count; i++) - collect_func (glyphs, values[i], collect_data); + return + + hb_iter (values, count) + | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); }) + ; } @@ -846,7 +917,7 @@ static inline bool match_input (hb_ot_apply_context_t *c, if (ligbase == LIGBASE_NOT_CHECKED) { bool found = false; - const hb_glyph_info_t *out = buffer->out_info; + const auto *out = buffer->out_info; unsigned int j = buffer->out_len; while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id) { @@ -970,7 +1041,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, if (this_comp == 0) this_comp = last_num_components; unsigned int new_lig_comp = components_so_far - last_num_components + - MIN (this_comp, last_num_components); + hb_min (this_comp, last_num_components); _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp); } buffer->next_glyph (); @@ -984,18 +1055,19 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, buffer->idx++; } - if (!is_mark_ligature && last_lig_id) { + if (!is_mark_ligature && last_lig_id) + { /* Re-adjust components for any marks following. */ - for (unsigned int i = buffer->idx; i < buffer->len; i++) { - if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) { - unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]); - if (!this_comp) - break; - unsigned int new_lig_comp = components_so_far - last_num_components + - MIN (this_comp, last_num_components); - _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp); - } else - break; + for (unsigned i = buffer->idx; i < buffer->len; ++i) + { + if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break; + + unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]); + if (!this_comp) break; + + unsigned new_lig_comp = components_so_far - last_num_components + + hb_min (this_comp, last_num_components); + _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp); } } return_trace (true); @@ -1050,6 +1122,17 @@ static inline bool match_lookahead (hb_ot_apply_context_t *c, struct LookupRecord { + LookupRecord* copy (hb_serialize_context_t *c, + const hb_map_t *lookup_map) const + { + TRACE_SERIALIZE (this); + auto *out = c->embed (*this); + if (unlikely (!out)) return_trace (nullptr); + + out->lookupListIndex = hb_map_get (lookup_map, lookupListIndex); + return_trace (out); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -1170,7 +1253,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, else { /* NOTE: delta is negative. */ - delta = MAX (delta, (int) next - (int) count); + delta = hb_max (delta, (int) next - (int) count); next -= delta; } @@ -1221,9 +1304,9 @@ static inline bool context_intersects (const hb_set_t *glyphs, const HBUINT16 input[], /* Array of input values--start with second glyph */ ContextClosureLookupContext &lookup_context) { - return intersects_array (glyphs, - inputCount ? inputCount - 1 : 0, input, - lookup_context.funcs.intersects, lookup_context.intersects_data); + return array_is_subset_of (glyphs, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data); } static inline void context_closure_lookup (hb_closure_context_t *c, @@ -1296,7 +1379,9 @@ struct Rule void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { - const UnsizedArrayOf &lookupRecord = StructAfter > + if (unlikely (c->lookup_limit_exceeded ())) return; + + const UnsizedArrayOf &lookupRecord = StructAfter> (inputZ.as_array ((inputCount ? inputCount - 1 : 0))); context_closure_lookup (c, inputCount, inputZ.arrayZ, @@ -1304,10 +1389,19 @@ struct Rule lookup_context); } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + if (unlikely (c->lookup_limit_exceeded ())) return; + + const UnsizedArrayOf &lookupRecord = StructAfter> + (inputZ.as_array (inputCount ? inputCount - 1 : 0)); + recurse_lookups (c, lookupCount, lookupRecord.arrayZ); + } + void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const { - const UnsizedArrayOf &lookupRecord = StructAfter > + const UnsizedArrayOf &lookupRecord = StructAfter> (inputZ.as_array (inputCount ? inputCount - 1 : 0)); context_collect_glyphs_lookup (c, inputCount, inputZ.arrayZ, @@ -1318,21 +1412,64 @@ struct Rule bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { - TRACE_WOULD_APPLY (this); - const UnsizedArrayOf &lookupRecord = StructAfter > + const UnsizedArrayOf &lookupRecord = StructAfter> (inputZ.as_array (inputCount ? inputCount - 1 : 0)); - return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context)); + return context_would_apply_lookup (c, + inputCount, inputZ.arrayZ, + lookupCount, lookupRecord.arrayZ, + lookup_context); } bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); - const UnsizedArrayOf &lookupRecord = StructAfter > + const UnsizedArrayOf &lookupRecord = StructAfter> (inputZ.as_array (inputCount ? inputCount - 1 : 0)); return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context)); } + bool serialize (hb_serialize_context_t *c, + const hb_map_t *input_mapping, /* old->new glyphid or class mapping */ + const hb_map_t *lookup_map) const + { + TRACE_SERIALIZE (this); + auto *out = c->start_embed (this); + if (unlikely (!c->extend_min (out))) return_trace (false); + + out->inputCount = inputCount; + out->lookupCount = lookupCount; + + const hb_array_t input = inputZ.as_array (inputCount - 1); + for (const auto org : input) + { + HBUINT16 d; + d = input_mapping->get (org); + c->copy (d); + } + + const UnsizedArrayOf &lookupRecord = StructAfter> + (inputZ.as_array ((inputCount ? inputCount - 1 : 0))); + for (unsigned i = 0; i < (unsigned) lookupCount; i++) + c->copy (lookupRecord[i], lookup_map); + + return_trace (true); + } + + bool subset (hb_subset_context_t *c, + const hb_map_t *lookup_map, + const hb_map_t *klass_map = nullptr) const + { + TRACE_SUBSET (this); + + const hb_array_t input = inputZ.as_array ((inputCount ? inputCount - 1 : 0)); + if (!input.length) return_trace (false); + + const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map; + if (!hb_all (input, mapping)) return_trace (false); + return_trace (serialize (c->serializer, mapping, lookup_map)); + } + public: bool sanitize (hb_sanitize_context_t *c) const { @@ -1364,53 +1501,99 @@ struct RuleSet bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const { - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) - if ((this+rule[i]).intersects (glyphs, lookup_context)) - return true; - return false; + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); }) + | hb_any + ; } void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const { - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) - (this+rule[i]).closure (c, lookup_context); + if (unlikely (c->lookup_limit_exceeded ())) return; + + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); }) + ; + } + + void closure_lookups (hb_closure_lookups_context_t *c) const + { + if (unlikely (c->lookup_limit_exceeded ())) return; + + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([&] (const Rule &_) { _.closure_lookups (c); }) + ; } void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const { - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) - (this+rule[i]).collect_glyphs (c, lookup_context); + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); }) + ; } bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { - TRACE_WOULD_APPLY (this); - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) - { - if ((this+rule[i]).would_apply (c, lookup_context)) - return_trace (true); - } - return_trace (false); + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); }) + | hb_any + ; } bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) + return_trace ( + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); }) + | hb_any + ) + ; + } + + bool subset (hb_subset_context_t *c, + const hb_map_t *lookup_map, + const hb_map_t *klass_map = nullptr) const + { + TRACE_SUBSET (this); + + auto snap = c->serializer->snapshot (); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + for (const OffsetTo& _ : rule) { - if ((this+rule[i]).apply (c, lookup_context)) - return_trace (true); + if (!_) continue; + auto *o = out->rule.serialize_append (c->serializer); + if (unlikely (!o)) continue; + + auto o_snap = c->serializer->snapshot (); + if (!o->serialize_subset (c, _, this, lookup_map, klass_map)) + { + out->rule.pop (); + c->serializer->revert (o_snap); + } } - return_trace (false); + + bool ret = bool (out->rule); + if (!ret) c->serializer->revert (snap); + + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -1437,16 +1620,14 @@ struct ContextFormat1 nullptr }; - unsigned int count = ruleSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (glyphs->has (iter.get_glyph ()) && - (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) - return true; - } - return false; + return + + hb_zip (this+coverage, ruleSet) + | hb_filter (*glyphs, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); }) + | hb_any + ; } void closure (hb_closure_context_t *c) const @@ -1456,40 +1637,47 @@ struct ContextFormat1 nullptr }; - unsigned int count = ruleSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) - (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); - } + + hb_zip (this+coverage, ruleSet) + | hb_filter (*c->glyphs, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); }) + ; + } + + void closure_lookups (hb_closure_lookups_context_t *c) const + { + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); }) + ; } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - (this+coverage).add_coverage (c->input); + (this+coverage).collect_coverage (c->input); struct ContextCollectGlyphsLookupContext lookup_context = { {collect_glyph}, nullptr }; - unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - (this+ruleSet[i]).collect_glyphs (c, lookup_context); + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); }) + ; } bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (this); - const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; struct ContextApplyLookupContext lookup_context = { {match_glyph}, nullptr }; - return_trace (rule_set.would_apply (c, lookup_context)); + return rule_set.would_apply (c, lookup_context); } const Coverage &get_coverage () const { return this+coverage; } @@ -1512,8 +1700,26 @@ struct ContextFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups; + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, ruleSet) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + out->coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1549,13 +1755,15 @@ struct ContextFormat2 &class_def }; - unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (class_def.intersects_class (glyphs, i) && - (this+ruleSet[i]).intersects (glyphs, lookup_context)) - return true; - - return false; + return + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_enumerate + | hb_map ([&] (const hb_pair_t p) + { return class_def.intersects_class (glyphs, p.first) && + p.second.intersects (glyphs, lookup_context); }) + | hb_any + ; } void closure (hb_closure_context_t *c) const @@ -1570,17 +1778,30 @@ struct ContextFormat2 &class_def }; - unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (class_def.intersects_class (c->glyphs, i)) { - const RuleSet &rule_set = this+ruleSet[i]; - rule_set.closure (c, lookup_context); - } + return + + hb_enumerate (ruleSet) + | hb_filter ([&] (unsigned _) + { return class_def.intersects_class (c->glyphs, _); }, + hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); }) + ; } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); }) + ; + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - (this+coverage).add_coverage (c->input); + (this+coverage).collect_coverage (c->input); const ClassDef &class_def = this+classDef; struct ContextCollectGlyphsLookupContext lookup_context = { @@ -1588,15 +1809,14 @@ struct ContextFormat2 &class_def }; - unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - (this+ruleSet[i]).collect_glyphs (c, lookup_context); + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); }) + ; } bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (this); - const ClassDef &class_def = this+classDef; unsigned int index = class_def.get_class (c->glyphs[0]); const RuleSet &rule_set = this+ruleSet[index]; @@ -1604,7 +1824,7 @@ struct ContextFormat2 {match_class}, &class_def }; - return_trace (rule_set.would_apply (c, lookup_context)); + return rule_set.would_apply (c, lookup_context); } const Coverage &get_coverage () const { return this+coverage; } @@ -1628,8 +1848,45 @@ struct ContextFormat2 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + if (unlikely (!out->coverage.serialize_subset (c, coverage, this))) + return_trace (false); + + hb_map_t klass_map; + out->classDef.serialize_subset (c, classDef, this, &klass_map); + + const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups; + bool ret = true; + unsigned non_zero_index = 0, index = 0; + for (const hb_pair_t&> _ : + hb_enumerate (ruleSet) + | hb_filter (klass_map, hb_first)) + { + auto *o = out->ruleSet.serialize_append (c->serializer); + if (unlikely (!o)) + { + ret = false; + break; + } + + if (o->serialize_subset (c, _.second, this, lookup_map, &klass_map)) + non_zero_index = index; + + index++; + } + + if (!ret) return_trace (ret); + + //prune empty trailing ruleSets + --index; + while (index > non_zero_index) + { + out->ruleSet.pop (); + index--; + } + + return_trace (bool (out->ruleSet)); } bool sanitize (hb_sanitize_context_t *c) const @@ -1686,9 +1943,17 @@ struct ContextFormat3 lookup_context); } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + const LookupRecord *lookupRecord = &StructAfter (coverageZ.as_array (glyphCount)); + recurse_lookups (c, lookupCount, lookupRecord); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - (this+coverageZ[0]).add_coverage (c->input); + (this+coverageZ[0]).collect_coverage (c->input); const LookupRecord *lookupRecord = &StructAfter (coverageZ.as_array (glyphCount)); struct ContextCollectGlyphsLookupContext lookup_context = { @@ -1704,14 +1969,15 @@ struct ContextFormat3 bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (this); - const LookupRecord *lookupRecord = &StructAfter (coverageZ.as_array (glyphCount)); struct ContextApplyLookupContext lookup_context = { {match_coverage}, this }; - return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context)); + return context_would_apply_lookup (c, + glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), + lookupCount, lookupRecord, + lookup_context); } const Coverage &get_coverage () const { return this+coverageZ[0]; } @@ -1733,8 +1999,28 @@ struct ContextFormat3 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + auto *out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + out->format = format; + out->glyphCount = glyphCount; + out->lookupCount = lookupCount; + + auto coverages = coverageZ.as_array (glyphCount); + + for (const OffsetTo& offset : coverages) + { + auto *o = c->serializer->allocate_size> (OffsetTo::static_size); + if (unlikely (!o)) return_trace (false); + if (!o->serialize_subset (c, offset, this)) return_trace (false); + } + + const LookupRecord *lookupRecord = &StructAfter (coverageZ.as_array (glyphCount)); + const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups; + for (unsigned i = 0; i < (unsigned) lookupCount; i++) + c->serializer->copy (lookupRecord[i], lookup_map); + + return_trace (true); } bool sanitize (hb_sanitize_context_t *c) const @@ -1755,7 +2041,7 @@ struct ContextFormat3 HBUINT16 glyphCount; /* Number of glyphs in the input glyph * sequence */ HBUINT16 lookupCount; /* Number of LookupRecords */ - UnsizedArrayOf > + UnsizedArrayOf> coverageZ; /* Array of offsets to Coverage * table in glyph sequence order */ /*UnsizedArrayOf @@ -1767,15 +2053,15 @@ struct ContextFormat3 struct Context { - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); - case 2: return_trace (c->dispatch (u.format2)); - case 3: return_trace (c->dispatch (u.format3)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, hb_forward (ds)...)); + case 3: return_trace (c->dispatch (u.format3, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -1819,15 +2105,15 @@ static inline bool chain_context_intersects (const hb_set_t *glyphs, const HBUINT16 lookahead[], ChainContextClosureLookupContext &lookup_context) { - return intersects_array (glyphs, - backtrackCount, backtrack, - lookup_context.funcs.intersects, lookup_context.intersects_data[0]) - && intersects_array (glyphs, - inputCount ? inputCount - 1 : 0, input, - lookup_context.funcs.intersects, lookup_context.intersects_data[1]) - && intersects_array (glyphs, - lookaheadCount, lookahead, - lookup_context.funcs.intersects, lookup_context.intersects_data[2]); + return array_is_subset_of (glyphs, + backtrackCount, backtrack, + lookup_context.funcs.intersects, lookup_context.intersects_data[0]) + && array_is_subset_of (glyphs, + inputCount ? inputCount - 1 : 0, input, + lookup_context.funcs.intersects, lookup_context.intersects_data[1]) + && array_is_subset_of (glyphs, + lookaheadCount, lookahead, + lookup_context.funcs.intersects, lookup_context.intersects_data[2]); } static inline void chain_context_closure_lookup (hb_closure_context_t *c, @@ -1927,8 +2213,8 @@ struct ChainRule { bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const { - const HeadlessArrayOf &input = StructAfter > (backtrack); - const ArrayOf &lookahead = StructAfter > (input); + const HeadlessArrayOf &input = StructAfter> (backtrack); + const ArrayOf &lookahead = StructAfter> (input); return chain_context_intersects (glyphs, backtrack.len, backtrack.arrayZ, input.lenP1, input.arrayZ, @@ -1939,9 +2225,11 @@ struct ChainRule void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { - const HeadlessArrayOf &input = StructAfter > (backtrack); - const ArrayOf &lookahead = StructAfter > (input); - const ArrayOf &lookup = StructAfter > (lookahead); + if (unlikely (c->lookup_limit_exceeded ())) return; + + const HeadlessArrayOf &input = StructAfter> (backtrack); + const ArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); chain_context_closure_lookup (c, backtrack.len, backtrack.arrayZ, input.lenP1, input.arrayZ, @@ -1950,12 +2238,22 @@ struct ChainRule lookup_context); } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + if (unlikely (c->lookup_limit_exceeded ())) return; + + const HeadlessArrayOf &input = StructAfter> (backtrack); + const ArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); + recurse_lookups (c, lookup.len, lookup.arrayZ); + } + void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const { - const HeadlessArrayOf &input = StructAfter > (backtrack); - const ArrayOf &lookahead = StructAfter > (input); - const ArrayOf &lookup = StructAfter > (lookahead); + const HeadlessArrayOf &input = StructAfter> (backtrack); + const ArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); chain_context_collect_glyphs_lookup (c, backtrack.len, backtrack.arrayZ, input.lenP1, input.arrayZ, @@ -1967,23 +2265,22 @@ struct ChainRule bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { - TRACE_WOULD_APPLY (this); - const HeadlessArrayOf &input = StructAfter > (backtrack); - const ArrayOf &lookahead = StructAfter > (input); - const ArrayOf &lookup = StructAfter > (lookahead); - return_trace (chain_context_would_apply_lookup (c, - backtrack.len, backtrack.arrayZ, - input.lenP1, input.arrayZ, - lookahead.len, lookahead.arrayZ, lookup.len, - lookup.arrayZ, lookup_context)); + const HeadlessArrayOf &input = StructAfter> (backtrack); + const ArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); + return chain_context_would_apply_lookup (c, + backtrack.len, backtrack.arrayZ, + input.lenP1, input.arrayZ, + lookahead.len, lookahead.arrayZ, lookup.len, + lookup.arrayZ, lookup_context); } bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); - const HeadlessArrayOf &input = StructAfter > (backtrack); - const ArrayOf &lookahead = StructAfter > (input); - const ArrayOf &lookup = StructAfter > (lookahead); + const HeadlessArrayOf &input = StructAfter> (backtrack); + const ArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); return_trace (chain_context_apply_lookup (c, backtrack.len, backtrack.arrayZ, input.lenP1, input.arrayZ, @@ -1991,15 +2288,99 @@ struct ChainRule lookup.arrayZ, lookup_context)); } + template + void serialize_array (hb_serialize_context_t *c, + HBUINT16 len, + Iterator it) const + { + c->copy (len); + for (const auto g : it) + { + HBUINT16 gid; + gid = g; + c->copy (gid); + } + } + + ChainRule* copy (hb_serialize_context_t *c, + const hb_map_t *lookup_map, + const hb_map_t *backtrack_map, + const hb_map_t *input_map = nullptr, + const hb_map_t *lookahead_map = nullptr) const + { + TRACE_SERIALIZE (this); + auto *out = c->start_embed (this); + if (unlikely (!out)) return_trace (nullptr); + + const hb_map_t *mapping = backtrack_map; + serialize_array (c, backtrack.len, + backtrack.iter () + | hb_map (mapping)); + + const HeadlessArrayOf &input = StructAfter> (backtrack); + if (input_map) mapping = input_map; + serialize_array (c, input.lenP1, + input.iter () + | hb_map (mapping)); + + const ArrayOf &lookahead = StructAfter> (input); + if (lookahead_map) mapping = lookahead_map; + serialize_array (c, lookahead.len, + lookahead.iter () + | hb_map (mapping)); + + const ArrayOf &lookupRecord = StructAfter> (lookahead); + HBUINT16 lookupCount; + lookupCount = lookupRecord.len; + if (!c->copy (lookupCount)) return_trace (nullptr); + + for (unsigned i = 0; i < (unsigned) lookupCount; i++) + if (!c->copy (lookupRecord[i], lookup_map)) return_trace (nullptr); + + return_trace (out); + } + + bool subset (hb_subset_context_t *c, + const hb_map_t *lookup_map, + const hb_map_t *backtrack_map = nullptr, + const hb_map_t *input_map = nullptr, + const hb_map_t *lookahead_map = nullptr) const + { + TRACE_SUBSET (this); + + const HeadlessArrayOf &input = StructAfter> (backtrack); + const ArrayOf &lookahead = StructAfter> (input); + + if (!backtrack_map) + { + const hb_set_t &glyphset = *c->plan->glyphset (); + if (!hb_all (backtrack, glyphset) || + !hb_all (input, glyphset) || + !hb_all (lookahead, glyphset)) + return_trace (false); + + copy (c->serializer, lookup_map, c->plan->glyph_map); + } + else + { + if (!hb_all (backtrack, backtrack_map) || + !hb_all (input, input_map) || + !hb_all (lookahead, lookahead_map)) + return_trace (false); + + copy (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map); + } + + return_trace (true); + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!backtrack.sanitize (c)) return_trace (false); - const HeadlessArrayOf &input = StructAfter > (backtrack); + const HeadlessArrayOf &input = StructAfter> (backtrack); if (!input.sanitize (c)) return_trace (false); - const ArrayOf &lookahead = StructAfter > (input); + const ArrayOf &lookahead = StructAfter> (input); if (!lookahead.sanitize (c)) return_trace (false); - const ArrayOf &lookup = StructAfter > (lookahead); + const ArrayOf &lookup = StructAfter> (lookahead); return_trace (lookup.sanitize (c)); } @@ -2025,46 +2406,100 @@ struct ChainRuleSet { bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const { - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) - if ((this+rule[i]).intersects (glyphs, lookup_context)) - return true; - return false; + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); }) + | hb_any + ; } void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const { - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) - (this+rule[i]).closure (c, lookup_context); + if (unlikely (c->lookup_limit_exceeded ())) return; + + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); }) + ; + } + + void closure_lookups (hb_closure_lookups_context_t *c) const + { + if (unlikely (c->lookup_limit_exceeded ())) return; + + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c); }) + ; } void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const { - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) - (this+rule[i]).collect_glyphs (c, lookup_context); + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); }) + ; } bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { - TRACE_WOULD_APPLY (this); - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) - if ((this+rule[i]).would_apply (c, lookup_context)) - return_trace (true); - - return_trace (false); + return + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); }) + | hb_any + ; } bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const { TRACE_APPLY (this); - unsigned int num_rules = rule.len; - for (unsigned int i = 0; i < num_rules; i++) - if ((this+rule[i]).apply (c, lookup_context)) - return_trace (true); + return_trace ( + + hb_iter (rule) + | hb_map (hb_add (this)) + | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); }) + | hb_any + ) + ; + } + + bool subset (hb_subset_context_t *c, + const hb_map_t *lookup_map, + const hb_map_t *backtrack_klass_map = nullptr, + const hb_map_t *input_klass_map = nullptr, + const hb_map_t *lookahead_klass_map = nullptr) const + { + TRACE_SUBSET (this); + + auto snap = c->serializer->snapshot (); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + for (const OffsetTo& _ : rule) + { + if (!_) continue; + auto *o = out->rule.serialize_append (c->serializer); + if (unlikely (!o)) continue; + + auto o_snap = c->serializer->snapshot (); + if (!o->serialize_subset (c, _, this, + lookup_map, + backtrack_klass_map, + input_klass_map, + lookahead_klass_map)) + { + out->rule.pop (); + c->serializer->revert (o_snap); + } + } + + bool ret = bool (out->rule); + if (!ret) c->serializer->revert (snap); - return_trace (false); + return_trace (ret); } bool sanitize (hb_sanitize_context_t *c) const @@ -2090,16 +2525,14 @@ struct ChainContextFormat1 {nullptr, nullptr, nullptr} }; - unsigned int count = ruleSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (glyphs->has (iter.get_glyph ()) && - (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context)) - return true; - } - return false; + return + + hb_zip (this+coverage, ruleSet) + | hb_filter (*glyphs, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); }) + | hb_any + ; } void closure (hb_closure_context_t *c) const @@ -2109,40 +2542,47 @@ struct ChainContextFormat1 {nullptr, nullptr, nullptr} }; - unsigned int count = ruleSet.len; - for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ()) - { - if (unlikely (iter.get_coverage () >= count)) - break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */ - if (c->glyphs->has (iter.get_glyph ())) - (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context); - } + + hb_zip (this+coverage, ruleSet) + | hb_filter (*c->glyphs, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); }) + ; } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); }) + ; + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - (this+coverage).add_coverage (c->input); + (this+coverage).collect_coverage (c->input); struct ChainContextCollectGlyphsLookupContext lookup_context = { {collect_glyph}, {nullptr, nullptr, nullptr} }; - unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - (this+ruleSet[i]).collect_glyphs (c, lookup_context); + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); }) + ; } bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (this); - const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; struct ChainContextApplyLookupContext lookup_context = { {match_glyph}, {nullptr, nullptr, nullptr} }; - return_trace (rule_set.would_apply (c, lookup_context)); + return rule_set.would_apply (c, lookup_context); } const Coverage &get_coverage () const { return this+coverage; } @@ -2164,8 +2604,26 @@ struct ChainContextFormat1 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + const hb_set_t &glyphset = *c->plan->glyphset (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups; + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, ruleSet) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + + out->coverage.serialize (c->serializer, out) + .serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); } bool sanitize (hb_sanitize_context_t *c) const @@ -2204,13 +2662,15 @@ struct ChainContextFormat2 &lookahead_class_def} }; - unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (input_class_def.intersects_class (glyphs, i) && - (this+ruleSet[i]).intersects (glyphs, lookup_context)) - return true; - - return false; + return + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_enumerate + | hb_map ([&] (const hb_pair_t p) + { return input_class_def.intersects_class (glyphs, p.first) && + p.second.intersects (glyphs, lookup_context); }) + | hb_any + ; } void closure (hb_closure_context_t *c) const { @@ -2228,17 +2688,30 @@ struct ChainContextFormat2 &lookahead_class_def} }; - unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - if (input_class_def.intersects_class (c->glyphs, i)) { - const ChainRuleSet &rule_set = this+ruleSet[i]; - rule_set.closure (c, lookup_context); - } + return + + hb_enumerate (ruleSet) + | hb_filter ([&] (unsigned _) + { return input_class_def.intersects_class (c->glyphs, _); }, + hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); }) + ; + } + + void closure_lookups (hb_closure_lookups_context_t *c) const + { + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); }) + ; } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - (this+coverage).add_coverage (c->input); + (this+coverage).collect_coverage (c->input); const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; @@ -2251,15 +2724,14 @@ struct ChainContextFormat2 &lookahead_class_def} }; - unsigned int count = ruleSet.len; - for (unsigned int i = 0; i < count; i++) - (this+ruleSet[i]).collect_glyphs (c, lookup_context); + + hb_iter (ruleSet) + | hb_map (hb_add (this)) + | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); }) + ; } bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (this); - const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; const ClassDef &lookahead_class_def = this+lookaheadClassDef; @@ -2272,7 +2744,7 @@ struct ChainContextFormat2 &input_class_def, &lookahead_class_def} }; - return_trace (rule_set.would_apply (c, lookup_context)); + return rule_set.would_apply (c, lookup_context); } const Coverage &get_coverage () const { return this+coverage; } @@ -2301,8 +2773,61 @@ struct ChainContextFormat2 bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + out->coverage.serialize_subset (c, coverage, this); + + hb_map_t backtrack_klass_map; + out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map); + if (unlikely (!c->serializer->check_success (!backtrack_klass_map.in_error ()))) + return_trace (false); + + // subset inputClassDef based on glyphs survived in Coverage subsetting + hb_map_t input_klass_map; + out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map); + if (unlikely (!c->serializer->check_success (!input_klass_map.in_error ()))) + return_trace (false); + + hb_map_t lookahead_klass_map; + out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map); + if (unlikely (!c->serializer->check_success (!lookahead_klass_map.in_error ()))) + return_trace (false); + + unsigned non_zero_index = 0, index = 0; + bool ret = true; + const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups; + for (const OffsetTo& _ : + hb_enumerate (ruleSet) + | hb_filter (input_klass_map, hb_first) + | hb_map (hb_second)) + { + auto *o = out->ruleSet.serialize_append (c->serializer); + if (unlikely (!o)) + { + ret = false; + break; + } + if (o->serialize_subset (c, _, this, + lookup_map, + &backtrack_klass_map, + &input_klass_map, + &lookahead_klass_map)) + non_zero_index = index; + + index++; + } + + if (!ret) return_trace (ret); + + //prune empty trailing ruleSets + --index; + while (index > non_zero_index) + { + out->ruleSet.pop (); + index--; + } + + return_trace (bool (out->ruleSet)); } bool sanitize (hb_sanitize_context_t *c) const @@ -2343,12 +2868,12 @@ struct ChainContextFormat3 { bool intersects (const hb_set_t *glyphs) const { - const OffsetArrayOf &input = StructAfter > (backtrack); + const OffsetArrayOf &input = StructAfter> (backtrack); if (!(this+input[0]).intersects (glyphs)) return false; - const OffsetArrayOf &lookahead = StructAfter > (input); + const OffsetArrayOf &lookahead = StructAfter> (input); struct ChainContextClosureLookupContext lookup_context = { {intersects_coverage}, {this, this, this} @@ -2362,13 +2887,13 @@ struct ChainContextFormat3 void closure (hb_closure_context_t *c) const { - const OffsetArrayOf &input = StructAfter > (backtrack); + const OffsetArrayOf &input = StructAfter> (backtrack); if (!(this+input[0]).intersects (c->glyphs)) return; - const OffsetArrayOf &lookahead = StructAfter > (input); - const ArrayOf &lookup = StructAfter > (lookahead); + const OffsetArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); struct ChainContextClosureLookupContext lookup_context = { {intersects_coverage}, {this, this, this} @@ -2381,14 +2906,24 @@ struct ChainContextFormat3 lookup_context); } + void closure_lookups (hb_closure_lookups_context_t *c) const + { + const OffsetArrayOf &input = StructAfter> (backtrack); + const OffsetArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); + recurse_lookups (c, lookup.len, lookup.arrayZ); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {} + void collect_glyphs (hb_collect_glyphs_context_t *c) const { - const OffsetArrayOf &input = StructAfter > (backtrack); + const OffsetArrayOf &input = StructAfter> (backtrack); - (this+input[0]).add_coverage (c->input); + (this+input[0]).collect_coverage (c->input); - const OffsetArrayOf &lookahead = StructAfter > (input); - const ArrayOf &lookup = StructAfter > (lookahead); + const OffsetArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); struct ChainContextCollectGlyphsLookupContext lookup_context = { {collect_coverage}, {this, this, this} @@ -2403,38 +2938,36 @@ struct ChainContextFormat3 bool would_apply (hb_would_apply_context_t *c) const { - TRACE_WOULD_APPLY (this); - - const OffsetArrayOf &input = StructAfter > (backtrack); - const OffsetArrayOf &lookahead = StructAfter > (input); - const ArrayOf &lookup = StructAfter > (lookahead); + const OffsetArrayOf &input = StructAfter> (backtrack); + const OffsetArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); struct ChainContextApplyLookupContext lookup_context = { {match_coverage}, {this, this, this} }; - return_trace (chain_context_would_apply_lookup (c, - backtrack.len, (const HBUINT16 *) backtrack.arrayZ, - input.len, (const HBUINT16 *) input.arrayZ + 1, - lookahead.len, (const HBUINT16 *) lookahead.arrayZ, - lookup.len, lookup.arrayZ, lookup_context)); + return chain_context_would_apply_lookup (c, + backtrack.len, (const HBUINT16 *) backtrack.arrayZ, + input.len, (const HBUINT16 *) input.arrayZ + 1, + lookahead.len, (const HBUINT16 *) lookahead.arrayZ, + lookup.len, lookup.arrayZ, lookup_context); } const Coverage &get_coverage () const { - const OffsetArrayOf &input = StructAfter > (backtrack); + const OffsetArrayOf &input = StructAfter> (backtrack); return this+input[0]; } bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); - const OffsetArrayOf &input = StructAfter > (backtrack); + const OffsetArrayOf &input = StructAfter> (backtrack); unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - const OffsetArrayOf &lookahead = StructAfter > (input); - const ArrayOf &lookup = StructAfter > (lookahead); + const OffsetArrayOf &lookahead = StructAfter> (input); + const ArrayOf &lookup = StructAfter> (lookahead); struct ChainContextApplyLookupContext lookup_context = { {match_coverage}, {this, this, this} @@ -2446,23 +2979,63 @@ struct ChainContextFormat3 lookup.len, lookup.arrayZ, lookup_context)); } + template + bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const + { + TRACE_SERIALIZE (this); + auto *out = c->serializer->start_embed> (); + + if (unlikely (!c->serializer->allocate_size (HBUINT16::static_size))) return_trace (false); + + + it + | hb_apply (subset_offset_array (c, *out, base)) + ; + + return_trace (out->len); + } + bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - // TODO(subset) - return_trace (false); + + auto *out = c->serializer->start_embed (this); + if (unlikely (!out)) return_trace (false); + if (unlikely (!c->serializer->embed (this->format))) return_trace (false); + + if (!serialize_coverage_offsets (c, backtrack.iter (), this)) + return_trace (false); + + const OffsetArrayOf &input = StructAfter> (backtrack); + if (!serialize_coverage_offsets (c, input.iter (), this)) + return_trace (false); + + const OffsetArrayOf &lookahead = StructAfter> (input); + if (!serialize_coverage_offsets (c, lookahead.iter (), this)) + return_trace (false); + + const ArrayOf &lookupRecord = StructAfter> (lookahead); + HBUINT16 lookupCount; + lookupCount = lookupRecord.len; + if (!c->serializer->copy (lookupCount)) return_trace (false); + + const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups; + for (unsigned i = 0; i < (unsigned) lookupCount; i++) + if (!c->serializer->copy (lookupRecord[i], lookup_map)) return_trace (false); + + return_trace (true); } bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); if (!backtrack.sanitize (c, this)) return_trace (false); - const OffsetArrayOf &input = StructAfter > (backtrack); + const OffsetArrayOf &input = StructAfter> (backtrack); if (!input.sanitize (c, this)) return_trace (false); if (!input.len) return_trace (false); /* To be consistent with Context. */ - const OffsetArrayOf &lookahead = StructAfter > (input); + const OffsetArrayOf &lookahead = StructAfter> (input); if (!lookahead.sanitize (c, this)) return_trace (false); - const ArrayOf &lookup = StructAfter > (lookahead); + const ArrayOf &lookup = StructAfter> (lookahead); return_trace (lookup.sanitize (c)); } @@ -2489,15 +3062,15 @@ struct ChainContextFormat3 struct ChainContext { - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (c->dispatch (u.format1)); - case 2: return_trace (c->dispatch (u.format2)); - case 3: return_trace (c->dispatch (u.format3)); + case 1: return_trace (c->dispatch (u.format1, hb_forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, hb_forward (ds)...)); + case 3: return_trace (c->dispatch (u.format3, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -2519,26 +3092,24 @@ struct ExtensionFormat1 template const X& get_subtable () const - { - unsigned int offset = extensionOffset; - if (unlikely (!offset)) return Null(typename T::SubTable); - return StructAtOffset (this, offset); - } + { return this + reinterpret_cast &> (extensionOffset); } - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, format); if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ()); - return_trace (get_subtable ().dispatch (c, get_type ())); + return_trace (get_subtable ().dispatch (c, get_type (), hb_forward (ds)...)); } + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { dispatch (c); } + /* This is called from may_dispatch() above with hb_sanitize_context_t. */ bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this) && - extensionOffset != 0 && extensionLookupType != T::SubTable::Extension); } @@ -2547,7 +3118,7 @@ struct ExtensionFormat1 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced * by ExtensionOffset (i.e. the * extension subtable). */ - HBUINT32 extensionOffset; /* Offset to the extension subtable, + Offset32 extensionOffset; /* Offset to the extension subtable, * of lookup type subtable. */ public: DEFINE_SIZE_STATIC (8); @@ -2568,17 +3139,17 @@ struct Extension { switch (u.format) { case 1: return u.format1.template get_subtable (); - default:return Null(typename T::SubTable); + default:return Null (typename T::SubTable); } } - template - typename context_t::return_t dispatch (context_t *c) const + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { TRACE_DISPATCH (this, u.format); if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { - case 1: return_trace (u.format1.dispatch (c)); + case 1: return_trace (u.format1.dispatch (c, hb_forward (ds)...)); default:return_trace (c->default_return_value ()); } } @@ -2601,7 +3172,7 @@ struct hb_ot_layout_lookup_accelerator_t void init (const TLookup &lookup) { digest.init (); - lookup.add_coverage (&digest); + lookup.collect_coverage (&digest); subtables.init (); OT::hb_get_subtables_context_t c_get_subtables (subtables); @@ -2661,11 +3232,18 @@ struct GSUBGPOS bool find_variations_index (const int *coords, unsigned int num_coords, unsigned int *index) const - { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations)) - .find_index (coords, num_coords, index); } + { +#ifdef HB_NO_VAR + *index = FeatureVariations::NOT_FOUND_INDEX; + return false; +#endif + return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations)) + .find_index (coords, num_coords, index); + } const Feature& get_feature_variation (unsigned int feature_index, unsigned int variations_index) const { +#ifndef HB_NO_VAR if (FeatureVariations::NOT_FOUND_INDEX != variations_index && version.to_int () >= 0x00010001u) { @@ -2674,32 +3252,90 @@ struct GSUBGPOS if (feature) return *feature; } +#endif return get_feature (feature_index); } + void feature_variation_collect_lookups (const hb_set_t *feature_indexes, + hb_set_t *lookup_indexes /* OUT */) const + { +#ifndef HB_NO_VAR + if (version.to_int () >= 0x00010001u) + (this+featureVars).collect_lookups (feature_indexes, lookup_indexes); +#endif + } + template - bool subset (hb_subset_context_t *c) const + void closure_lookups (hb_face_t *face, + const hb_set_t *glyphs, + hb_set_t *lookup_indexes /* IN/OUT */) const { - TRACE_SUBSET (this); - struct GSUBGPOS *out = c->serializer->embed (*this); - if (unlikely (!out)) return_trace (false); + hb_set_t visited_lookups, inactive_lookups; + OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups); - out->scriptList.serialize_subset (c, this+scriptList, out); - out->featureList.serialize_subset (c, this+featureList, out); + for (unsigned lookup_index : + hb_iter (lookup_indexes)) + reinterpret_cast (get_lookup (lookup_index)).closure_lookups (&c, lookup_index); - typedef OffsetListOf TLookupList; - /* TODO Use intersects() to count how many subtables survive? */ - CastR > (out->lookupList) - .serialize_subset (c, - this+CastR > (lookupList), - out); + hb_set_union (lookup_indexes, &visited_lookups); + hb_set_subtract (lookup_indexes, &inactive_lookups); + } + + template + bool subset (hb_subset_layout_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->subset_context->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + typedef LookupOffsetList TLookupList; + reinterpret_cast &> (out->lookupList) + .serialize_subset (c->subset_context, + reinterpret_cast &> (lookupList), + this, + c); + + reinterpret_cast &> (out->featureList) + .serialize_subset (c->subset_context, + reinterpret_cast &> (featureList), + this, + c); + + out->scriptList.serialize_subset (c->subset_context, + scriptList, + this, + c); + +#ifndef HB_NO_VAR if (version.to_int () >= 0x00010001u) - out->featureVars.serialize_subset (c, this+featureVars, out); + { + bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c); + if (!ret) + { + out->version.major = 1; + out->version.minor = 0; + } + } +#endif return_trace (true); } + void closure_features (const hb_map_t *lookup_indexes, /* IN */ + hb_set_t *feature_indexes /* OUT */) const + { + unsigned int feature_count = hb_min (get_feature_count (), (unsigned) HB_MAX_FEATURES); + for (unsigned i = 0; i < feature_count; i++) + { + const Feature& f = get_feature (i); + if ((!f.featureParams.is_null ()) || f.intersects_lookup_indexes (lookup_indexes)) + feature_indexes->add (i); + } +#ifndef HB_NO_VAR + if (version.to_int () >= 0x00010001u) + (this+featureVars).closure_features (lookup_indexes, feature_indexes); +#endif + } + unsigned int get_size () const { return min_size + @@ -2711,12 +3347,19 @@ struct GSUBGPOS { TRACE_SANITIZE (this); typedef OffsetListOf TLookupList; - return_trace (version.sanitize (c) && - likely (version.major == 1) && - scriptList.sanitize (c, this) && - featureList.sanitize (c, this) && - CastR > (lookupList).sanitize (c, this) && - (version.to_int () < 0x00010001u || featureVars.sanitize (c, this))); + if (unlikely (!(version.sanitize (c) && + likely (version.major == 1) && + scriptList.sanitize (c, this) && + featureList.sanitize (c, this) && + reinterpret_cast &> (lookupList).sanitize (c, this)))) + return_trace (false); + +#ifndef HB_NO_VAR + if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this)))) + return_trace (false); +#endif + + return_trace (true); } template @@ -2724,8 +3367,8 @@ struct GSUBGPOS { void init (hb_face_t *face) { - this->table = hb_sanitize_context_t().reference_table (face); - if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face))) + this->table = hb_sanitize_context_t ().reference_table (face); + if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face))) { hb_blob_destroy (this->table.get_blob ()); this->table = hb_blob_get_empty (); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh index 7a543b0aa40..f8cd27f9221 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-jstf-table.hh @@ -136,7 +136,7 @@ struct JstfLangSys : OffsetListOf * ExtenderGlyphs -- Extender Glyph Table */ -typedef SortedArrayOf ExtenderGlyphs; +typedef SortedArrayOf ExtenderGlyphs; /* diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc index a8e579b4472..c326120628b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.cc @@ -28,6 +28,14 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_LAYOUT + +#ifdef HB_NO_OT_TAG +#error "Cannot compile hb-ot-layout.cc with HB_NO_OT_TAG." +#endif + #include "hb-open-type.hh" #include "hb-ot-layout.hh" #include "hb-ot-face.hh" @@ -35,7 +43,6 @@ #include "hb-map.hh" #include "hb-ot-kern-table.hh" -#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" @@ -44,9 +51,8 @@ #include "hb-ot-name-table.hh" #include "hb-ot-os2-table.hh" -#include "hb-aat-layout-lcar-table.hh" #include "hb-aat-layout-morx-table.hh" - +#include "hb-aat-layout-opbd-table.hh" // Just so we compile it; unused otherwise. /** * SECTION:hb-ot-layout @@ -62,18 +68,53 @@ * kern */ +#ifndef HB_NO_OT_KERN +/** + * hb_ot_layout_has_kerning: + * @face: The #hb_face_t to work on + * + * Tests whether a face includes any kerning data in the 'kern' table. + * Does NOT test for kerning lookups in the GPOS table. + * + * Return value: true if data found, false otherwise + * + **/ bool hb_ot_layout_has_kerning (hb_face_t *face) { return face->table.kern->has_data (); } +/** + * hb_ot_layout_has_machine_kerning: + * @face: The #hb_face_t to work on + * + * Tests whether a face includes any state-machine kerning in the 'kern' table. + * Does NOT examine the GPOS table. + * + * Return value: true if data found, false otherwise + * + **/ bool hb_ot_layout_has_machine_kerning (hb_face_t *face) { return face->table.kern->has_state_machine (); } +/** + * hb_ot_layout_has_cross_kerning: + * @face: The #hb_face_t to work on + * + * Tests whether a face has any cross-stream kerning (i.e., kerns + * that make adjustments perpendicular to the direction of the text + * flow: Y adjustments in horizontal text or X adjustments in + * vertical text) in the 'kern' table. + * + * Does NOT examine the GPOS table. + * + * Return value: true is data found, false otherwise + * + **/ bool hb_ot_layout_has_cross_kerning (hb_face_t *face) { @@ -92,6 +133,7 @@ hb_ot_layout_kern (const hb_ot_shape_plan_t *plan, kern.apply (&c); } +#endif /* @@ -99,10 +141,13 @@ hb_ot_layout_kern (const hb_ot_shape_plan_t *plan, */ bool -OT::GDEF::is_blacklisted (hb_blob_t *blob, +OT::GDEF::is_blocklisted (hb_blob_t *blob, hb_face_t *face) const { - /* The ugly business of blacklisting individual fonts' tables happen here! +#ifdef HB_NO_OT_LAYOUT_BLACKLIST + return false; +#endif + /* The ugly business of blocklisting individual fonts' tables happen here! * See this thread for why we finally had to bend in and do this: * https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html * @@ -119,84 +164,82 @@ OT::GDEF::is_blacklisted (hb_blob_t *blob, * https://bugzilla.mozilla.org/show_bug.cgi?id=1279693 * https://bugzilla.mozilla.org/show_bug.cgi?id=1279875 */ -#define ENCODE(x,y,z) (((uint64_t) (x) << 48) | ((uint64_t) (y) << 24) | (uint64_t) (z)) - switch ENCODE(blob->length, - face->table.GSUB->table.get_length (), - face->table.GPOS->table.get_length ()) + switch HB_CODEPOINT_ENCODE3(blob->length, + face->table.GSUB->table.get_length (), + face->table.GPOS->table.get_length ()) { /* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */ - case ENCODE (442, 2874, 42038): + case HB_CODEPOINT_ENCODE3 (442, 2874, 42038): /* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */ - case ENCODE (430, 2874, 40662): + case HB_CODEPOINT_ENCODE3 (430, 2874, 40662): /* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */ - case ENCODE (442, 2874, 39116): + case HB_CODEPOINT_ENCODE3 (442, 2874, 39116): /* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */ - case ENCODE (430, 2874, 39374): + case HB_CODEPOINT_ENCODE3 (430, 2874, 39374): /* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */ - case ENCODE (490, 3046, 41638): + case HB_CODEPOINT_ENCODE3 (490, 3046, 41638): /* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */ - case ENCODE (478, 3046, 41902): + case HB_CODEPOINT_ENCODE3 (478, 3046, 41902): /* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */ - case ENCODE (898, 12554, 46470): + case HB_CODEPOINT_ENCODE3 (898, 12554, 46470): /* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */ - case ENCODE (910, 12566, 47732): + case HB_CODEPOINT_ENCODE3 (910, 12566, 47732): /* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */ - case ENCODE (928, 23298, 59332): + case HB_CODEPOINT_ENCODE3 (928, 23298, 59332): /* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */ - case ENCODE (940, 23310, 60732): + case HB_CODEPOINT_ENCODE3 (940, 23310, 60732): /* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ - case ENCODE (964, 23836, 60072): + case HB_CODEPOINT_ENCODE3 (964, 23836, 60072): /* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ - case ENCODE (976, 23832, 61456): + case HB_CODEPOINT_ENCODE3 (976, 23832, 61456): /* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */ - case ENCODE (994, 24474, 60336): + case HB_CODEPOINT_ENCODE3 (994, 24474, 60336): /* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */ - case ENCODE (1006, 24470, 61740): + case HB_CODEPOINT_ENCODE3 (1006, 24470, 61740): /* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ - case ENCODE (1006, 24576, 61346): + case HB_CODEPOINT_ENCODE3 (1006, 24576, 61346): /* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */ - case ENCODE (1018, 24572, 62828): + case HB_CODEPOINT_ENCODE3 (1018, 24572, 62828): /* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */ - case ENCODE (1006, 24576, 61352): + case HB_CODEPOINT_ENCODE3 (1006, 24576, 61352): /* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */ - case ENCODE (1018, 24572, 62834): + case HB_CODEPOINT_ENCODE3 (1018, 24572, 62834): /* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */ - case ENCODE (832, 7324, 47162): + case HB_CODEPOINT_ENCODE3 (832, 7324, 47162): /* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */ - case ENCODE (844, 7302, 45474): + case HB_CODEPOINT_ENCODE3 (844, 7302, 45474): /* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */ - case ENCODE (180, 13054, 7254): + case HB_CODEPOINT_ENCODE3 (180, 13054, 7254): /* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */ - case ENCODE (192, 12638, 7254): + case HB_CODEPOINT_ENCODE3 (192, 12638, 7254): /* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */ - case ENCODE (192, 12690, 7254): + case HB_CODEPOINT_ENCODE3 (192, 12690, 7254): /* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */ /* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */ - case ENCODE (188, 248, 3852): + case HB_CODEPOINT_ENCODE3 (188, 248, 3852): /* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */ /* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */ - case ENCODE (188, 264, 3426): + case HB_CODEPOINT_ENCODE3 (188, 264, 3426): /* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */ - case ENCODE (1058, 47032, 11818): + case HB_CODEPOINT_ENCODE3 (1058, 47032, 11818): /* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/ - case ENCODE (1046, 47030, 12600): + case HB_CODEPOINT_ENCODE3 (1046, 47030, 12600): /* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */ - case ENCODE (1058, 71796, 16770): + case HB_CODEPOINT_ENCODE3 (1058, 71796, 16770): /* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */ - case ENCODE (1046, 71790, 17862): + case HB_CODEPOINT_ENCODE3 (1046, 71790, 17862): /* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */ - case ENCODE (1046, 71788, 17112): + case HB_CODEPOINT_ENCODE3 (1046, 71788, 17112): /* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */ - case ENCODE (1058, 71794, 17514): + case HB_CODEPOINT_ENCODE3 (1058, 71794, 17514): /* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */ - case ENCODE (1330, 109904, 57938): + case HB_CODEPOINT_ENCODE3 (1330, 109904, 57938): /* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */ - case ENCODE (1330, 109904, 58972): + case HB_CODEPOINT_ENCODE3 (1330, 109904, 58972): /* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf * "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */ - case ENCODE (1004, 59092, 14836): + case HB_CODEPOINT_ENCODE3 (1004, 59092, 14836): return true; -#undef ENCODE } return false; } @@ -219,6 +262,15 @@ _hb_ot_layout_set_glyph_props (hb_font_t *font, /* Public API */ +/** + * hb_ot_layout_has_glyph_classes: + * @face: #hb_face_t to work upon + * + * Tests whether a face has any glyph classes defined in its GDEF table. + * + * Return value: true if data found, false otherwise + * + **/ hb_bool_t hb_ot_layout_has_glyph_classes (hb_face_t *face) { @@ -227,6 +279,13 @@ hb_ot_layout_has_glyph_classes (hb_face_t *face) /** * hb_ot_layout_get_glyph_class: + * @face: The #hb_face_t to work on + * @glyph: The #hb_codepoint_t code point to query + * + * Fetches the GDEF class of the requested glyph in the specified face. + * + * Return value: The #hb_ot_layout_glyph_class_t glyph class of the given code + * point in the GDEF table of the face. * * Since: 0.9.7 **/ @@ -239,6 +298,13 @@ hb_ot_layout_get_glyph_class (hb_face_t *face, /** * hb_ot_layout_get_glyphs_in_class: + * @face: The #hb_face_t to work on + * @klass: The #hb_ot_layout_glyph_class_t GDEF class to retrieve + * @glyphs: (out): The #hb_set_t set of all glyphs belonging to the requested + * class. + * + * Retrieves the set of all glyphs from the face that belong to the requested + * glyph class in the face's GDEF table. * * Since: 0.9.7 **/ @@ -250,6 +316,22 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face, return face->table.GDEF->table->get_glyphs_in_class (klass, glyphs); } +#ifndef HB_NO_LAYOUT_UNUSED +/** + * hb_ot_layout_get_attach_points: + * @face: The #hb_face_t to work on + * @glyph: The #hb_codepoint_t code point to query + * @start_offset: offset of the first attachment point to retrieve + * @point_count: (inout) (allow-none): Input = the maximum number of attachment points to return; + * Output = the actual number of attachment points returned (may be zero) + * @point_array: (out) (array length=point_count): The array of attachment points found for the query + * + * Fetches a list of all attachment points for the specified glyph in the GDEF + * table of the face. The list returned will begin at the offset provided. + * + * Useful if the client program wishes to cache the list. + * + **/ unsigned int hb_ot_layout_get_attach_points (hb_face_t *face, hb_codepoint_t glyph, @@ -262,7 +344,20 @@ hb_ot_layout_get_attach_points (hb_face_t *face, point_count, point_array); } - +/** + * hb_ot_layout_get_ligature_carets: + * @font: The #hb_font_t to work on + * @direction: The #hb_direction_t text direction to use + * @glyph: The #hb_codepoint_t code point to query + * @start_offset: offset of the first caret position to retrieve + * @caret_count: (inout) (allow-none): Input = the maximum number of caret positions to return; + * Output = the actual number of caret positions returned (may be zero) + * @caret_array: (out) (array length=caret_count): The array of caret positions found for the query + * + * Fetches a list of the caret positions defined for a ligature glyph in the GDEF + * table of the font. The list returned will begin at the offset provided. + * + **/ unsigned int hb_ot_layout_get_ligature_carets (hb_font_t *font, hb_direction_t direction, @@ -271,16 +366,9 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font, unsigned int *caret_count /* IN/OUT */, hb_position_t *caret_array /* OUT */) { - unsigned int result_caret_count = 0; - unsigned int result = font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, &result_caret_count, caret_array); - if (result) - { - if (caret_count) *caret_count = result_caret_count; - } - else - result = font->face->table.lcar->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); - return result; + return font->face->table.GDEF->table->get_lig_carets (font, direction, glyph, start_offset, caret_count, caret_array); } +#endif /* @@ -288,34 +376,22 @@ hb_ot_layout_get_ligature_carets (hb_font_t *font, */ bool -OT::GSUB::is_blacklisted (hb_blob_t *blob HB_UNUSED, +OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED, hb_face_t *face) const { - /* Mac OS X prefers morx over GSUB. It also ships with various Indic fonts, - * all by 'MUTF' foundry (Tamil MN, Tamil Sangam MN, etc.), that have broken - * GSUB/GPOS tables. Some have GSUB with zero scripts, those are ignored by - * our morx/GSUB preference code. But if GSUB has non-zero scripts, we tend - * to prefer it over morx because we want to be consistent with other OpenType - * shapers. - * - * To work around broken Indic Mac system fonts, we ignore GSUB table if - * OS/2 VendorId is 'MUTF' and font has morx table as well. - * - * https://github.com/harfbuzz/harfbuzz/issues/1410 - * https://github.com/harfbuzz/harfbuzz/issues/1348 - * https://github.com/harfbuzz/harfbuzz/issues/1391 - */ - if (unlikely (face->table.OS2->achVendID == HB_TAG ('M','U','T','F') && - face->table.morx->has_data ())) - return true; - +#ifdef HB_NO_OT_LAYOUT_BLACKLIST + return false; +#endif return false; } bool -OT::GPOS::is_blacklisted (hb_blob_t *blob HB_UNUSED, +OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED, hb_face_t *face HB_UNUSED) const { +#ifdef HB_NO_OT_LAYOUT_BLACKLIST + return false; +#endif return false; } @@ -326,11 +402,24 @@ get_gsubgpos_table (hb_face_t *face, switch (table_tag) { case HB_OT_TAG_GSUB: return *face->table.GSUB->table; case HB_OT_TAG_GPOS: return *face->table.GPOS->table; - default: return Null(OT::GSUBGPOS); + default: return Null (OT::GSUBGPOS); } } +/** + * hb_ot_layout_table_get_script_tags: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @start_offset: offset of the first script tag to retrieve + * @script_count: (inout) (allow-none): Input = the maximum number of script tags to return; + * Output = the actual number of script tags returned (may be zero) + * @script_tags: (out) (array length=script_count): The array of #hb_tag_t script tags found for the query + * + * Fetches a list of all scripts enumerated in the specified face's GSUB table + * or GPOS table. The list returned will begin at the offset provided. + * + **/ unsigned int hb_ot_layout_table_get_script_tags (hb_face_t *face, hb_tag_t table_tag, @@ -345,11 +434,24 @@ hb_ot_layout_table_get_script_tags (hb_face_t *face, #define HB_OT_TAG_LATIN_SCRIPT HB_TAG ('l', 'a', 't', 'n') +/** + * hb_ot_layout_table_find_script: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_tag: #hb_tag_t of the script tag requested + * @script_index: (out): The index of the requested script tag + * + * Fetches the index if a given script tag in the specified face's GSUB table + * or GPOS table. + * + * Return value: true if the script is found, false otherwise + * + **/ hb_bool_t hb_ot_layout_table_find_script (hb_face_t *face, hb_tag_t table_tag, hb_tag_t script_tag, - unsigned int *script_index) + unsigned int *script_index /* OUT */) { static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_SCRIPT_INDEX), ""); const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); @@ -375,20 +477,38 @@ hb_ot_layout_table_find_script (hb_face_t *face, return false; } +#ifndef HB_DISABLE_DEPRECATED +/** + * hb_ot_layout_table_choose_script: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_tags: Array of #hb_tag_t script tags + * @script_index: (out): The index of the requested script tag + * @chosen_script: (out): #hb_tag_t of the script tag requested + * + * Deprecated since 2.0.0 + **/ hb_bool_t hb_ot_layout_table_choose_script (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *script_tags, - unsigned int *script_index, - hb_tag_t *chosen_script) + unsigned int *script_index /* OUT */, + hb_tag_t *chosen_script /* OUT */) { const hb_tag_t *t; for (t = script_tags; *t; t++); return hb_ot_layout_table_select_script (face, table_tag, t - script_tags, script_tags, script_index, chosen_script); } +#endif /** * hb_ot_layout_table_select_script: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_count: Number of script tags in the array + * @script_tags: Array of #hb_tag_t script tags + * @script_index: (out): The index of the requested script + * @chosen_script: (out): #hb_tag_t of the requested script * * Since: 2.0.0 **/ @@ -442,6 +562,19 @@ hb_ot_layout_table_select_script (hb_face_t *face, return false; } + +/** + * hb_ot_layout_table_get_feature_tags: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @start_offset: offset of the first feature tag to retrieve + * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return; + * Output = the actual number of feature tags returned (may be zero) + * @feature_tags: (out) (array length=feature_count): Array of feature tags found in the table + * + * Fetches a list of all feature tags in the given face's GSUB or GPOS table. + * + **/ unsigned int hb_ot_layout_table_get_feature_tags (hb_face_t *face, hb_tag_t table_tag, @@ -454,11 +587,24 @@ hb_ot_layout_table_get_feature_tags (hb_face_t *face, return g.get_feature_tags (start_offset, feature_count, feature_tags); } + +/** + * hb_ot_layout_table_find_feature: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @feature_tag: The #hb_tag_t og the requested feature tag + * @feature_index: (out): The index of the requested feature + * + * Fetches the index for a given feature tag in the specified face's GSUB table + * or GPOS table. + * + * Return value: true if the feature is found, false otherwise + **/ bool hb_ot_layout_table_find_feature (hb_face_t *face, hb_tag_t table_tag, hb_tag_t feature_tag, - unsigned int *feature_index) + unsigned int *feature_index /* OUT */) { static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), ""); const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); @@ -477,6 +623,20 @@ hb_ot_layout_table_find_feature (hb_face_t *face, } +/** + * hb_ot_layout_script_get_language_tags: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_index: The index of the requested script tag + * @start_offset: offset of the first language tag to retrieve + * @language_count: (inout) (allow-none): Input = the maximum number of language tags to return; + * Output = the actual number of language tags returned (may be zero) + * @language_tags: (out) (array length=language_count): Array of language tags found in the table + * + * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath + * the specified script index. The list returned will begin at the offset provided. + * + **/ unsigned int hb_ot_layout_script_get_language_tags (hb_face_t *face, hb_tag_t table_tag, @@ -490,6 +650,24 @@ hb_ot_layout_script_get_language_tags (hb_face_t *face, return s.get_lang_sys_tags (start_offset, language_count, language_tags); } + +#ifndef HB_DISABLE_DEPRECATED +/** + * hb_ot_layout_script_find_language: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_index: The index of the requested script tag + * @language_tag: The #hb_tag_t of the requested language + * @language_index: The index of the requested language + * + * Fetches the index of a given language tag in the specified face's GSUB table + * or GPOS table, underneath the specified script tag. + * + * Return value: true if the language tag is found, false otherwise + * + * Since: ?? + * Deprecated: ?? + **/ hb_bool_t hb_ot_layout_script_find_language (hb_face_t *face, hb_tag_t table_tag, @@ -504,9 +682,22 @@ hb_ot_layout_script_find_language (hb_face_t *face, &language_tag, language_index); } +#endif + /** * hb_ot_layout_script_select_language: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_index: The index of the requested script tag + * @language_count: The number of languages in the specified script + * @language_tags: The array of language tags + * @language_index: (out): The index of the requested language + * + * Fetches the index of a given language tag in the specified face's GSUB table + * or GPOS table, underneath the specified script index. + * + * Return value: true if the language tag is found, false otherwise * * Since: 2.0.0 **/ @@ -536,12 +727,27 @@ hb_ot_layout_script_select_language (hb_face_t *face, return false; } + +/** + * hb_ot_layout_language_get_required_feature_index: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_index: The index of the requested script tag + * @language_index: The index of the requested language tag + * @feature_index: (out): The index of the requested feature + * + * Fetches the index of a requested feature in the given face's GSUB or GPOS table, + * underneath the specified script and language. + * + * Return value: true if the feature is found, false otherwise + * + **/ hb_bool_t hb_ot_layout_language_get_required_feature_index (hb_face_t *face, hb_tag_t table_tag, unsigned int script_index, unsigned int language_index, - unsigned int *feature_index) + unsigned int *feature_index /* OUT */) { return hb_ot_layout_language_get_required_feature (face, table_tag, @@ -551,8 +757,20 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face, nullptr); } + /** * hb_ot_layout_language_get_required_feature: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_index: The index of the requested script tag + * @language_index: The index of the requested language tag + * @feature_index: (out): The index of the requested feature + * @feature_tag: (out): The #hb_tag_t of the requested feature + * + * Fetches the tag of a requested feature index in the given face's GSUB or GPOS table, + * underneath the specified script and language. + * + * Return value: true if the feature is found, false otherwise * * Since: 0.9.30 **/ @@ -561,8 +779,8 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face, hb_tag_t table_tag, unsigned int script_index, unsigned int language_index, - unsigned int *feature_index, - hb_tag_t *feature_tag) + unsigned int *feature_index /* OUT */, + hb_tag_t *feature_tag /* OUT */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index); @@ -574,6 +792,22 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face, return l.has_required_feature (); } + +/** + * hb_ot_layout_language_get_feature_indexes: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_index: The index of the requested script tag + * @language_index: The index of the requested language tag + * @start_offset: offset of the first feature tag to retrieve + * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return; + * Output: the actual number of feature tags returned (may be zero) + * @feature_indexes: (out) (array length=feature_count): The array of feature indexes found for the query + * + * Fetches a list of all features in the specified face's GSUB table + * or GPOS table, underneath the specified script and language. The list + * returned will begin at the offset provided. + **/ unsigned int hb_ot_layout_language_get_feature_indexes (hb_face_t *face, hb_tag_t table_tag, @@ -589,6 +823,23 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face, return l.get_feature_indexes (start_offset, feature_count, feature_indexes); } + +/** + * hb_ot_layout_language_get_feature_tags: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_index: The index of the requested script tag + * @language_index: The index of the requested language tag + * @start_offset: offset of the first feature tag to retrieve + * @feature_count: (inout) (allow-none): Input = the maximum number of feature tags to return; + * Output = the actual number of feature tags returned (may be zero) + * @feature_tags: (out) (array length=feature_count): The array of #hb_tag_t feature tags found for the query + * + * Fetches a list of all features in the specified face's GSUB table + * or GPOS table, underneath the specified script and language. The list + * returned will begin at the offset provided. + * + **/ unsigned int hb_ot_layout_language_get_feature_tags (hb_face_t *face, hb_tag_t table_tag, @@ -614,13 +865,28 @@ hb_ot_layout_language_get_feature_tags (hb_face_t *face, } +/** + * hb_ot_layout_language_find_feature: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @script_index: The index of the requested script tag + * @language_index: The index of the requested language tag + * @feature_tag: #hb_tag_t of the feature tag requested + * @feature_index: (out): The index of the requested feature + * + * Fetches the index of a given feature tag in the specified face's GSUB table + * or GPOS table, underneath the specified script and language. + * + * Return value: true if the feature is found, false otherwise + * + **/ hb_bool_t hb_ot_layout_language_find_feature (hb_face_t *face, hb_tag_t table_tag, unsigned int script_index, unsigned int language_index, hb_tag_t feature_tag, - unsigned int *feature_index) + unsigned int *feature_index /* OUT */) { static_assert ((OT::Index::NOT_FOUND_INDEX == HB_OT_LAYOUT_NO_FEATURE_INDEX), ""); const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); @@ -640,8 +906,20 @@ hb_ot_layout_language_find_feature (hb_face_t *face, return false; } + /** * hb_ot_layout_feature_get_lookups: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @feature_index: The index of the requested feature + * @start_offset: offset of the first lookup to retrieve + * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return; + * Output = the actual number of lookups returned (may be zero) + * @lookup_indexes: (out) (array length=lookup_count): The array of lookup indexes found for the query + * + * Fetches a list of all lookups enumerated for the specified feature, in + * the specified face's GSUB table or GPOS table. The list returned will + * begin at the offset provided. * * Since: 0.9.7 **/ @@ -662,8 +940,14 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face, lookup_indexes); } + /** * hb_ot_layout_table_get_lookup_count: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * + * Fetches the total number of lookups enumerated in the specified + * face's GSUB table or GPOS table. * * Since: 0.9.22 **/ @@ -677,12 +961,12 @@ hb_ot_layout_table_get_lookup_count (hb_face_t *face, struct hb_collect_features_context_t { - hb_collect_features_context_t (hb_face_t *face, - hb_tag_t table_tag, - hb_set_t *feature_indexes_) + hb_collect_features_context_t (hb_face_t *face, + hb_tag_t table_tag, + hb_set_t *feature_indexes_) : g (get_gsubgpos_table (face, table_tag)), feature_indexes (feature_indexes_), - script_count(0),langsys_count(0) {} + script_count (0),langsys_count (0), feature_index_count (0) {} bool visited (const OT::Script &s) { @@ -711,6 +995,12 @@ struct hb_collect_features_context_t return visited (l, visited_langsys); } + bool visited_feature_indices (unsigned count) + { + feature_index_count += count; + return feature_index_count > HB_MAX_FEATURE_INDICES; + } + private: template bool visited (const T &p, hb_set_t &visited_set) @@ -732,6 +1022,7 @@ struct hb_collect_features_context_t hb_set_t visited_langsys; unsigned int script_count; unsigned int langsys_count; + unsigned int feature_index_count; }; static void @@ -744,10 +1035,11 @@ langsys_collect_features (hb_collect_features_context_t *c, if (!features) { /* All features. */ - if (l.has_required_feature ()) + if (l.has_required_feature () && !c->visited_feature_indices (1)) c->feature_indexes->add (l.get_required_feature_index ()); - l.add_feature_indexes_to (c->feature_indexes); + if (!c->visited_feature_indices (l.featureIndex.len)) + l.add_feature_indexes_to (c->feature_indexes); } else { @@ -805,8 +1097,21 @@ script_collect_features (hb_collect_features_context_t *c, } } + /** * hb_ot_layout_collect_features: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @scripts: The array of scripts to collect features for + * @languages: The array of languages to collect features for + * @features: The array of features to collect + * @feature_indexes: (out): The array of feature indexes found for the query + * + * Fetches a list of all feature indexes in the specified face's GSUB table + * or GPOS table, underneath the specified scripts, languages, and features. + * If no list of scripts is provided, all scripts will be queried. If no list + * of languages is provided, all languages will be queried. If no list of + * features is provided, all features will be queried. * * Since: 1.8.5 **/ @@ -843,8 +1148,21 @@ hb_ot_layout_collect_features (hb_face_t *face, } } + /** * hb_ot_layout_collect_lookups: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @scripts: The array of scripts to collect lookups for + * @languages: The array of languages to collect lookups for + * @features: The array of features to collect lookups for + * @lookup_indexes: (out): The array of lookup indexes found for the query + * + * Fetches a list of all feature-lookup indexes in the specified face's GSUB + * table or GPOS table, underneath the specified scripts, languages, and + * features. If no list of scripts is provided, all scripts will be queried. + * If no list of languages is provided, all languages will be queried. If no + * list of features is provided, all features will be queried. * * Since: 0.9.8 **/ @@ -864,10 +1182,24 @@ hb_ot_layout_collect_lookups (hb_face_t *face, for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID; hb_set_next (&feature_indexes, &feature_index);) g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes); + + g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes); } + +#ifndef HB_NO_LAYOUT_COLLECT_GLYPHS /** * hb_ot_layout_lookup_collect_glyphs: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @lookup_index: The index of the feature lookup to query + * @glyphs_before: (out): Array of glyphs preceding the substitution range + * @glyphs_input: (out): Array of input glyphs that would be substituted by the lookup + * @glyphs_after: (out): Array of glyphs following the substitution range + * @glyphs_output: (out): Array of glyphs that would be the substitued output of the lookup + * + * Fetches a list of all glyphs affected by the specified lookup in the + * specified face's GSUB table or GPOS table. * * Since: 0.9.7 **/ @@ -902,10 +1234,24 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, } } } +#endif /* Variations support */ + +/** + * hb_ot_layout_table_find_feature_variations: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @coords: The variation coordinates to query + * @num_coords: The number of variation coorinates + * @variations_index: (out): The array of feature variations found for the query + * + * Fetches a list of feature variations in the specified face's GSUB table + * or GPOS table, at the specified variation coordinates. + * + **/ hb_bool_t hb_ot_layout_table_find_feature_variations (hb_face_t *face, hb_tag_t table_tag, @@ -918,6 +1264,23 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face, return g.find_variations_index (coords, num_coords, variations_index); } + +/** + * hb_ot_layout_feature_with_variations_get_lookups: + * @face: #hb_face_t to work upon + * @table_tag: HB_OT_TAG_GSUB or HB_OT_TAG_GPOS + * @feature_index: The index of the feature to query + * @variations_index: The index of the feature variation to query + * @start_offset: offset of the first lookup to retrieve + * @lookup_count: (inout) (allow-none): Input = the maximum number of lookups to return; + * Output = the actual number of lookups returned (may be zero) + * @lookup_indexes: (out) (array length=lookup_count): The array of lookups found for the query + * + * Fetches a list of all lookups enumerated for the specified feature, in + * the specified face's GSUB table or GPOS table, enabled at the specified + * variations index. The list returned will begin at the offset provided. + * + **/ unsigned int hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face, hb_tag_t table_tag, @@ -940,14 +1303,35 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face, * OT::GSUB */ + +/** + * hb_ot_layout_has_substitution: + * @face: #hb_face_t to work upon + * + * Tests whether the specified face includes any GSUB substitutions. + * + * Return value: true if data found, false otherwise + * + **/ hb_bool_t hb_ot_layout_has_substitution (hb_face_t *face) { return face->table.GSUB->table->has_data (); } + /** * hb_ot_layout_lookup_would_substitute: + * @face: #hb_face_t to work upon + * @lookup_index: The index of the lookup to query + * @glyphs: The sequence of glyphs to query for substitution + * @glyphs_length: The length of the glyph sequence + * @zero_context: #hb_bool_t indicating whether substitutions should be context-free + * + * Tests whether a specified lookup in the specified face would + * trigger a substitution on the given glyph sequence. + * + * Return value: true if a substitution would be triggered, false otherwise * * Since: 0.9.7 **/ @@ -957,33 +1341,29 @@ hb_ot_layout_lookup_would_substitute (hb_face_t *face, const hb_codepoint_t *glyphs, unsigned int glyphs_length, hb_bool_t zero_context) -{ - return hb_ot_layout_lookup_would_substitute_fast (face, - lookup_index, - glyphs, glyphs_length, - zero_context); -} - -bool -hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, - unsigned int lookup_index, - const hb_codepoint_t *glyphs, - unsigned int glyphs_length, - bool zero_context) { if (unlikely (lookup_index >= face->table.GSUB->lookup_count)) return false; OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context); const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); - return l.would_apply (&c, &face->table.GSUB->accels[lookup_index]); } + +/** + * hb_ot_layout_substitute_start: + * @font: #hb_font_t to use + * @buffer: #hb_buffer_t buffer to work upon + * + * Called before substitution lookups are performed, to ensure that glyph + * class and other properties are set on the glyphs in the buffer. + * + **/ void hb_ot_layout_substitute_start (hb_font_t *font, hb_buffer_t *buffer) { -_hb_ot_layout_set_glyph_props (font, buffer); + _hb_ot_layout_set_glyph_props (font, buffer); } void @@ -1038,13 +1418,19 @@ hb_ot_layout_delete_glyphs_inplace (hb_buffer_t *buffer, /** * hb_ot_layout_lookup_substitute_closure: + * @face: #hb_face_t to work upon + * @lookup_index: index of the feature lookup to query + * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookup + * + * Compute the transitive closure of glyphs needed for a + * specified lookup. * * Since: 0.9.7 **/ void hb_ot_layout_lookup_substitute_closure (hb_face_t *face, unsigned int lookup_index, - hb_set_t *glyphs) + hb_set_t *glyphs /* OUT */) { hb_map_t done_lookups; OT::hb_closure_context_t c (face, glyphs, &done_lookups); @@ -1056,6 +1442,9 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face, /** * hb_ot_layout_lookups_substitute_closure: + * @face: #hb_face_t to work upon + * @lookups: The set of lookups to query + * @glyphs: (out): Array of glyphs comprising the transitive closure of the lookups * * Compute the transitive closure of glyphs needed for all of the * provided lookups. @@ -1065,7 +1454,7 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face, void hb_ot_layout_lookups_substitute_closure (hb_face_t *face, const hb_set_t *lookups, - hb_set_t *glyphs) + hb_set_t *glyphs /* OUT */) { hb_map_t done_lookups; OT::hb_closure_context_t c (face, glyphs, &done_lookups); @@ -1076,7 +1465,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, do { glyphs_length = glyphs->get_population (); - if (lookups != nullptr) + if (lookups) { for (hb_codepoint_t lookup_index = HB_SET_VALUE_INVALID; hb_set_next (lookups, &lookup_index);) gsub.get_lookup (lookup_index).closure (&c, lookup_index); @@ -1094,32 +1483,85 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, * OT::GPOS */ + +/** + * hb_ot_layout_has_positioning: + * @face: #hb_face_t to work upon + * + * Return value: true if the face has GPOS data, false otherwise + * + **/ hb_bool_t hb_ot_layout_has_positioning (hb_face_t *face) { return face->table.GPOS->table->has_data (); } +/** + * hb_ot_layout_position_start: + * @font: #hb_font_t to use + * @buffer: #hb_buffer_t buffer to work upon + * + * Called before positioning lookups are performed, to ensure that glyph + * attachment types and glyph-attachment chains are set for the glyphs in the buffer. + * + **/ void hb_ot_layout_position_start (hb_font_t *font, hb_buffer_t *buffer) { OT::GPOS::position_start (font, buffer); } + +/** + * hb_ot_layout_position_finish_advances: + * @font: #hb_font_t to use + * @buffer: #hb_buffer_t buffer to work upon + * + * Called after positioning lookups are performed, to finish glyph advances. + * + **/ void hb_ot_layout_position_finish_advances (hb_font_t *font, hb_buffer_t *buffer) { OT::GPOS::position_finish_advances (font, buffer); } +/** + * hb_ot_layout_position_finish_offsets: + * @font: #hb_font_t to use + * @buffer: #hb_buffer_t buffer to work upon + * + * Called after positioning lookups are performed, to finish glyph offsets. + * + **/ void hb_ot_layout_position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) { OT::GPOS::position_finish_offsets (font, buffer); } + +#ifndef HB_NO_LAYOUT_FEATURE_PARAMS /** * hb_ot_layout_get_size_params: + * @face: #hb_face_t to work upon + * @design_size: (out): The design size of the face + * @subfamily_id: (out): The identifier of the face within the font subfamily + * @subfamily_name_id: (out): The ‘name’ table name ID of the face within the font subfamily + * @range_start: (out): The minimum size of the recommended size range for the face + * @range_end: (out): The maximum size of the recommended size range for the face + * + * Fetches optical-size feature data (i.e., the `size` feature from GPOS). Note that + * the subfamily_id and the subfamily name string (accessible via the subfamily_name_id) + * as used here are defined as pertaining only to fonts within a font family that differ + * specifically in their respective size ranges; other ways to differentiate fonts within + * a subfamily are not covered by the `size` feature. + * + * For more information on this distinction, see the [`size` feature documentation]( + * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#tag-size). + * + * Return value: true if data found, false otherwise * * Since: 0.9.10 **/ @@ -1163,7 +1605,6 @@ hb_ot_layout_get_size_params (hb_face_t *face, return false; } - /** * hb_ot_layout_feature_get_name_ids: * @face: #hb_face_t to work upon @@ -1238,24 +1679,20 @@ hb_ot_layout_feature_get_name_ids (hb_face_t *face, if (first_param_id) *first_param_id = HB_OT_NAME_ID_INVALID; return false; } - /** * hb_ot_layout_feature_get_characters: * @face: #hb_face_t to work upon * @table_tag: table tag to query, "GSUB" or "GPOS". * @feature_index: index of feature to query. - * @start_offset: In case the resulting char_count was equal to its input value, there - * is a chance there were more characters on the tag so this API can be - * called with an offset till resulting char_count gets to a number - * lower than input buffer (or consider using just a bigger buffer for - * one shot copying). - * @char_count: (inout) (allow-none): The count of characters for which this feature - * provides glyph variants. (May be zero.) - * @characters: (out caller-allocates) (array length=char_count): A buffer pointer. The Unicode codepoints - * of the characters for which this feature provides glyph variants. - * - * Fetches characters listed by designer under feature parameters for "Character - * Variant" ("cvXX") features. + * @start_offset: offset of the first character to retrieve + * @char_count: (inout) (allow-none): Input = the maximum number of characters to return; + * Output = the actual number of characters returned (may be zero) + * @characters: (out caller-allocates) (array length=char_count): A buffer pointer. + * The Unicode codepoints of the characters for which this feature provides + * glyph variants. + * + * Fetches a list of the characters defined as having a variant under the specified + * "Character Variant" ("cvXX") feature tag. * * Return value: Number of total sample characters in the cvXX feature. * @@ -1270,25 +1707,12 @@ hb_ot_layout_feature_get_characters (hb_face_t *face, hb_codepoint_t *characters /* OUT. May be NULL */) { const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag); - - hb_tag_t feature_tag = g.get_feature_tag (feature_index); - const OT::Feature &f = g.get_feature (feature_index); - - const OT::FeatureParams &feature_params = f.get_feature_params (); - - const OT::FeatureParamsCharacterVariants& cv_params = - feature_params.get_character_variants_params(feature_tag); - - unsigned int len = 0; - if (char_count && characters && start_offset < cv_params.characters.len) - { - len = MIN (cv_params.characters.len - start_offset, *char_count); - for (unsigned int i = 0; i < len; ++i) - characters[i] = cv_params.characters[start_offset + i]; - } - if (char_count) *char_count = len; - return cv_params.characters.len; + return g.get_feature (feature_index) + .get_feature_params () + .get_character_variants_params(g.get_feature_tag (feature_index)) + .get_characters (start_offset, char_count, characters); } +#endif /* @@ -1455,13 +1879,17 @@ inline void hb_ot_map_t::apply (const Proxy &proxy, void hb_ot_map_t::substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const { GSUBProxy proxy (font->face); + if (!buffer->message (font, "start table GSUB")) return; apply (proxy, plan, font, buffer); + (void)buffer->message (font, "end table GSUB"); } void hb_ot_map_t::position (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const { GPOSProxy proxy (font->face); + if (!buffer->message (font, "start table GPOS")) return; apply (proxy, plan, font, buffer); + (void)buffer->message (font, "end table GPOS"); } void @@ -1472,60 +1900,94 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, apply_string (c, lookup, accel); } -#if 0 -static const OT::BASE& _get_base (hb_face_t *face) -{ - return *face->table.BASE; -} - +#ifndef HB_NO_BASE +/** + * hb_ot_layout_get_baseline: + * @font: a font + * @baseline_tag: a baseline tag + * @direction: text direction. + * @script_tag: script tag. + * @language_tag: language tag. + * @coord: (out): baseline value if found. + * + * Fetches a baseline value from the face. + * + * Return value: if found baseline value in the font. + * + * Since: 2.6.0 + **/ hb_bool_t -hb_ot_layout_get_baseline (hb_font_t *font, - hb_ot_layout_baseline_t baseline, - hb_direction_t direction, - hb_tag_t script_tag, - hb_tag_t language_tag, - hb_position_t *coord /* OUT. May be NULL. */) +hb_ot_layout_get_baseline (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *coord /* OUT. May be NULL. */) { - const OT::BASE &base = _get_base (font->face); - bool result = base.get_baseline (font, baseline, direction, script_tag, - language_tag, coord); + bool result = font->face->table.BASE->get_baseline (font, baseline_tag, direction, script_tag, language_tag, coord); - /* TODO: Simulate https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags#ideographic-em-box */ - if (!result && coord) *coord = 0; - - if (coord) *coord = font->em_scale_dir (*coord, direction); + if (result && coord) + *coord = HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_y (*coord) : font->em_scale_x (*coord); return result; } +#endif -/* To be moved to public header */ -/* - * BASE - */ + +struct hb_get_glyph_alternates_dispatch_t : + hb_dispatch_context_t +{ + static return_t default_return_value () { return 0; } + bool stop_sublookup_iteration (return_t r) const { return r; } + + hb_face_t *face; + + hb_get_glyph_alternates_dispatch_t (hb_face_t *face) : + face (face) {} + + private: + template auto + _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN + ( obj.get_glyph_alternates (hb_forward (ds)...) ) + template auto + _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN + ( default_return_value () ) + public: + template auto + dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN + ( _dispatch (obj, hb_prioritize, hb_forward (ds)...) ) +}; /** - * hb_ot_layout_baseline_t: + * hb_ot_layout_lookup_get_glyph_alternates: + * @face: a face. + * @lookup_index: index of the feature lookup to query. + * @glyph: a glyph id. + * @start_offset: starting offset. + * @alternate_count: (inout) (allow-none): Input = the maximum number of alternate glyphs to return; + * Output = the actual number of alternate glyphs returned (may be zero). + * @alternate_glyphs: (out caller-allocates) (array length=alternate_count): A glyphs buffer. + * Alternate glyphs associated with the glyph id. * - * https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags + * Fetches alternates of a glyph from a given GSUB lookup index. * - * Since: DONTREPLACEME - */ -typedef enum { - HB_OT_LAYOUT_BASELINE_HANG = HB_TAG('h','a','n','g'), - HB_OT_LAYOUT_BASELINE_ICFB = HB_TAG('i','c','f','b'), - HB_OT_LAYOUT_BASELINE_ICFT = HB_TAG('i','c','f','t'), - HB_OT_LAYOUT_BASELINE_IDEO = HB_TAG('i','d','e','o'), - HB_OT_LAYOUT_BASELINE_IDTB = HB_TAG('i','d','t','b'), - HB_OT_LAYOUT_BASELINE_MATH = HB_TAG('m','a','t','h'), - HB_OT_LAYOUT_BASELINE_ROMN = HB_TAG('r','o','m','n') -} hb_ot_layout_baseline_t; - -HB_EXTERN hb_bool_t -hb_ot_layout_get_baseline (hb_font_t *font, - hb_ot_layout_baseline_t baseline, - hb_direction_t direction, - hb_tag_t script_tag, - hb_tag_t language_tag, - hb_position_t *coord /* OUT. May be NULL. */); + * Return value: total number of alternates found in the specific lookup index for the given glyph id. + * + * Since: 2.6.8 + **/ +HB_EXTERN unsigned +hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face, + unsigned lookup_index, + hb_codepoint_t glyph, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT. May be NULL. */, + hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) +{ + hb_get_glyph_alternates_dispatch_t c (face); + const OT::SubstLookup &lookup = face->table.GSUB->table->get_lookup (lookup_index); + auto ret = lookup.dispatch (&c, glyph, start_offset, alternate_count, alternate_glyphs); + if (!ret && alternate_count) *alternate_count = 0; + return ret; +} #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h index 0419f603916..cdb1955317c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.h @@ -93,6 +93,17 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag, HB_EXTERN hb_bool_t hb_ot_layout_has_glyph_classes (hb_face_t *face); +/** + * hb_ot_layout_glyph_class_t: + * @HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED: Glyphs not matching the other classifications + * @HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH: Spacing, single characters, capable of accepting marks + * @HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE: Glyphs that represent ligation of multiple characters + * @HB_OT_LAYOUT_GLYPH_CLASS_MARK: Non-spacing, combining glyphs that represent marks + * @HB_OT_LAYOUT_GLYPH_CLASS_COMPONENT: Spacing glyphs that represent part of a single character + * + * The GDEF classes defined for glyphs. + * + **/ typedef enum { HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED = 0, HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH = 1, @@ -110,7 +121,6 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face, hb_ot_layout_glyph_class_t klass, hb_set_t *glyphs /* OUT */); - /* Not that useful. Provides list of attach points for a glyph that a * client may want to cache */ HB_EXTERN unsigned int @@ -150,7 +160,7 @@ HB_EXTERN hb_bool_t hb_ot_layout_table_find_script (hb_face_t *face, hb_tag_t table_tag, hb_tag_t script_tag, - unsigned int *script_index); + unsigned int *script_index /* OUT */); HB_EXTERN hb_bool_t hb_ot_layout_table_select_script (hb_face_t *face, @@ -188,15 +198,15 @@ hb_ot_layout_language_get_required_feature_index (hb_face_t *face, hb_tag_t table_tag, unsigned int script_index, unsigned int language_index, - unsigned int *feature_index); + unsigned int *feature_index /* OUT */); HB_EXTERN hb_bool_t hb_ot_layout_language_get_required_feature (hb_face_t *face, hb_tag_t table_tag, unsigned int script_index, unsigned int language_index, - unsigned int *feature_index, - hb_tag_t *feature_tag); + unsigned int *feature_index /* OUT */, + hb_tag_t *feature_tag /* OUT */); HB_EXTERN unsigned int hb_ot_layout_language_get_feature_indexes (hb_face_t *face, @@ -222,7 +232,7 @@ hb_ot_layout_language_find_feature (hb_face_t *face, unsigned int script_index, unsigned int language_index, hb_tag_t feature_tag, - unsigned int *feature_index); + unsigned int *feature_index /* OUT */); HB_EXTERN unsigned int hb_ot_layout_feature_get_lookups (hb_face_t *face, @@ -313,6 +323,14 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face, HB_EXTERN hb_bool_t hb_ot_layout_has_substitution (hb_face_t *face); +HB_EXTERN unsigned +hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face, + unsigned lookup_index, + hb_codepoint_t glyph, + unsigned start_offset, + unsigned *alternate_count /* IN/OUT */, + hb_codepoint_t *alternate_glyphs /* OUT */); + HB_EXTERN hb_bool_t hb_ot_layout_lookup_would_substitute (hb_face_t *face, unsigned int lookup_index, @@ -391,6 +409,54 @@ hb_ot_layout_feature_get_characters (hb_face_t *face, unsigned int *char_count /* IN/OUT. May be NULL */, hb_codepoint_t *characters /* OUT. May be NULL */); +/* + * BASE + */ + +/** + * hb_ot_layout_baseline_tag_t: + * @HB_OT_LAYOUT_BASELINE_TAG_ROMAN: The baseline used by alphabetic scripts such as Latin, Cyrillic and Greek. + * In vertical writing mode, the alphabetic baseline for characters rotated 90 degrees clockwise. + * (This would not apply to alphabetic characters that remain upright in vertical writing mode, since these + * characters are not rotated.) + * @HB_OT_LAYOUT_BASELINE_TAG_HANGING: The hanging baseline. In horizontal direction, this is the horizontal + * line from which syllables seem, to hang in Tibetan and other similar scripts. In vertical writing mode, + * for Tibetan (or some other similar script) characters rotated 90 degrees clockwise. + * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT: Ideographic character face bottom or left edge, + * if the direction is horizontal or vertical, respectively. + * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: Ideographic character face top or right edge, + * if the direction is horizontal or vertical, respectively. + * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: Ideographic em-box bottom or left edge, + * if the direction is horizontal or vertical, respectively. + * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: Ideographic em-box top or right edge baseline, + * if the direction is horizontal or vertical, respectively. + * @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered. + * In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered. + * + * Baseline tags from https://docs.microsoft.com/en-us/typography/opentype/spec/baselinetags + * + * Since: 2.6.0 + */ +typedef enum { + HB_OT_LAYOUT_BASELINE_TAG_ROMAN = HB_TAG ('r','o','m','n'), + HB_OT_LAYOUT_BASELINE_TAG_HANGING = HB_TAG ('h','a','n','g'), + HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT = HB_TAG ('i','c','f','b'), + HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT = HB_TAG ('i','c','f','t'), + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT = HB_TAG ('i','d','e','o'), + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT = HB_TAG ('i','d','t','p'), + HB_OT_LAYOUT_BASELINE_TAG_MATH = HB_TAG ('m','a','t','h'), + + _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ +} hb_ot_layout_baseline_tag_t; + +HB_EXTERN hb_bool_t +hb_ot_layout_get_baseline (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *coord /* OUT. May be NULL. */); + HB_END_DECLS #endif /* HB_OT_LAYOUT_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh index 9025bc5a8a0..07447f913c8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout.hh @@ -96,13 +96,6 @@ HB_MARK_AS_FLAG_T (hb_ot_layout_glyph_props_flags_t); * GSUB/GPOS */ -HB_INTERNAL bool -hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face, - unsigned int lookup_index, - const hb_codepoint_t *glyphs, - unsigned int glyphs_length, - bool zero_context); - /* Should be called before all the substitute_lookup's are done. */ HB_INTERNAL void @@ -175,6 +168,17 @@ _hb_next_syllable (hb_buffer_t *buffer, unsigned int start) return start; } +static inline void +_hb_clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) +{ + hb_glyph_info_t *info = buffer->info; + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + info[i].syllable() = 0; +} + /* unicode_props */ @@ -215,7 +219,7 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer) unsigned int gen_cat = (unsigned int) unicode->general_category (u); unsigned int props = gen_cat; - if (u >= 0x80) + if (u >= 0x80u) { buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII; @@ -232,10 +236,10 @@ _hb_glyph_info_set_unicode_props (hb_glyph_info_t *info, hb_buffer_t *buffer) * FVSes are GC=Mn, we have use a separate bit to remember them. * Fixes: * https://github.com/harfbuzz/harfbuzz/issues/234 */ - else if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN; + else if (unlikely (hb_in_range (u, 0x180Bu, 0x180Du))) props |= UPROPS_MASK_HIDDEN; /* TAG characters need similar treatment. Fixes: * https://github.com/harfbuzz/harfbuzz/issues/463 */ - else if (unlikely (hb_in_range (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN; + else if (unlikely (hb_in_range (u, 0xE0020u, 0xE007Fu))) props |= UPROPS_MASK_HIDDEN; /* COMBINING GRAPHEME JOINER should not be skipped; at least some times. * https://github.com/harfbuzz/harfbuzz/issues/554 */ else if (unlikely (u == 0x034Fu)) @@ -558,6 +562,17 @@ _hb_glyph_info_clear_substituted (hb_glyph_info_t *info) info->glyph_props() &= ~(HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED); } +static inline void +_hb_clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) +{ + hb_glyph_info_t *info = buffer->info; + unsigned int count = buffer->len; + for (unsigned int i = 0; i < count; i++) + _hb_glyph_info_clear_substituted (&info[i]); +} + /* Allocation / deallocation. */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc index a428b4bdbe3..d256a04ca5a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.cc @@ -26,6 +26,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-map.hh" #include "hb-ot-shape.hh" #include "hb-ot-layout.hh" @@ -34,7 +38,7 @@ void hb_ot_map_t::collect_lookups (unsigned int table_index, hb_set_t *lookups_out) const { for (unsigned int i = 0; i < lookups[table_index].length; i++) - hb_set_add (lookups_out, lookups[table_index][i].index); + lookups_out->add (lookups[table_index][i].index); } @@ -187,13 +191,14 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, feature_infos[j].max_value = feature_infos[i].max_value; feature_infos[j].default_value = feature_infos[i].default_value; } else { - feature_infos[j].flags &= ~F_GLOBAL; - feature_infos[j].max_value = MAX (feature_infos[j].max_value, feature_infos[i].max_value); + if (feature_infos[j].flags & F_GLOBAL) + feature_infos[j].flags ^= F_GLOBAL; + feature_infos[j].max_value = hb_max (feature_infos[j].max_value, feature_infos[i].max_value); /* Inherit default_value from j */ } feature_infos[j].flags |= (feature_infos[i].flags & F_HAS_FALLBACK); - feature_infos[j].stage[0] = MIN (feature_infos[j].stage[0], feature_infos[i].stage[0]); - feature_infos[j].stage[1] = MIN (feature_infos[j].stage[1], feature_infos[i].stage[1]); + feature_infos[j].stage[0] = hb_min (feature_infos[j].stage[0], feature_infos[i].stage[0]); + feature_infos[j].stage[1] = hb_min (feature_infos[j].stage[1], feature_infos[i].stage[1]); } feature_infos.shrink (j + 1); } @@ -213,34 +218,34 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, bits_needed = 0; else /* Limit bits per feature. */ - bits_needed = MIN(HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value)); + bits_needed = hb_min (HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value)); if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t)) continue; /* Feature disabled, or not enough bits. */ - hb_bool_t found = false; + bool found = false; unsigned int feature_index[2]; for (unsigned int table_index = 0; table_index < 2; table_index++) { if (required_feature_tag[table_index] == info->tag) required_feature_stage[table_index] = info->stage[table_index]; - found |= hb_ot_layout_language_find_feature (face, - table_tags[table_index], - script_index[table_index], - language_index[table_index], - info->tag, - &feature_index[table_index]); + found |= (bool) hb_ot_layout_language_find_feature (face, + table_tags[table_index], + script_index[table_index], + language_index[table_index], + info->tag, + &feature_index[table_index]); } if (!found && (info->flags & F_GLOBAL_SEARCH)) { for (unsigned int table_index = 0; table_index < 2; table_index++) { - found |= hb_ot_layout_table_find_feature (face, - table_tags[table_index], - info->tag, - &feature_index[table_index]); + found |= (bool) hb_ot_layout_table_find_feature (face, + table_tags[table_index], + info->tag, + &feature_index[table_index]); } } if (!found && !(info->flags & F_HAS_FALLBACK)) @@ -332,3 +337,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m, } } } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh index 7505adfe127..5c23eb57814 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-map.hh @@ -68,7 +68,7 @@ struct hb_ot_map_t unsigned short random : 1; hb_mask_t mask; - static int cmp (const void *pa, const void *pb) + HB_INTERNAL static int cmp (const void *pa, const void *pb) { const lookup_map_t *a = (const lookup_map_t *) pa; const lookup_map_t *b = (const lookup_map_t *) pb; @@ -134,13 +134,13 @@ struct hb_ot_map_t unsigned int get_feature_stage (unsigned int table_index, hb_tag_t feature_tag) const { const feature_map_t *map = features.bsearch (feature_tag); - return map ? map->stage[table_index] : (unsigned int) -1; + return map ? map->stage[table_index] : UINT_MAX; } void get_stage_lookups (unsigned int table_index, unsigned int stage, const struct lookup_map_t **plookups, unsigned int *lookup_count) const { - if (unlikely (stage == (unsigned int) -1)) { + if (unlikely (stage == UINT_MAX)) { *plookups = nullptr; *lookup_count = 0; return; @@ -154,8 +154,8 @@ struct hb_ot_map_t HB_INTERNAL void collect_lookups (unsigned int table_index, hb_set_t *lookups) const; template - HB_INTERNAL inline void apply (const Proxy &proxy, - const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; + HB_INTERNAL void apply (const Proxy &proxy, + const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; HB_INTERNAL void substitute (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; HB_INTERNAL void position (const struct hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) const; @@ -167,7 +167,7 @@ struct hb_ot_map_t hb_mask_t global_mask; - hb_vector_t features; + hb_sorted_vector_t features; hb_vector_t lookups[2]; /* GSUB/GPOS */ hb_vector_t stages[2]; /* GSUB/GPOS */ }; @@ -213,8 +213,8 @@ struct hb_ot_map_builder_t { add_feature (feat.tag, feat.flags); } void enable_feature (hb_tag_t tag, - hb_ot_map_feature_flags_t flags=F_NONE, - unsigned int value=1) + hb_ot_map_feature_flags_t flags=F_NONE, + unsigned int value=1) { add_feature (tag, F_GLOBAL | flags, value); } void disable_feature (hb_tag_t tag) @@ -247,7 +247,7 @@ struct hb_ot_map_builder_t unsigned int default_value; /* for non-global features, what should the unset glyphs take */ unsigned int stage[2]; /* GSUB/GPOS */ - static int cmp (const void *pa, const void *pb) + HB_INTERNAL static int cmp (const void *pa, const void *pb) { const feature_info_t *a = (const feature_info_t *) pa; const feature_info_t *b = (const feature_info_t *) pb; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh index 07112e0f420..6cacf8eadb7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-math-table.hh @@ -48,7 +48,7 @@ struct MathValueRecord } protected: - HBINT16 value; /* The X or Y value in design units */ + HBINT16 value; /* The X or Y value in design units */ OffsetTo deviceTable; /* Offset to the device table - from the * beginning of parent table. May be NULL. * Suggested format for device table is 1. */ @@ -78,7 +78,7 @@ struct MathConstants } hb_position_t get_value (hb_ot_math_constant_t constant, - hb_font_t *font) const + hb_font_t *font) const { switch (constant) { @@ -279,14 +279,15 @@ struct MathKern protected: HBUINT16 heightCount; UnsizedArrayOf - mathValueRecordsZ; /* Array of correction heights at - * which the kern value changes. - * Sorted by the height value in - * design units (heightCount entries), - * Followed by: - * Array of kern values corresponding - * to heights. (heightCount+1 entries). - */ + mathValueRecordsZ; + /* Array of correction heights at + * which the kern value changes. + * Sorted by the height value in + * design units (heightCount entries), + * Followed by: + * Array of kern values corresponding + * to heights. (heightCount+1 entries). + */ public: DEFINE_SIZE_ARRAY (2, mathValueRecordsZ); @@ -345,15 +346,18 @@ struct MathKernInfo } protected: - OffsetTo mathKernCoverage; /* Offset to Coverage table - - * from the beginning of the - * MathKernInfo table. */ - ArrayOf mathKernInfoRecords; /* Array of - * MathKernInfoRecords, - * per-glyph information for - * mathematical positioning - * of subscripts and - * superscripts. */ + OffsetTo + mathKernCoverage; + /* Offset to Coverage table - + * from the beginning of the + * MathKernInfo table. */ + ArrayOf + mathKernInfoRecords; + /* Array of MathKernInfoRecords, + * per-glyph information for + * mathematical positioning + * of subscripts and + * superscripts. */ public: DEFINE_SIZE_ARRAY (4, mathKernInfoRecords); @@ -423,7 +427,7 @@ struct MathGlyphVariantRecord } protected: - GlyphID variantGlyph; /* Glyph ID for the variant. */ + HBGlyphID variantGlyph; /* Glyph ID for the variant. */ HBUINT16 advanceMeasurement; /* Advance width/height, in design units, of the * variant, in the direction of requested * glyph extension. */ @@ -453,16 +457,16 @@ struct MathGlyphPartRecord } void extract (hb_ot_math_glyph_part_t &out, - int scale, + int64_t mult, hb_font_t *font) const { out.glyph = glyph; - out.start_connector_length = font->em_scale (startConnectorLength, scale); - out.end_connector_length = font->em_scale (endConnectorLength, scale); - out.full_advance = font->em_scale (fullAdvance, scale); + out.start_connector_length = font->em_mult (startConnectorLength, mult); + out.end_connector_length = font->em_mult (endConnectorLength, mult); + out.full_advance = font->em_mult (fullAdvance, mult); - static_assert ((unsigned int) HB_MATH_GLYPH_PART_FLAG_EXTENDER == + static_assert ((unsigned int) HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER == (unsigned int) PartFlags::Extender, ""); out.flags = (hb_ot_math_glyph_part_flags_t) @@ -471,19 +475,21 @@ struct MathGlyphPartRecord } protected: - GlyphID glyph; /* Glyph ID for the part. */ - HBUINT16 startConnectorLength; /* Advance width/ height of the straight bar - * connector material, in design units, is at - * the beginning of the glyph, in the - * direction of the extension. */ - HBUINT16 endConnectorLength; /* Advance width/ height of the straight bar - * connector material, in design units, is at - * the end of the glyph, in the direction of - * the extension. */ - HBUINT16 fullAdvance; /* Full advance width/height for this part, - * in the direction of the extension. - * In design units. */ - PartFlags partFlags; /* Part qualifiers. */ + HBGlyphID glyph; /* Glyph ID for the part. */ + HBUINT16 startConnectorLength; + /* Advance width/ height of the straight bar + * connector material, in design units, is at + * the beginning of the glyph, in the + * direction of the extension. */ + HBUINT16 endConnectorLength; + /* Advance width/ height of the straight bar + * connector material, in design units, is at + * the end of the glyph, in the direction of + * the extension. */ + HBUINT16 fullAdvance; /* Full advance width/height for this part, + * in the direction of the extension. + * In design units. */ + PartFlags partFlags; /* Part qualifiers. */ public: DEFINE_SIZE_STATIC (10); @@ -508,11 +514,10 @@ struct MathGlyphAssembly { if (parts_count) { - int scale = font->dir_scale (direction); - hb_array_t arr = partRecords.sub_array (start_offset, parts_count); - unsigned int count = arr.length; - for (unsigned int i = 0; i < count; i++) - arr[i].extract (parts[i], scale, font); + int64_t mult = font->dir_mult (direction); + for (auto _ : hb_zip (partRecords.sub_array (start_offset, parts_count), + hb_array (parts, *parts_count))) + _.first.extract (_.second, mult, font); } if (italics_correction) @@ -522,12 +527,15 @@ struct MathGlyphAssembly } protected: - MathValueRecord italicsCorrection; /* Italics correction of this - * MathGlyphAssembly. Should not - * depend on the assembly size. */ - ArrayOf partRecords; /* Array of part records, from - * left to right and bottom to - * top. */ + MathValueRecord + italicsCorrection; + /* Italics correction of this + * MathGlyphAssembly. Should not + * depend on the assembly size. */ + ArrayOf + partRecords; /* Array of part records, from + * left to right and bottom to + * top. */ public: DEFINE_SIZE_ARRAY (6, partRecords); @@ -553,14 +561,10 @@ struct MathGlyphConstruction { if (variants_count) { - int scale = font->dir_scale (direction); - hb_array_t arr = mathGlyphVariantRecord.sub_array (start_offset, variants_count); - unsigned int count = arr.length; - for (unsigned int i = 0; i < count; i++) - { - variants[i].glyph = arr[i].variantGlyph; - variants[i].advance = font->em_scale (arr[i].advanceMeasurement, scale); - } + int64_t mult = font->dir_mult (direction); + for (auto _ : hb_zip (mathGlyphVariantRecord.sub_array (start_offset, variants_count), + hb_array (variants, *variants_count))) + _.second = {_.first.variantGlyph, font->em_mult (_.first.advanceMeasurement, mult)}; } return mathGlyphVariantRecord.len; } @@ -612,12 +616,12 @@ struct MathVariants .get_variants (direction, font, start_offset, variants_count, variants); } unsigned int get_glyph_parts (hb_codepoint_t glyph, - hb_direction_t direction, - hb_font_t *font, - unsigned int start_offset, - unsigned int *parts_count, /* IN/OUT */ - hb_ot_math_glyph_part_t *parts /* OUT */, - hb_position_t *italics_correction /* OUT */) const + hb_direction_t direction, + hb_font_t *font, + unsigned int start_offset, + unsigned int *parts_count, /* IN/OUT */ + hb_ot_math_glyph_part_t *parts /* OUT */, + hb_position_t *italics_correction /* OUT */) const { return get_glyph_construction (glyph, direction, font) .get_assembly () .get_parts (direction, font, @@ -645,26 +649,29 @@ struct MathVariants } protected: - HBUINT16 minConnectorOverlap; /* Minimum overlap of connecting - * glyphs during glyph construction, - * in design units. */ - OffsetTo vertGlyphCoverage; /* Offset to Coverage table - - * from the beginning of MathVariants - * table. */ - OffsetTo horizGlyphCoverage; /* Offset to Coverage table - - * from the beginning of MathVariants - * table. */ - HBUINT16 vertGlyphCount; /* Number of glyphs for which - * information is provided for - * vertically growing variants. */ - HBUINT16 horizGlyphCount; /* Number of glyphs for which - * information is provided for - * horizontally growing variants. */ + HBUINT16 minConnectorOverlap; + /* Minimum overlap of connecting + * glyphs during glyph construction, + * in design units. */ + OffsetTo vertGlyphCoverage; + /* Offset to Coverage table - + * from the beginning of MathVariants + * table. */ + OffsetTo horizGlyphCoverage; + /* Offset to Coverage table - + * from the beginning of MathVariants + * table. */ + HBUINT16 vertGlyphCount; /* Number of glyphs for which + * information is provided for + * vertically growing variants. */ + HBUINT16 horizGlyphCount;/* Number of glyphs for which + * information is provided for + * horizontally growing variants. */ /* Array of offsets to MathGlyphConstruction tables - from the beginning of the MathVariants table, for shapes growing in vertical/horizontal direction. */ - UnsizedArrayOf > + UnsizedArrayOf> glyphConstruction; public: @@ -694,7 +701,7 @@ struct MATH } hb_position_t get_constant (hb_ot_math_constant_t constant, - hb_font_t *font) const + hb_font_t *font) const { return (this+mathConstants).get_value (constant, font); } const MathGlyphInfo &get_glyph_info () const { return this+mathGlyphInfo; } @@ -702,11 +709,14 @@ struct MATH const MathVariants &get_variants () const { return this+mathVariants; } protected: - FixedVersion<>version; /* Version of the MATH table - * initially set to 0x00010000u */ - OffsetTo mathConstants;/* MathConstants table */ - OffsetTo mathGlyphInfo;/* MathGlyphInfo table */ - OffsetTo mathVariants; /* MathVariants table */ + FixedVersion<>version; /* Version of the MATH table + * initially set to 0x00010000u */ + OffsetTo + mathConstants; /* MathConstants table */ + OffsetTo + mathGlyphInfo; /* MathGlyphInfo table */ + OffsetTo + mathVariants; /* MathVariants table */ public: DEFINE_SIZE_STATIC (10); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc index e10cf3844ba..94a57201871 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.cc @@ -24,9 +24,10 @@ * Igalia Author(s): Frédéric Wang */ -#include "hb-open-type.hh" +#include "hb.hh" + +#ifndef HB_NO_MATH -#include "hb-ot-face.hh" #include "hb-ot-math-table.hh" @@ -37,6 +38,11 @@ * @include: hb-ot.h * * Functions for fetching mathematics layout data from OpenType fonts. + * + * HarfBuzz itself does not implement a math layout solution. The + * functions and types provided can be used by client programs to access + * the font data necessary for typesetting OpenType Math layout. + * **/ @@ -48,10 +54,9 @@ * hb_ot_math_has_data: * @face: #hb_face_t to test * - * This function allows to verify the presence of an OpenType MATH table on the - * face. + * Tests whether a face has a `MATH` table. * - * Return value: true if face has a MATH table, false otherwise + * Return value: true if the table is found, false otherwise * * Since: 1.3.3 **/ @@ -63,16 +68,18 @@ hb_ot_math_has_data (hb_face_t *face) /** * hb_ot_math_get_constant: - * @font: #hb_font_t from which to retrieve the value + * @font: #hb_font_t to work upon * @constant: #hb_ot_math_constant_t the constant to retrieve * - * This function returns the requested math constants as a #hb_position_t. - * If the request constant is HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN, - * HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or - * HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN then the return value is - * actually an integer between 0 and 100 representing that percentage. + * Fetches the specified math constant. For most constants, the value returned + * is an #hb_position_t. + * + * However, if the requested constant is #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN, + * #HB_OT_MATH_CONSTANT_SCRIPT_SCRIPT_PERCENT_SCALE_DOWN or + * #HB_OT_MATH_CONSTANT_SCRIPT_PERCENT_SCALE_DOWN, then the return value is + * an integer between 0 and 100 representing that percentage. * - * Return value: the requested constant or 0 + * Return value: the requested constant or zero * * Since: 1.3.3 **/ @@ -85,10 +92,13 @@ hb_ot_math_get_constant (hb_font_t *font, /** * hb_ot_math_get_glyph_italics_correction: - * @font: #hb_font_t from which to retrieve the value - * @glyph: glyph index from which to retrieve the value + * @font: #hb_font_t to work upon + * @glyph: The glyph index from which to retrieve the value * - * Return value: the italics correction of the glyph or 0 + * Fetches an italics-correction value (if one exists) for the specified + * glyph index. + * + * Return value: the italics correction of the glyph or zero * * Since: 1.3.3 **/ @@ -101,10 +111,20 @@ hb_ot_math_get_glyph_italics_correction (hb_font_t *font, /** * hb_ot_math_get_glyph_top_accent_attachment: - * @font: #hb_font_t from which to retrieve the value - * @glyph: glyph index from which to retrieve the value + * @font: #hb_font_t to work upon + * @glyph: The glyph index from which to retrieve the value + * + * Fetches a top-accent-attachment value (if one exists) for the specified + * glyph index. + * + * For any glyph that does not have a top-accent-attachment value - that is, + * a glyph not covered by the `MathTopAccentAttachment` table (or, when + * @font has no `MathTopAccentAttachment` table or no `MATH` table, any + * glyph) - the function synthesizes a value, returning the position at + * one-half the glyph's advance width. * - * Return value: the top accent attachment of the glyph or 0 + * Return value: the top accent attachment of the glyph or 0.5 * the advance + * width of @glyph * * Since: 1.3.3 **/ @@ -117,8 +137,10 @@ hb_ot_math_get_glyph_top_accent_attachment (hb_font_t *font, /** * hb_ot_math_is_glyph_extended_shape: - * @face: a #hb_face_t to test - * @glyph: a glyph index to test + * @face: #hb_face_t to work upon + * @glyph: The glyph index to test + * + * Tests whether the given glyph index is an extended shape in the face. * * Return value: true if the glyph is an extended shape, false otherwise * @@ -133,18 +155,20 @@ hb_ot_math_is_glyph_extended_shape (hb_face_t *face, /** * hb_ot_math_get_glyph_kerning: - * @font: #hb_font_t from which to retrieve the value - * @glyph: glyph index from which to retrieve the value - * @kern: the #hb_ot_math_kern_t from which to retrieve the value + * @font: #hb_font_t to work upon + * @glyph: The glyph index from which to retrieve the value + * @kern: The #hb_ot_math_kern_t from which to retrieve the value * @correction_height: the correction height to use to determine the kerning. * - * This function tries to retrieve the MathKern table for the specified font, - * glyph and #hb_ot_math_kern_t. Then it browses the list of heights from the - * MathKern table to find one value that is greater or equal to specified - * correction_height. If one is found the corresponding value from the list of - * kerns is returned and otherwise the last kern value is returned. + * Fetches the math kerning (cut-ins) value for the specified font, glyph index, and + * @kern. + * + * If the MathKern table is found, the function examines it to find a height + * value that is greater or equal to @correction_height. If such a height + * value is found, corresponding kerning value from the table is returned. If + * no such height value is found, the last kerning value is returned. * - * Return value: requested kerning or 0 + * Return value: requested kerning value or zero * * Since: 1.3.3 **/ @@ -162,20 +186,24 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font, /** * hb_ot_math_get_glyph_variants: - * @font: #hb_font_t from which to retrieve the values - * @glyph: index of the glyph to stretch - * @direction: direction of the stretching + * @font: #hb_font_t to work upon + * @glyph: The index of the glyph to stretch + * @direction: The direction of the stretching (horizontal or vertical) * @start_offset: offset of the first variant to retrieve - * @variants_count: maximum number of variants to retrieve after start_offset - * (IN) and actual number of variants retrieved (OUT) - * @variants: array of size at least @variants_count to store the result + * @variants_count: (inout): Input = the maximum number of variants to return; + * Output = the actual number of variants returned + * @variants: (out) (array length=variants_count): array of variants returned * - * This function tries to retrieve the MathGlyphConstruction for the specified - * font, glyph and direction. Note that only the value of - * #HB_DIRECTION_IS_HORIZONTAL is considered. It provides the corresponding list - * of size variants as an array of hb_ot_math_glyph_variant_t structs. + * Fetches the MathGlyphConstruction for the specified font, glyph index, and + * direction. The corresponding list of size variants is returned as a list of + * #hb_ot_math_glyph_variant_t structs. * - * Return value: the total number of size variants available or 0 + * The @direction parameter is only used to select between horizontal + * or vertical directions for the construction. Even though all #hb_direction_t + * values are accepted, only the result of #HB_DIRECTION_IS_HORIZONTAL is + * considered. + * + * Return value: the total number of size variants available or zero * * Since: 1.3.3 **/ @@ -195,15 +223,19 @@ hb_ot_math_get_glyph_variants (hb_font_t *font, /** * hb_ot_math_get_min_connector_overlap: - * @font: #hb_font_t from which to retrieve the value - * @direction: direction of the stretching + * @font: #hb_font_t to work upon + * @direction: direction of the stretching (horizontal or vertical) + * + * Fetches the MathVariants table for the specified font and returns the + * minimum overlap of connecting glyphs that are required to draw a glyph + * assembly in the specified direction. * - * This function tries to retrieve the MathVariants table for the specified - * font and returns the minimum overlap of connecting glyphs to draw a glyph - * assembly in the specified direction. Note that only the value of - * #HB_DIRECTION_IS_HORIZONTAL is considered. + * The @direction parameter is only used to select between horizontal + * or vertical directions for the construction. Even though all #hb_direction_t + * values are accepted, only the result of #HB_DIRECTION_IS_HORIZONTAL is + * considered. * - * Return value: requested min connector overlap or 0 + * Return value: requested minimum connector overlap or zero * * Since: 1.3.3 **/ @@ -216,19 +248,24 @@ hb_ot_math_get_min_connector_overlap (hb_font_t *font, /** * hb_ot_math_get_glyph_assembly: - * @font: #hb_font_t from which to retrieve the values - * @glyph: index of the glyph to stretch - * @direction: direction of the stretching + * @font: #hb_font_t to work upon + * @glyph: The index of the glyph to stretch + * @direction: direction of the stretching (horizontal or vertical) * @start_offset: offset of the first glyph part to retrieve - * @parts_count: maximum number of glyph parts to retrieve after start_offset - * (IN) and actual number of parts retrieved (OUT) - * @parts: array of size at least @parts_count to store the result - * @italics_correction: italic correction of the glyph assembly + * @parts_count: (inout): Input = maximum number of glyph parts to return; + * Output = actual number of parts returned + * @parts: (out) (array length=parts_count): the glyph parts returned + * @italics_correction: (out): italics correction of the glyph assembly * - * This function tries to retrieve the GlyphAssembly for the specified font, - * glyph and direction. Note that only the value of #HB_DIRECTION_IS_HORIZONTAL - * is considered. It provides the information necessary to draw the glyph - * assembly as an array of #hb_ot_math_glyph_part_t. + * Fetches the GlyphAssembly for the specified font, glyph index, and direction. + * Returned are a list of #hb_ot_math_glyph_part_t glyph parts that can be + * used to draw the glyph and an italics-correction value (if one is defined + * in the font). + * + * The @direction parameter is only used to select between horizontal + * or vertical directions for the construction. Even though all #hb_direction_t + * values are accepted, only the result of #HB_DIRECTION_IS_HORIZONTAL is + * considered. * * Return value: the total number of parts in the glyph assembly * @@ -251,3 +288,6 @@ hb_ot_math_get_glyph_assembly (hb_font_t *font, parts, italics_correction); } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.h index 3cbdb8b3e5d..0d92ffb4147 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-math.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-math.h @@ -50,6 +50,9 @@ HB_BEGIN_DECLS /** * hb_ot_math_constant_t: * + * The 'MATH' table constants specified at + * https://docs.microsoft.com/en-us/typography/opentype/spec/math + * * Since: 1.3.3 */ typedef enum { @@ -114,6 +117,9 @@ typedef enum { /** * hb_ot_math_kern_t: * + * The math kerning-table types defined for the four corners + * of a glyph. + * * Since: 1.3.3 */ typedef enum { @@ -125,6 +131,10 @@ typedef enum { /** * hb_ot_math_glyph_variant_t: + * @glyph: The glyph index of the variant + * @advance: The advance width of the variant + * + * Data type to hold math-variant information for a glyph. * * Since: 1.3.3 */ @@ -136,14 +146,25 @@ typedef struct hb_ot_math_glyph_variant_t { /** * hb_ot_math_glyph_part_flags_t: * + * Flags for math glyph parts. + * * Since: 1.3.3 */ typedef enum { /*< flags >*/ - HB_MATH_GLYPH_PART_FLAG_EXTENDER = 0x00000001u /* Extender glyph */ + HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER = 0x00000001u /* Extender glyph */ } hb_ot_math_glyph_part_flags_t; /** * hb_ot_math_glyph_part_t: + * @glyph: The glyph index of the variant part + * @start_connector_length: The length of the connector on the starting side of the variant part + * @end_connector_length: The length of the connector on the ending side of the variant part + * @full_advance: The total advance of the part + * @flags: #hb_ot_math_glyph_part_flags_t flags for the part + * + * Data type to hold information for a "part" component of a math-variant glyph. + * Large variants for stretchable math glyphs (such as parentheses) can be constructed + * on the fly from parts. * * Since: 1.3.3 */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh index 2940617b1b8..0afa53a882f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-maxp-table.hh @@ -77,7 +77,7 @@ struct maxp void set_num_glyphs (unsigned int count) { - numGlyphs.set (count); + numGlyphs = count; } bool sanitize (hb_sanitize_context_t *c) const @@ -94,46 +94,43 @@ struct maxp return_trace (likely (version.major == 0 && version.minor == 0x5000u)); } - bool subset (hb_subset_plan_t *plan) const + bool subset (hb_subset_context_t *c) const { - hb_blob_t *maxp_blob = hb_sanitize_context_t().reference_table (plan->source); - hb_blob_t *maxp_prime_blob = hb_blob_copy_writable_or_fail (maxp_blob); - hb_blob_destroy (maxp_blob); + TRACE_SUBSET (this); + maxp *maxp_prime = c->serializer->embed (this); + if (unlikely (!maxp_prime)) return_trace (false); - if (unlikely (!maxp_prime_blob)) { - return false; - } - maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr); + maxp_prime->numGlyphs = c->plan->num_output_glyphs (); + if (maxp_prime->version.major == 1) + { + const maxpV1Tail *src_v1 = &StructAfter (*this); + maxpV1Tail *dest_v1 = c->serializer->embed (src_v1); + if (unlikely (!dest_v1)) return_trace (false); - maxp_prime->set_num_glyphs (plan->glyphs.length); - if (plan->drop_hints) - drop_hint_fields (plan, maxp_prime); + if (c->plan->drop_hints) + drop_hint_fields (dest_v1); + } - bool result = plan->add_table (HB_OT_TAG_maxp, maxp_prime_blob); - hb_blob_destroy (maxp_prime_blob); - return result; + return_trace (true); } - static void drop_hint_fields (hb_subset_plan_t *plan HB_UNUSED, maxp *maxp_prime) + static void drop_hint_fields (maxpV1Tail* dest_v1) { - if (maxp_prime->version.major == 1) - { - maxpV1Tail &v1 = StructAfter (*maxp_prime); - v1.maxZones.set (1); - v1.maxTwilightPoints.set (0); - v1.maxStorage.set (0); - v1.maxFunctionDefs.set (0); - v1.maxInstructionDefs.set (0); - v1.maxStackElements.set (0); - v1.maxSizeOfInstructions.set (0); - } + dest_v1->maxZones = 1; + dest_v1->maxTwilightPoints = 0; + dest_v1->maxStorage = 0; + dest_v1->maxFunctionDefs = 0; + dest_v1->maxInstructionDefs = 0; + dest_v1->maxStackElements = 0; + dest_v1->maxSizeOfInstructions = 0; } protected: - FixedVersion<>version; /* Version of the maxp table (0.5 or 1.0), - * 0x00005000u or 0x00010000u. */ - HBUINT16 numGlyphs; /* The number of glyphs in the font. */ -/*maxpV1Tail v1Tail[VAR]; */ + FixedVersion<>version;/* Version of the maxp table (0.5 or 1.0), + * 0x00005000u or 0x00010000u. */ + HBUINT16 numGlyphs; + /* The number of glyphs in the font. */ +/*maxpV1Tail v1Tail[HB_VAR_ARRAY]; */ public: DEFINE_SIZE_STATIC (6); }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh new file mode 100644 index 00000000000..2b45f42572f --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta-table.hh @@ -0,0 +1,127 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_OT_META_TABLE_HH +#define HB_OT_META_TABLE_HH + +#include "hb-open-type.hh" + +/* + * meta -- Metadata Table + * https://docs.microsoft.com/en-us/typography/opentype/spec/meta + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6meta.html + */ +#define HB_OT_TAG_meta HB_TAG ('m','e','t','a') + + +namespace OT { + + +struct DataMap +{ + int cmp (hb_tag_t a) const { return tag.cmp (a); } + + hb_tag_t get_tag () const { return tag; } + + hb_blob_t *reference_entry (hb_blob_t *meta_blob) const + { return hb_blob_create_sub_blob (meta_blob, dataZ, dataLength); } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + dataZ.sanitize (c, base, dataLength))); + } + + protected: + Tag tag; /* A tag indicating the type of metadata. */ + LNNOffsetTo> + dataZ; /* Offset in bytes from the beginning of the + * metadata table to the data for this tag. */ + HBUINT32 dataLength; /* Length of the data. The data is not required to + * be padded to any byte boundary. */ + public: + DEFINE_SIZE_STATIC (12); +}; + +struct meta +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_meta; + + struct accelerator_t + { + void init (hb_face_t *face) + { table = hb_sanitize_context_t ().reference_table (face); } + void fini () { table.destroy (); } + + hb_blob_t *reference_entry (hb_tag_t tag) const + { return table->dataMaps.lsearch (tag).reference_entry (table.get_blob ()); } + + unsigned int get_entries (unsigned int start_offset, + unsigned int *count, + hb_ot_meta_tag_t *entries) const + { + if (count) + { + + table->dataMaps.sub_array (start_offset, count) + | hb_map (&DataMap::get_tag) + | hb_map ([](hb_tag_t tag) { return (hb_ot_meta_tag_t) tag; }) + | hb_sink (hb_array (entries, *count)) + ; + } + return table->dataMaps.len; + } + + private: + hb_blob_ptr_t table; + }; + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (likely (c->check_struct (this) && + version == 1 && + dataMaps.sanitize (c, this))); + } + + protected: + HBUINT32 version; /* Version number of the metadata table — set to 1. */ + HBUINT32 flags; /* Flags — currently unused; set to 0. */ + HBUINT32 dataOffset; + /* Per Apple specification: + * Offset from the beginning of the table to the data. + * Per OT specification: + * Reserved. Not used; should be set to 0. */ + LArrayOf + dataMaps;/* Array of data map records. */ + public: + DEFINE_SIZE_ARRAY (16, dataMaps); +}; + +struct meta_accelerator_t : meta::accelerator_t {}; + +} /* namespace OT */ + + +#endif /* HB_OT_META_TABLE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc new file mode 100644 index 00000000000..f2d7d337cf3 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.cc @@ -0,0 +1,77 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" + +#ifndef HB_NO_META + +#include "hb-ot-meta-table.hh" + +/** + * SECTION:hb-ot-meta + * @title: hb-ot-meta + * @short_description: OpenType Metadata + * @include: hb-ot.h + * + * Functions for fetching metadata from fonts. + **/ + +/** + * hb_ot_meta_get_entry_tags: + * @face: a face object + * @start_offset: iteration's start offset + * @entries_count:(inout) (allow-none): buffer size as input, filled size as output + * @entries: (out caller-allocates) (array length=entries_count): entries tags buffer + * + * Return value: Number of all available feature types. + * + * Since: 2.6.0 + **/ +unsigned int +hb_ot_meta_get_entry_tags (hb_face_t *face, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT. May be NULL. */ + hb_ot_meta_tag_t *entries /* OUT. May be NULL. */) +{ + return face->table.meta->get_entries (start_offset, entries_count, entries); +} + +/** + * hb_ot_meta_reference_entry: + * @face: a #hb_face_t object. + * @meta_tag: tag of metadata you like to have. + * + * It fetches metadata entry of a given tag from a font. + * + * Returns: (transfer full): A blob containing the blob. + * + * Since: 2.6.0 + **/ +hb_blob_t * +hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_tag_t meta_tag) +{ + return face->table.meta->reference_entry (meta_tag); +} + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.h new file mode 100644 index 00000000000..71e1b781970 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-meta.h @@ -0,0 +1,71 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_OT_H_IN +#error "Include instead." +#endif + +#ifndef HB_OT_META_H +#define HB_OT_META_H + +#include "hb.h" + +HB_BEGIN_DECLS + +/** + * hb_ot_meta_tag_t: + * @HB_OT_META_TAG_DESIGN_LANGUAGES: Design languages. Text, using only + * Basic Latin (ASCII) characters. Indicates languages and/or scripts + * for the user audiences that the font was primarily designed for. + * @HB_OT_META_TAG_SUPPORTED_LANGUAGES: Supported languages. Text, using + * only Basic Latin (ASCII) characters. Indicates languages and/or scripts + * that the font is declared to be capable of supporting. + * + * Known metadata tags from https://docs.microsoft.com/en-us/typography/opentype/spec/meta + * + * Since: 2.6.0 + **/ +typedef enum { +/* + HB_OT_META_TAG_APPL = HB_TAG ('a','p','p','l'), + HB_OT_META_TAG_BILD = HB_TAG ('b','i','l','d'), +*/ + HB_OT_META_TAG_DESIGN_LANGUAGES = HB_TAG ('d','l','n','g'), + HB_OT_META_TAG_SUPPORTED_LANGUAGES = HB_TAG ('s','l','n','g'), + + _HB_OT_META_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ +} hb_ot_meta_tag_t; + +HB_EXTERN unsigned int +hb_ot_meta_get_entry_tags (hb_face_t *face, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT. May be NULL. */ + hb_ot_meta_tag_t *entries /* OUT. May be NULL. */); + +HB_EXTERN hb_blob_t * +hb_ot_meta_reference_entry (hb_face_t *face, hb_ot_meta_tag_t meta_tag); + +HB_END_DECLS + +#endif /* HB_OT_META_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc new file mode 100644 index 00000000000..9c0920a8085 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.cc @@ -0,0 +1,231 @@ +/* + * Copyright © 2018-2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" + +#include "hb-ot-var-mvar-table.hh" +#include "hb-ot-gasp-table.hh" // Just so we compile it; unused otherwise. +#include "hb-ot-os2-table.hh" +#include "hb-ot-post-table.hh" +#include "hb-ot-hhea-table.hh" +#include "hb-ot-metrics.hh" +#include "hb-ot-face.hh" + + +static float +_fix_ascender_descender (float value, hb_ot_metrics_tag_t metrics_tag) +{ + if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER || + metrics_tag == HB_OT_METRICS_TAG_VERTICAL_ASCENDER) + return fabs ((double) value); + if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER || + metrics_tag == HB_OT_METRICS_TAG_VERTICAL_DESCENDER) + return -fabs ((double) value); + return value; +} + +/* The common part of _get_position logic needed on hb-ot-font and here + to be able to have slim builds without the not always needed parts */ +bool +_hb_ot_metrics_get_position_common (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */) +{ + hb_face_t *face = font->face; + switch ((unsigned) metrics_tag) + { +#ifndef HB_NO_VAR +#define GET_VAR face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords) +#else +#define GET_VAR .0f +#endif +#define GET_METRIC_X(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = font->em_scalef_x (_fix_ascender_descender ( \ + face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true)) +#define GET_METRIC_Y(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \ + face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true)) + case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER: + return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) || + GET_METRIC_Y (hhea, ascender); + case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER: + return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoDescender)) || + GET_METRIC_Y (hhea, descender); + case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP: + return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoLineGap)) || + GET_METRIC_Y (hhea, lineGap); + case HB_OT_METRICS_TAG_VERTICAL_ASCENDER: return GET_METRIC_X (vhea, ascender); + case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender); + case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: return GET_METRIC_X (vhea, lineGap); +#undef GET_METRIC_Y +#undef GET_METRIC_X +#undef GET_VAR + default: assert (0); return false; + } +} + +#ifndef HB_NO_METRICS + +#if 0 +static bool +_get_gasp (hb_face_t *face, float *result, hb_ot_metrics_tag_t metrics_tag) +{ + const OT::GaspRange& range = face->table.gasp->get_gasp_range (metrics_tag - HB_TAG ('g','s','p','0')); + if (&range == &Null (OT::GaspRange)) return false; + if (result) *result = range.rangeMaxPPEM + font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords); + return true; +} +#endif + +/* Private tags for https://github.com/harfbuzz/harfbuzz/issues/1866 */ +#define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2 HB_TAG ('O','a','s','c') +#define _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA HB_TAG ('H','a','s','c') +#define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2 HB_TAG ('O','d','s','c') +#define _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA HB_TAG ('H','d','s','c') +#define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2 HB_TAG ('O','l','g','p') +#define _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA HB_TAG ('H','l','g','p') + +/** + * hb_ot_metrics_get_position: + * @font: a #hb_font_t object. + * @metrics_tag: tag of metrics value you like to fetch. + * @position: (out) (optional): result of metrics value from the font. + * + * It fetches metrics value corresponding to a given tag from a font. + * + * Returns: Whether found the requested metrics in the font. + * Since: 2.6.0 + **/ +hb_bool_t +hb_ot_metrics_get_position (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */) +{ + hb_face_t *face = font->face; + switch ((unsigned) metrics_tag) + { + case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER: + case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER: + case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP: + case HB_OT_METRICS_TAG_VERTICAL_ASCENDER: + case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: + case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: return _hb_ot_metrics_get_position_common (font, metrics_tag, position); +#ifndef HB_NO_VAR +#define GET_VAR hb_ot_metrics_get_variation (font, metrics_tag) +#else +#define GET_VAR 0 +#endif +#define GET_METRIC_X(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = font->em_scalef_x (face->table.TABLE->ATTR + GET_VAR)), true)) +#define GET_METRIC_Y(TABLE, ATTR) \ + (face->table.TABLE->has_data () && \ + (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true)) + case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC_Y (OS2, usWinAscent); + case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent); + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: return GET_METRIC_Y (hhea, caretSlopeRise); + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: return GET_METRIC_X (hhea, caretSlopeRun); + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: return GET_METRIC_X (hhea, caretOffset); + case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: return GET_METRIC_X (vhea, caretSlopeRise); + case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: return GET_METRIC_Y (vhea, caretSlopeRun); + case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: return GET_METRIC_Y (vhea, caretOffset); + case HB_OT_METRICS_TAG_X_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sxHeight); + case HB_OT_METRICS_TAG_CAP_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sCapHeight); + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE: return GET_METRIC_X (OS2, ySubscriptXSize); + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE: return GET_METRIC_Y (OS2, ySubscriptYSize); + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET: return GET_METRIC_X (OS2, ySubscriptXOffset); + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET: return GET_METRIC_Y (OS2, ySubscriptYOffset); + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE: return GET_METRIC_X (OS2, ySuperscriptXSize); + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE: return GET_METRIC_Y (OS2, ySuperscriptYSize); + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET: return GET_METRIC_X (OS2, ySuperscriptXOffset); + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET: return GET_METRIC_Y (OS2, ySuperscriptYOffset); + case HB_OT_METRICS_TAG_STRIKEOUT_SIZE: return GET_METRIC_Y (OS2, yStrikeoutSize); + case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET: return GET_METRIC_Y (OS2, yStrikeoutPosition); + case HB_OT_METRICS_TAG_UNDERLINE_SIZE: return GET_METRIC_Y (post->table, underlineThickness); + case HB_OT_METRICS_TAG_UNDERLINE_OFFSET: return GET_METRIC_Y (post->table, underlinePosition); + + /* Private tags */ + case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_OS2: return GET_METRIC_Y (OS2, sTypoAscender); + case _HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER_HHEA: return GET_METRIC_Y (hhea, ascender); + case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_OS2: return GET_METRIC_Y (OS2, sTypoDescender); + case _HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER_HHEA: return GET_METRIC_Y (hhea, descender); + case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_OS2: return GET_METRIC_Y (OS2, sTypoLineGap); + case _HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP_HHEA: return GET_METRIC_Y (hhea, lineGap); +#undef GET_METRIC_Y +#undef GET_METRIC_X +#undef GET_VAR + default: return false; + } +} + +#ifndef HB_NO_VAR +/** + * hb_ot_metrics_get_variation: + * @font: + * @metrics_tag: + * + * Returns: + * + * Since: 2.6.0 + **/ +float +hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag) +{ + return font->face->table.MVAR->get_var (metrics_tag, font->coords, font->num_coords); +} + +/** + * hb_ot_metrics_get_x_variation: + * @font: + * @metrics_tag: + * + * Returns: + * + * Since: 2.6.0 + **/ +hb_position_t +hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag) +{ + return font->em_scalef_x (hb_ot_metrics_get_variation (font, metrics_tag)); +} + +/** + * hb_ot_metrics_get_y_variation: + * @font: + * @metrics_tag: + * + * Returns: + * + * Since: 2.6.0 + **/ +hb_position_t +hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag) +{ + return font->em_scalef_y (hb_ot_metrics_get_variation (font, metrics_tag)); +} +#endif + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.h new file mode 100644 index 00000000000..c1be1d85b3c --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.h @@ -0,0 +1,122 @@ +/* + * Copyright © 2018 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_OT_H_IN +#error "Include instead." +#endif + +#ifndef HB_OT_METRICS_H +#define HB_OT_METRICS_H + +#include "hb.h" +#include "hb-ot-name.h" + +HB_BEGIN_DECLS + + +/** + * hb_ot_metrics_tag_t: + * @HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER: horizontal ascender. + * @HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER: horizontal descender. + * @HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP: horizontal line gap. + * @HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: horizontal clipping ascent. + * @HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: horizontal clipping descent. + * @HB_OT_METRICS_TAG_VERTICAL_ASCENDER: vertical ascender. + * @HB_OT_METRICS_TAG_VERTICAL_DESCENDER: vertical descender. + * @HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: vertical line gap. + * @HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: horizontal caret rise. + * @HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: horizontal caret run. + * @HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: horizontal caret offset. + * @HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: vertical caret rise. + * @HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: vertical caret run. + * @HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: vertical caret offset. + * @HB_OT_METRICS_TAG_X_HEIGHT: x height. + * @HB_OT_METRICS_TAG_CAP_HEIGHT: cap height. + * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE: subscript em x size. + * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE: subscript em y size. + * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET: subscript em x offset. + * @HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET: subscript em y offset. + * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE: superscript em x size. + * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE: superscript em y size. + * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET: superscript em x offset. + * @HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET: superscript em y offset. + * @HB_OT_METRICS_TAG_STRIKEOUT_SIZE: strikeout size. + * @HB_OT_METRICS_TAG_STRIKEOUT_OFFSET: strikeout offset. + * @HB_OT_METRICS_TAG_UNDERLINE_SIZE: underline size. + * @HB_OT_METRICS_TAG_UNDERLINE_OFFSET: underline offset. + * + * From https://docs.microsoft.com/en-us/typography/opentype/spec/mvar#value-tags + * + * Since: 2.6.0 + **/ +typedef enum { + HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER = HB_TAG ('h','a','s','c'), + HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER = HB_TAG ('h','d','s','c'), + HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP = HB_TAG ('h','l','g','p'), + HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT = HB_TAG ('h','c','l','a'), + HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT = HB_TAG ('h','c','l','d'), + HB_OT_METRICS_TAG_VERTICAL_ASCENDER = HB_TAG ('v','a','s','c'), + HB_OT_METRICS_TAG_VERTICAL_DESCENDER = HB_TAG ('v','d','s','c'), + HB_OT_METRICS_TAG_VERTICAL_LINE_GAP = HB_TAG ('v','l','g','p'), + HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE = HB_TAG ('h','c','r','s'), + HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN = HB_TAG ('h','c','r','n'), + HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET = HB_TAG ('h','c','o','f'), + HB_OT_METRICS_TAG_VERTICAL_CARET_RISE = HB_TAG ('v','c','r','s'), + HB_OT_METRICS_TAG_VERTICAL_CARET_RUN = HB_TAG ('v','c','r','n'), + HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET = HB_TAG ('v','c','o','f'), + HB_OT_METRICS_TAG_X_HEIGHT = HB_TAG ('x','h','g','t'), + HB_OT_METRICS_TAG_CAP_HEIGHT = HB_TAG ('c','p','h','t'), + HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE = HB_TAG ('s','b','x','s'), + HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE = HB_TAG ('s','b','y','s'), + HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET = HB_TAG ('s','b','x','o'), + HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET = HB_TAG ('s','b','y','o'), + HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE = HB_TAG ('s','p','x','s'), + HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE = HB_TAG ('s','p','y','s'), + HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET = HB_TAG ('s','p','x','o'), + HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET = HB_TAG ('s','p','y','o'), + HB_OT_METRICS_TAG_STRIKEOUT_SIZE = HB_TAG ('s','t','r','s'), + HB_OT_METRICS_TAG_STRIKEOUT_OFFSET = HB_TAG ('s','t','r','o'), + HB_OT_METRICS_TAG_UNDERLINE_SIZE = HB_TAG ('u','n','d','s'), + HB_OT_METRICS_TAG_UNDERLINE_OFFSET = HB_TAG ('u','n','d','o'), + + _HB_OT_METRICS_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ +} hb_ot_metrics_tag_t; + +HB_EXTERN hb_bool_t +hb_ot_metrics_get_position (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */); + +HB_EXTERN float +hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag); + +HB_EXTERN hb_position_t +hb_ot_metrics_get_x_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag); + +HB_EXTERN hb_position_t +hb_ot_metrics_get_y_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag); + +HB_END_DECLS + +#endif /* HB_OT_METRICS_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.hh similarity index 70% rename from src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.hh rename to src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.hh index 385a8f9d564..2c75f32d999 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-metrics.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2018 Google, Inc. + * Copyright © 2018 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -20,21 +20,16 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Garret Rieger */ -#ifndef HB_SUBSET_GLYF_HH -#define HB_SUBSET_GLYF_HH +#ifndef HB_OT_METRICS_HH +#define HB_OT_METRICS_HH #include "hb.hh" -#include "hb-subset.hh" - HB_INTERNAL bool -hb_subset_glyf_and_loca (hb_subset_plan_t *plan, - bool *use_short_loca, /* OUT */ - hb_blob_t **glyf_prime /* OUT */, - hb_blob_t **loca_prime /* OUT */); +_hb_ot_metrics_get_position_common (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT. May be NULL. */); -#endif /* HB_SUBSET_GLYF_HH */ +#endif /* HB_OT_METRICS_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-name-language.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-name-language-static.hh similarity index 96% rename from src/java.desktop/share/native/libharfbuzz/hb-ot-name-language.cc rename to src/java.desktop/share/native/libharfbuzz/hb-ot-name-language-static.hh index 1606a13cec9..5312f7b3a6e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-name-language.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-name-language-static.hh @@ -24,6 +24,9 @@ * Google Author(s): Behdad Esfahbod */ +#ifndef HB_OT_NAME_LANGUAGE_STATIC_HH +#define HB_OT_NAME_LANGUAGE_STATIC_HH + #include "hb-ot-name-language.hh" /* Following two tables were generated by joining FreeType, FontConfig, @@ -34,12 +37,8 @@ struct hb_ot_language_map_t { - static int cmp (const void *key, const void *item) - { - unsigned int a = * (unsigned int *) key; - unsigned int b = ((const hb_ot_language_map_t *) item)->code; - return a < b ? -1 : a > b ? +1 : 0; - } + int cmp (unsigned int key) const + { return key < code ? -1 : key > code ? +1 : 0; } uint16_t code; char lang[6]; @@ -427,12 +426,10 @@ _hb_ot_name_language_for (unsigned int code, const hb_ot_language_map_t *array, unsigned int len) { - const hb_ot_language_map_t *entry = (const hb_ot_language_map_t *) - hb_bsearch (&code, - array, - len, - sizeof (array[0]), - hb_ot_language_map_t::cmp); +#ifdef HB_NO_OT_NAME_LANGUAGE + return HB_LANGUAGE_INVALID; +#endif + auto *entry = hb_bsearch (code, array, len); if (entry) return hb_language_from_string (entry->lang, -1); @@ -455,3 +452,5 @@ _hb_ot_name_language_for_mac_code (unsigned int code) hb_mac_language_map, ARRAY_LENGTH (hb_mac_language_map)); } + +#endif /* HB_OT_NAME_LANGUAGE_STATIC_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-name-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-name-table.hh index 96600cb4006..fb2300d0688 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-name-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-name-table.hh @@ -51,6 +51,7 @@ struct NameRecord { hb_language_t language (hb_face_t *face) const { +#ifndef HB_NO_OT_NAME_LANGUAGE unsigned int p = platformID; unsigned int l = languageID; @@ -60,9 +61,12 @@ struct NameRecord if (p == 1) return _hb_ot_name_language_for_mac_code (l); +#ifndef HB_NO_OT_NAME_LANGUAGE_AAT if (p == 0) - return _hb_aat_language_get (face, l); + return face->table.ltag->get_language (l); +#endif +#endif return HB_LANGUAGE_INVALID; } @@ -93,11 +97,51 @@ struct NameRecord return UNSUPPORTED; } + NameRecord* copy (hb_serialize_context_t *c, const void *base) const + { + TRACE_SERIALIZE (this); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); + out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length); + return_trace (out); + } + + bool isUnicode () const + { + unsigned int p = platformID; + unsigned int e = encodingID; + + return (p == 0 || + (p == 3 && (e == 0 || e == 1 || e == 10))); + } + + static int cmp (const void *pa, const void *pb) + { + const NameRecord *a = (const NameRecord *)pa; + const NameRecord *b = (const NameRecord *)pb; + + if (a->platformID != b->platformID) + return a->platformID - b->platformID; + + if (a->encodingID != b->encodingID) + return a->encodingID - b->encodingID; + + if (a->languageID != b->languageID) + return a->languageID - b->languageID; + + if (a->nameID != b->nameID) + return a->nameID - b->nameID; + + if (a->length != b->length) + return a->length - b->length; + + return 0; + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); - /* We can check from base all the way up to the end of string... */ - return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset)); + return_trace (c->check_struct (this) && offset.sanitize (c, base, length)); } HBUINT16 platformID; /* Platform ID. */ @@ -105,7 +149,8 @@ struct NameRecord HBUINT16 languageID; /* Language ID. */ HBUINT16 nameID; /* Name ID. */ HBUINT16 length; /* String length (in bytes). */ - HBUINT16 offset; /* String offset from start of storage area (in bytes). */ + NNOffsetTo> + offset; /* String offset from start of storage area (in bytes). */ public: DEFINE_SIZE_STATIC (12); }; @@ -119,7 +164,7 @@ _hb_ot_name_entry_cmp_key (const void *pa, const void *pb) /* Compare by name_id, then language. */ if (a->name_id != b->name_id) - return a->name_id < b->name_id ? -1 : +1; + return a->name_id - b->name_id; if (a->language == b->language) return 0; if (!a->language) return -1; @@ -141,10 +186,10 @@ _hb_ot_name_entry_cmp (const void *pa, const void *pb) const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; if (a->entry_score != b->entry_score) - return a->entry_score < b->entry_score ? -1 : +1; + return a->entry_score - b->entry_score; if (a->entry_index != b->entry_index) - return a->entry_index < b->entry_index ? -1 : +1; + return a->entry_index - b->entry_index; return 0; } @@ -156,15 +201,65 @@ struct name unsigned int get_size () const { return min_size + count * nameRecordZ.item_size; } + template + bool serialize (hb_serialize_context_t *c, + Iterator it, + const void *src_string_pool) + { + TRACE_SERIALIZE (this); + + if (unlikely (!c->extend_min ((*this)))) return_trace (false); + + this->format = 0; + this->count = it.len (); + + NameRecord *name_records = (NameRecord *) calloc (it.len (), NameRecord::static_size); + if (unlikely (!name_records)) return_trace (false); + + hb_array_t records (name_records, it.len ()); + + for (const NameRecord& record : it) + { + memcpy (name_records, &record, NameRecord::static_size); + name_records++; + } + + records.qsort (); + + c->copy_all (records, src_string_pool); + free (records.arrayZ); + + if (unlikely (c->ran_out_of_room)) return_trace (false); + + this->stringOffset = c->length (); + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + name *name_prime = c->serializer->start_embed (); + if (unlikely (!name_prime)) return_trace (false); + + auto it = + + nameRecordZ.as_array (count) + | hb_filter (c->plan->name_ids, &NameRecord::nameID) + | hb_filter (c->plan->name_languages, &NameRecord::languageID) + | hb_filter ([&] (const NameRecord& namerecord) { return c->plan->name_legacy || namerecord.isUnicode (); }) + ; + + name_prime->serialize (c->serializer, it, hb_addressof (this + stringOffset)); + return_trace (name_prime->count); + } + bool sanitize_records (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); const void *string_pool = (this+stringOffset).arrayZ; - unsigned int _count = count; - /* Move to run-time?! */ - for (unsigned int i = 0; i < _count; i++) - if (!nameRecordZ[i].sanitize (c, string_pool)) return_trace (false); - return_trace (true); + return_trace (nameRecordZ.sanitize (c, count, string_pool)); } bool sanitize (hb_sanitize_context_t *c) const @@ -173,14 +268,15 @@ struct name return_trace (c->check_struct (this) && likely (format == 0 || format == 1) && c->check_array (nameRecordZ.arrayZ, count) && - c->check_range (this, stringOffset)); + c->check_range (this, stringOffset) && + sanitize_records (c)); } struct accelerator_t { void init (hb_face_t *face) { - this->table = hb_sanitize_context_t().reference_table (face); + this->table = hb_sanitize_context_t ().reference_table (face); assert (this->table.get_length () >= this->table->stringOffset); this->pool = (const char *) (const void *) (this->table+this->table->stringOffset); this->pool_len = this->table.get_length () - this->table->stringOffset; @@ -224,16 +320,14 @@ struct name this->table.destroy (); } - int get_index (hb_ot_name_id_t name_id, - hb_language_t language, - unsigned int *width=nullptr) const + int get_index (hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *width=nullptr) const { const hb_ot_name_entry_t key = {name_id, {0}, language}; - const hb_ot_name_entry_t *entry = (const hb_ot_name_entry_t *) - hb_bsearch (&key, - (const hb_ot_name_entry_t *) this->names, + const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, this->names.length, - sizeof (key), + sizeof (hb_ot_name_entry_t), _hb_ot_name_entry_cmp_key); if (!entry) return -1; @@ -261,16 +355,19 @@ struct name }; /* We only implement format 0 for now. */ - HBUINT16 format; /* Format selector (=0/1). */ - HBUINT16 count; /* Number of name records. */ - NNOffsetTo > - stringOffset; /* Offset to start of string storage (from start of table). */ + HBUINT16 format; /* Format selector (=0/1). */ + HBUINT16 count; /* Number of name records. */ + NNOffsetTo> + stringOffset; /* Offset to start of string storage (from start of table). */ UnsizedArrayOf - nameRecordZ; /* The name records where count is the number of records. */ + nameRecordZ; /* The name records where count is the number of records. */ public: DEFINE_SIZE_ARRAY (6, nameRecordZ); }; +#undef entry_index +#undef entry_score + struct name_accelerator_t : name::accelerator_t {}; } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-name.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-name.cc index 83a332e77d2..56bfd39168b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-name.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-name.cc @@ -26,9 +26,10 @@ #include "hb.hh" +#ifndef HB_NO_NAME + #include "hb-ot-name-table.hh" -#include "hb-ot-face.hh" #include "hb-utf.hh" @@ -93,7 +94,7 @@ hb_ot_name_convert_utf (hb_bytes_t bytes, dst = dst_next; src = src_next; - }; + } *text_size = dst - text; *dst = 0; /* NUL-terminate. */ @@ -105,7 +106,7 @@ hb_ot_name_convert_utf (hb_bytes_t bytes, { src = in_utf_t::next (src, src_end, &unicode, replacement); dst_len += out_utf_t::encode_len (unicode); - }; + } return dst_len; } @@ -222,3 +223,6 @@ hb_ot_name_get_utf32 (hb_face_t *face, { return hb_ot_name_get_utf (face, name_id, language, text_size, text); } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh index 6fbffb14512..3639a06e9be 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-table.hh @@ -30,6 +30,7 @@ #include "hb-open-type.hh" #include "hb-ot-os2-unicode-ranges.hh" +#include "hb-ot-cmap-table.hh" #include "hb-set.hh" @@ -59,6 +60,10 @@ struct OS2V1Tail struct OS2V2Tail { + bool has_data () const { return sxHeight || sCapHeight; } + + const OS2V2Tail * operator -> () const { return this; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -77,6 +82,23 @@ struct OS2V2Tail struct OS2V5Tail { + inline bool get_optical_size (unsigned int *lower, unsigned int *upper) const + { + unsigned int lower_optical_size = usLowerOpticalPointSize; + unsigned int upper_optical_size = usUpperOpticalPointSize; + + /* Per https://docs.microsoft.com/en-us/typography/opentype/spec/os2#lps */ + if (lower_optical_size < upper_optical_size && + lower_optical_size >= 1 && lower_optical_size <= 0xFFFE && + upper_optical_size >= 2 && upper_optical_size <= 0xFFFF) + { + *lower = lower_optical_size; + *upper = upper_optical_size; + return true; + } + return false; + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -94,7 +116,7 @@ struct OS2 { static constexpr hb_tag_t tableTag = HB_OT_TAG_OS2; - bool has_data () const { return this != &Null (OS2); } + bool has_data () const { return usWeightClass || usWidthClass || usFirstCharIndex || usLastCharIndex; } const OS2V1Tail &v1 () const { return version >= 1 ? v1X : Null (OS2V1Tail); } const OS2V2Tail &v2 () const { return version >= 2 ? v2X : Null (OS2V2Tail); } @@ -113,9 +135,9 @@ struct OS2 OBLIQUE = 1u<<9 }; - bool is_italic () const { return fsSelection & ITALIC; } - bool is_oblique () const { return fsSelection & OBLIQUE; } - bool is_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; } + bool is_italic () const { return fsSelection & ITALIC; } + bool is_oblique () const { return fsSelection & OBLIQUE; } + bool use_typo_metrics () const { return fsSelection & USE_TYPO_METRICS; } enum width_class_t { FWIDTH_ULTRA_CONDENSED = 1, /* 50% */ @@ -145,36 +167,49 @@ struct OS2 } } - bool subset (hb_subset_plan_t *plan) const + bool subset (hb_subset_context_t *c) const { - hb_blob_t *os2_blob = hb_sanitize_context_t ().reference_table (plan->source); - hb_blob_t *os2_prime_blob = hb_blob_create_sub_blob (os2_blob, 0, -1); - // TODO(grieger): move to hb_blob_copy_writable_or_fail - hb_blob_destroy (os2_blob); - - OS2 *os2_prime = (OS2 *) hb_blob_get_data_writable (os2_prime_blob, nullptr); - if (unlikely (!os2_prime)) { - hb_blob_destroy (os2_prime_blob); - return false; + TRACE_SUBSET (this); + OS2 *os2_prime = c->serializer->embed (this); + if (unlikely (!os2_prime)) return_trace (false); + + hb_set_t unicodes; + if (!c->plan->glyphs_requested->is_empty ()) + { + hb_map_t unicode_glyphid_map; + + OT::cmap::accelerator_t cmap; + cmap.init (c->plan->source); + cmap.collect_mapping (&unicodes, &unicode_glyphid_map); + cmap.fini (); + + if (c->plan->unicodes->is_empty ()) unicodes.clear (); + else hb_set_set (&unicodes, c->plan->unicodes); + + + unicode_glyphid_map.iter () + | hb_filter (c->plan->glyphs_requested, hb_second) + | hb_map (hb_first) + | hb_sink (unicodes) + ; } - + /* when --gids option is not used, no need to do collect_mapping that is + * iterating all codepoints in each subtable, which is not efficient */ uint16_t min_cp, max_cp; - find_min_and_max_codepoint (plan->unicodes, &min_cp, &max_cp); - os2_prime->usFirstCharIndex.set (min_cp); - os2_prime->usLastCharIndex.set (max_cp); + find_min_and_max_codepoint (unicodes.is_empty () ? c->plan->unicodes : &unicodes, &min_cp, &max_cp); + os2_prime->usFirstCharIndex = min_cp; + os2_prime->usLastCharIndex = max_cp; - _update_unicode_ranges (plan->unicodes, os2_prime->ulUnicodeRange); - bool result = plan->add_table (HB_OT_TAG_OS2, os2_prime_blob); + _update_unicode_ranges (unicodes.is_empty () ? c->plan->unicodes : &unicodes, os2_prime->ulUnicodeRange); - hb_blob_destroy (os2_prime_blob); - return result; + return_trace (true); } void _update_unicode_ranges (const hb_set_t *codepoints, HBUINT32 ulUnicodeRange[4]) const { + HBUINT32 newBits[4]; for (unsigned int i = 0; i < 4; i++) - ulUnicodeRange[i].set (0); + newBits[i] = 0; hb_codepoint_t cp = HB_SET_VALUE_INVALID; while (codepoints->next (&cp)) { @@ -184,40 +219,52 @@ struct OS2 unsigned int block = bit / 32; unsigned int bit_in_block = bit % 32; unsigned int mask = 1 << bit_in_block; - ulUnicodeRange[block].set (ulUnicodeRange[block] | mask); + newBits[block] = newBits[block] | mask; } if (cp >= 0x10000 && cp <= 0x110000) { /* the spec says that bit 57 ("Non Plane 0") implies that there's at least one codepoint beyond the BMP; so I also include all the non-BMP codepoints here */ - ulUnicodeRange[1].set (ulUnicodeRange[1] | (1 << 25)); + newBits[1] = newBits[1] | (1 << 25); } } + + for (unsigned int i = 0; i < 4; i++) + ulUnicodeRange[i] = ulUnicodeRange[i] & newBits[i]; // set bits only if set in the original } static void find_min_and_max_codepoint (const hb_set_t *codepoints, - uint16_t *min_cp, /* OUT */ - uint16_t *max_cp /* OUT */) + uint16_t *min_cp, /* OUT */ + uint16_t *max_cp /* OUT */) { - *min_cp = codepoints->get_min (); - *max_cp = codepoints->get_max (); + *min_cp = hb_min (0xFFFFu, codepoints->get_min ()); + *max_cp = hb_min (0xFFFFu, codepoints->get_max ()); } - enum font_page_t { - HEBREW_FONT_PAGE = 0xB100, // Hebrew Windows 3.1 font page - SIMP_ARABIC_FONT_PAGE = 0xB200, // Simplified Arabic Windows 3.1 font page - TRAD_ARABIC_FONT_PAGE = 0xB300, // Traditional Arabic Windows 3.1 font page - OEM_ARABIC_FONT_PAGE = 0xB400, // OEM Arabic Windows 3.1 font page - SIMP_FARSI_FONT_PAGE = 0xBA00, // Simplified Farsi Windows 3.1 font page - TRAD_FARSI_FONT_PAGE = 0xBB00, // Traditional Farsi Windows 3.1 font page - THAI_FONT_PAGE = 0xDE00 // Thai Windows 3.1 font page + /* https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 */ + enum font_page_t + { + FONT_PAGE_HEBREW = 0xB100, /* Hebrew Windows 3.1 font page */ + FONT_PAGE_SIMP_ARABIC = 0xB200, /* Simplified Arabic Windows 3.1 font page */ + FONT_PAGE_TRAD_ARABIC = 0xB300, /* Traditional Arabic Windows 3.1 font page */ + FONT_PAGE_OEM_ARABIC = 0xB400, /* OEM Arabic Windows 3.1 font page */ + FONT_PAGE_SIMP_FARSI = 0xBA00, /* Simplified Farsi Windows 3.1 font page */ + FONT_PAGE_TRAD_FARSI = 0xBB00, /* Traditional Farsi Windows 3.1 font page */ + FONT_PAGE_THAI = 0xDE00 /* Thai Windows 3.1 font page */ }; - - // https://github.com/Microsoft/Font-Validator/blob/520aaae/OTFontFileVal/val_OS2.cs#L644-L681 font_page_t get_font_page () const { return (font_page_t) (version == 0 ? fsSelection & 0xFF00 : 0); } + unsigned get_size () const + { + unsigned result = min_size; + if (version >= 1) result += v1X.get_size (); + if (version >= 2) result += v2X.get_size (); + if (version >= 5) result += v5X.get_size (); + return result; + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-unicode-ranges.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-unicode-ranges.hh index 7e573b33206..9613d2d186d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-unicode-ranges.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-os2-unicode-ranges.hh @@ -33,19 +33,8 @@ namespace OT { struct OS2Range { - static int - cmp (const void *_key, const void *_item) - { - hb_codepoint_t cp = *((hb_codepoint_t *) _key); - const OS2Range *range = (OS2Range *) _item; - - if (cp < range->start) - return -1; - else if (cp <= range->end) - return 0; - else - return +1; - } + int cmp (hb_codepoint_t key) const + { return (key < start) ? -1 : key <= end ? 0 : +1; } hb_codepoint_t start; hb_codepoint_t end; @@ -233,13 +222,8 @@ static const OS2Range _hb_os2_unicode_ranges[] = static unsigned int _hb_ot_os2_get_unicode_range_bit (hb_codepoint_t cp) { - OS2Range *range = (OS2Range*) hb_bsearch (&cp, _hb_os2_unicode_ranges, - ARRAY_LENGTH (_hb_os2_unicode_ranges), - sizeof (OS2Range), - OS2Range::cmp); - if (range != nullptr) - return range->bit; - return -1; + auto *range = hb_sorted_array (_hb_os2_unicode_ranges).bsearch (cp); + return range ? range->bit : -1; } } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh index 40134b40f13..08449ac2488 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-post-table.hh @@ -35,8 +35,6 @@ #undef HB_STRING_ARRAY_LIST #undef HB_STRING_ARRAY_NAME -#define NUM_FORMAT1_NAMES 258 - /* * post -- PostScript * https://docs.microsoft.com/en-us/typography/opentype/spec/post @@ -73,26 +71,25 @@ struct post { static constexpr hb_tag_t tableTag = HB_OT_TAG_post; - bool subset (hb_subset_plan_t *plan) const + void serialize (hb_serialize_context_t *c) const { - unsigned int post_prime_length; - hb_blob_t *post_blob = hb_sanitize_context_t ().reference_table(plan->source); - hb_blob_t *post_prime_blob = hb_blob_create_sub_blob (post_blob, 0, post::min_size); - post *post_prime = (post *) hb_blob_get_data_writable (post_prime_blob, &post_prime_length); - hb_blob_destroy (post_blob); + post *post_prime = c->allocate_min (); + if (unlikely (!post_prime)) return; - if (unlikely (!post_prime || post_prime_length != post::min_size)) - { - hb_blob_destroy (post_prime_blob); - DEBUG_MSG(SUBSET, nullptr, "Invalid source post table with length %d.", post_prime_length); - return false; - } + memcpy (post_prime, this, post::min_size); + post_prime->version.major = 3; // Version 3 does not have any glyph names. + } - post_prime->version.major.set (3); // Version 3 does not have any glyph names. - bool result = plan->add_table (HB_OT_TAG_post, post_prime_blob); - hb_blob_destroy (post_prime_blob); + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + post *post_prime = c->serializer->start_embed (); + if (unlikely (!post_prime)) return_trace (false); - return result; + serialize (c->serializer); + if (c->serializer->in_error () || c->serializer->ran_out_of_room) return_trace (false); + + return_trace (true); } struct accelerator_t @@ -131,7 +128,7 @@ struct post hb_bytes_t s = find_glyph_name (glyph); if (!s.length) return false; if (!buf_len) return true; - unsigned int len = MIN (buf_len - 1, s.length); + unsigned int len = hb_min (buf_len - 1, s.length); strncpy (buf, s.arrayZ, len); buf[len] = '\0'; return true; @@ -158,7 +155,7 @@ struct post for (unsigned int i = 0; i < count; i++) gids[i] = i; - hb_sort_r (gids, count, sizeof (gids[0]), cmp_gids, (void *) this); + hb_qsort (gids, count, sizeof (gids[0]), cmp_gids, (void *) this); if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids))) { @@ -168,8 +165,7 @@ struct post } hb_bytes_t st (name, len); - const uint16_t *gid = (const uint16_t *) hb_bsearch_r (hb_addressof (st), gids, count, - sizeof (gids[0]), cmp_key, (void *) this); + auto* gid = hb_bsearch (st, gids, count, sizeof (gids[0]), cmp_key, (void *) this); if (gid) { *glyph = *gid; @@ -179,12 +175,14 @@ struct post return false; } + hb_blob_ptr_t table; + protected: unsigned int get_glyph_count () const { if (version == 0x00010000) - return NUM_FORMAT1_NAMES; + return format1_names_length; if (version == 0x00020000) return glyphNameIndex->len; @@ -212,7 +210,7 @@ struct post { if (version == 0x00010000) { - if (glyph >= NUM_FORMAT1_NAMES) + if (glyph >= format1_names_length) return hb_bytes_t (); return format1_names (glyph); @@ -222,9 +220,9 @@ struct post return hb_bytes_t (); unsigned int index = glyphNameIndex->arrayZ[glyph]; - if (index < NUM_FORMAT1_NAMES) + if (index < format1_names_length) return format1_names (index); - index -= NUM_FORMAT1_NAMES; + index -= format1_names_length; if (index >= index_to_offset.length) return hb_bytes_t (); @@ -238,7 +236,6 @@ struct post } private: - hb_blob_ptr_t table; uint32_t version; const ArrayOf *glyphNameIndex; hb_vector_t index_to_offset; @@ -246,6 +243,8 @@ struct post hb_atomic_ptr_t gids_sorted_by_name; }; + bool has_data () const { return version.to_int (); } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -260,7 +259,7 @@ struct post * 0x00020000 for version 2.0 * 0x00025000 for version 2.5 (deprecated) * 0x00030000 for version 3.0 */ - Fixed italicAngle; /* Italic angle in counter-clockwise degrees + HBFixed italicAngle; /* Italic angle in counter-clockwise degrees * from the vertical. Zero for upright text, * negative for text that leans to the right * (forward). */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh index f0d104c63d8..8a29d54d961 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-fallback.hh @@ -49,8 +49,8 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS hb_font_t *font, unsigned int feature_index) { - OT::GlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1]; - OT::GlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1]; + OT::HBGlyphID glyphs[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1]; + OT::HBGlyphID substitutes[SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1]; unsigned int num_glyphs = 0; /* Populate arrays */ @@ -66,8 +66,8 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS u_glyph > 0xFFFFu || s_glyph > 0xFFFFu) continue; - glyphs[num_glyphs].set (u_glyph); - substitutes[num_glyphs].set (s_glyph); + glyphs[num_glyphs] = u_glyph; + substitutes[num_glyphs] = s_glyph; num_glyphs++; } @@ -77,7 +77,9 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS /* Bubble-sort or something equally good! * May not be good-enough for presidential candidate interviews, but good-enough for us... */ - hb_stable_sort (&glyphs[0], num_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &substitutes[0]); + hb_stable_sort (&glyphs[0], num_glyphs, + (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp, + &substitutes[0]); /* Each glyph takes four bytes max, and there's some overhead. */ @@ -86,27 +88,26 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS OT::SubstLookup *lookup = c.start_serialize (); bool ret = lookup->serialize_single (&c, OT::LookupFlag::IgnoreMarks, - hb_array (glyphs, num_glyphs), + hb_sorted_array (glyphs, num_glyphs), hb_array (substitutes, num_glyphs)); c.end_serialize (); - /* TODO sanitize the results? */ - return ret ? c.copy () : nullptr; + return ret && !c.in_error () ? c.copy () : nullptr; } static OT::SubstLookup * arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_font_t *font) { - OT::GlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)]; + OT::HBGlyphID first_glyphs[ARRAY_LENGTH_CONST (ligature_table)]; unsigned int first_glyphs_indirection[ARRAY_LENGTH_CONST (ligature_table)]; unsigned int ligature_per_first_glyph_count_list[ARRAY_LENGTH_CONST (first_glyphs)]; unsigned int num_first_glyphs = 0; /* We know that all our ligatures are 2-component */ - OT::GlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)]; + OT::HBGlyphID ligature_list[ARRAY_LENGTH_CONST (first_glyphs) * ARRAY_LENGTH_CONST(ligature_table[0].ligatures)]; unsigned int component_count_list[ARRAY_LENGTH_CONST (ligature_list)]; - OT::GlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */]; + OT::HBGlyphID component_list[ARRAY_LENGTH_CONST (ligature_list) * 1/* One extra component per ligature */]; unsigned int num_ligatures = 0; /* Populate arrays */ @@ -118,12 +119,14 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN hb_codepoint_t first_glyph; if (!hb_font_get_glyph (font, first_u, 0, &first_glyph)) continue; - first_glyphs[num_first_glyphs].set (first_glyph); + first_glyphs[num_first_glyphs] = first_glyph; ligature_per_first_glyph_count_list[num_first_glyphs] = 0; first_glyphs_indirection[num_first_glyphs] = first_glyph_idx; num_first_glyphs++; } - hb_stable_sort (&first_glyphs[0], num_first_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &first_glyphs_indirection[0]); + hb_stable_sort (&first_glyphs[0], num_first_glyphs, + (int(*)(const OT::HBUINT16*, const OT::HBUINT16 *)) OT::HBGlyphID::cmp, + &first_glyphs_indirection[0]); /* Now that the first-glyphs are sorted, walk again, populate ligatures. */ for (unsigned int i = 0; i < num_first_glyphs; i++) @@ -142,9 +145,9 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN ligature_per_first_glyph_count_list[i]++; - ligature_list[num_ligatures].set (ligature_glyph); + ligature_list[num_ligatures] = ligature_glyph; component_count_list[num_ligatures] = 2; - component_list[num_ligatures].set (second_glyph); + component_list[num_ligatures] = second_glyph; num_ligatures++; } } @@ -159,7 +162,7 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN OT::SubstLookup *lookup = c.start_serialize (); bool ret = lookup->serialize_ligature (&c, OT::LookupFlag::IgnoreMarks, - hb_array (first_glyphs, num_first_glyphs), + hb_sorted_array (first_glyphs, num_first_glyphs), hb_array (ligature_per_first_glyph_count_list, num_first_glyphs), hb_array (ligature_list, num_ligatures), hb_array (component_count_list, num_ligatures), @@ -167,7 +170,7 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN c.end_serialize (); /* TODO sanitize the results? */ - return ret ? c.copy () : nullptr; + return ret && !c.in_error () ? c.copy () : nullptr; } static OT::SubstLookup * @@ -227,8 +230,8 @@ arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUS return false; const Manifest &manifest = reinterpret_cast (arabic_win1256_gsub_lookups.manifest); - static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) / sizeof (ManifestLookup) - <= ARABIC_FALLBACK_MAX_LOOKUPS, ""); + static_assert (sizeof (arabic_win1256_gsub_lookups.manifestData) == + ARABIC_FALLBACK_MAX_LOOKUPS * sizeof (ManifestLookup), ""); /* TODO sanitize the table? */ unsigned j = 0; @@ -289,7 +292,7 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, { arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t)); if (unlikely (!fallback_plan)) - return const_cast (&Null(arabic_fallback_plan_t)); + return const_cast (&Null (arabic_fallback_plan_t)); fallback_plan->num_lookups = 0; fallback_plan->free_lookups = false; @@ -306,7 +309,7 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan, assert (fallback_plan->num_lookups == 0); free (fallback_plan); - return const_cast (&Null(arabic_fallback_plan_t)); + return const_cast (&Null (arabic_fallback_plan_t)); } static void diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-joining-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-joining-list.hh new file mode 100644 index 00000000000..c022d4bb06b --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-joining-list.hh @@ -0,0 +1,46 @@ +/* == Start of generated function == */ +/* + * The following function is generated by running: + * + * ./gen-arabic-joining-list.py ArabicShaping.txt Scripts.txt + * + * on files with these headers: + * + * # ArabicShaping-13.0.0.txt + * # Date: 2020-01-31, 23:55:00 GMT [KW, RP] + * # Scripts-13.0.0.txt + * # Date: 2020-01-22, 00:07:43 GMT + */ + +#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH +#define HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH + +static bool +has_arabic_joining (hb_script_t script) +{ + /* List of scripts that have data in arabic-table. */ + switch ((int) script) + { + case HB_SCRIPT_ADLAM: + case HB_SCRIPT_ARABIC: + case HB_SCRIPT_CHORASMIAN: + case HB_SCRIPT_HANIFI_ROHINGYA: + case HB_SCRIPT_MANDAIC: + case HB_SCRIPT_MANICHAEAN: + case HB_SCRIPT_MONGOLIAN: + case HB_SCRIPT_NKO: + case HB_SCRIPT_PHAGS_PA: + case HB_SCRIPT_PSALTER_PAHLAVI: + case HB_SCRIPT_SOGDIAN: + case HB_SCRIPT_SYRIAC: + return true; + + default: + return false; + } +} + + +#endif /* HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH */ + +/* == End of generated function == */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-table.hh index 7bb0aeb5220..d47d0367700 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic-table.hh @@ -6,10 +6,10 @@ * * on files with these headers: * - * # ArabicShaping-11.0.0.txt - * # Date: 2018-02-21, 14:50:00 GMT [KW, RP] - * # Blocks-11.0.0.txt - * # Date: 2017-10-16, 24:39:00 GMT [KW] + * # ArabicShaping-13.0.0.txt + * # Date: 2020-01-31, 23:55:00 GMT [KW, RP] + * # Blocks-13.0.0.txt + * # Date: 2019-07-10, 19:06:00 GMT [KW] * UnicodeData.txt does not have a header. */ @@ -17,15 +17,15 @@ #define HB_OT_SHAPE_COMPLEX_ARABIC_TABLE_HH -#define X JOINING_TYPE_X -#define R JOINING_TYPE_R -#define T JOINING_TYPE_T -#define U JOINING_TYPE_U #define A JOINING_GROUP_ALAPH #define DR JOINING_GROUP_DALATH_RISH -#define L JOINING_TYPE_L #define C JOINING_TYPE_C #define D JOINING_TYPE_D +#define L JOINING_TYPE_L +#define R JOINING_TYPE_R +#define T JOINING_TYPE_T +#define U JOINING_TYPE_U +#define X JOINING_TYPE_X static const uint8_t joining_table[] = { @@ -71,7 +71,7 @@ static const uint8_t joining_table[] = /* Mandaic */ - /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,U,U,U,X,X,X,X,X,X,X, + /* 0840 */ R,D,D,D,D,D,R,R,D,R,D,D,D,D,D,D,D,D,D,D,R,D,R,R,R,X,X,X,X,X,X,X, /* Syriac Supplement */ @@ -80,8 +80,8 @@ static const uint8_t joining_table[] = /* Arabic Extended-A */ - /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,X,D,D,D,R,D,D,D,D,X,X, - /* 08C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, + /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,X,D,D,D,R,D,D,D,D,D,D, + /* 08C0 */ D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X, /* 08E0 */ X,X,U, #define joining_offset_0x1806u 739 @@ -139,22 +139,29 @@ static const uint8_t joining_table[] = /* 10F20 */ D,D,D,R,D,D,D,D,D,D,D,D,D,D,D,D, /* 10F40 */ D,D,D,D,D,U,X,X,X,X,X,X,X,X,X,X,X,D,D,D,R, -#define joining_offset_0x110bdu 1219 +#define joining_offset_0x10fb0u 1219 + + /* Chorasmian */ + + /* 10FA0 */ D,U,D,D,R,R,R,U,D,R,R,D,D,R,D,D, + /* 10FC0 */ U,D,R,R,D,U,U,U,U,R,D,L, + +#define joining_offset_0x110bdu 1247 /* Kaithi */ /* 110A0 */ U,X,X, /* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U, -#define joining_offset_0x1e900u 1236 +#define joining_offset_0x1e900u 1264 /* Adlam */ /* 1E900 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D, /* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D, - /* 1E940 */ D,D,D,D, + /* 1E940 */ D,D,D,D,X,X,X,X,X,X,X,T, -}; /* Table items: 1304; occupancy: 56% */ +}; /* Table items: 1340; occupancy: 57% */ static unsigned int @@ -183,6 +190,7 @@ joining_type (hb_codepoint_t u) if (hb_in_range (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u]; if (hb_in_range (u, 0x10D00u, 0x10D23u)) return joining_table[u - 0x10D00u + joining_offset_0x10d00u]; if (hb_in_range (u, 0x10F30u, 0x10F54u)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u]; + if (hb_in_range (u, 0x10FB0u, 0x10FCBu)) return joining_table[u - 0x10FB0u + joining_offset_0x10fb0u]; break; case 0x11u: @@ -190,7 +198,7 @@ joining_type (hb_codepoint_t u) break; case 0x1Eu: - if (hb_in_range (u, 0x1E900u, 0x1E943u)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u]; + if (hb_in_range (u, 0x1E900u, 0x1E94Bu)) return joining_table[u - 0x1E900u + joining_offset_0x1e900u]; break; default: @@ -199,15 +207,15 @@ joining_type (hb_codepoint_t u) return X; } -#undef X -#undef R -#undef T -#undef U #undef A #undef DR -#undef L #undef C #undef D +#undef L +#undef R +#undef T +#undef U +#undef X static const uint16_t shaping_table[][4] = @@ -406,16 +414,16 @@ static const struct ligature_set_t { } ligature_table[] = { { 0xFEDFu, { - { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */ { 0xFE82u, 0xFEF5u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM */ - { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */ { 0xFE84u, 0xFEF7u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM */ + { 0xFE88u, 0xFEF9u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM */ + { 0xFE8Eu, 0xFEFBu }, /* ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM */ }}, { 0xFEE0u, { - { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */ { 0xFE82u, 0xFEF6u }, /* ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM */ - { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */ { 0xFE84u, 0xFEF8u }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM */ + { 0xFE88u, 0xFEFAu }, /* ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM */ + { 0xFE8Eu, 0xFEFCu }, /* ARABIC LIGATURE LAM WITH ALEF FINAL FORM */ }}, }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc index a25ced192bd..c8ad501bca6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-arabic.cc @@ -25,6 +25,9 @@ */ #include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex-arabic.hh" #include "hb-ot-shape.hh" @@ -225,8 +228,6 @@ collect_features_arabic (hb_ot_shape_planner_t *plan) map->enable_feature (HB_TAG('c','a','l','t'), F_MANUAL_ZWJ); map->add_gsub_pause (nullptr); - /* And undo here. */ - /* The spec includes 'cswh'. Earlier versions of Windows * used to enable this by default, but testing suggests * that Windows 8 and later do not enable it by default, @@ -289,7 +290,7 @@ arabic_joining (hb_buffer_t *buffer) { unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; - unsigned int prev = (unsigned int) -1, state = 0; + unsigned int prev = UINT_MAX, state = 0; /* Check pre-context */ for (unsigned int i = 0; i < buffer->context_len[0]; i++) @@ -315,7 +316,7 @@ arabic_joining (hb_buffer_t *buffer) const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; - if (entry->prev_action != NONE && prev != (unsigned int) -1) + if (entry->prev_action != NONE && prev != UINT_MAX) { info[prev].arabic_shaping_action() = entry->prev_action; buffer->unsafe_to_break (prev, i + 1); @@ -335,7 +336,7 @@ arabic_joining (hb_buffer_t *buffer) continue; const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; - if (entry->prev_action != NONE && prev != (unsigned int) -1) + if (entry->prev_action != NONE && prev != UINT_MAX) info[prev].arabic_shaping_action() = entry->prev_action; break; } @@ -383,6 +384,10 @@ arabic_fallback_shape (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) { +#ifdef HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK + return; +#endif + const arabic_shape_plan_t *arabic_plan = (const arabic_shape_plan_t *) plan->data; if (!arabic_plan->do_fallback) @@ -467,7 +472,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, unsigned int j = new_len; for (unsigned int i = count; i; i--) { - if (!hb_in_range (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING)) + if (!hb_in_range (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING)) { if (step == CUT) { @@ -488,7 +493,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, unsigned int end = i; while (i && - hb_in_range (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING)) + hb_in_range (info[i - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING)) { i--; hb_position_t width = font->get_glyph_h_advance (info[i].codepoint); @@ -506,7 +511,7 @@ apply_stch (const hb_ot_shape_plan_t *plan HB_UNUSED, unsigned int start = i; unsigned int context = i; while (context && - !hb_in_range (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) && + !hb_in_range (info[context - 1].arabic_shaping_action(), STCH_FIXED, STCH_REPEATING) && (_hb_glyph_info_is_default_ignorable (&info[context - 1]) || HB_ARABIC_GENERAL_CATEGORY_IS_WORD (_hb_glyph_info_get_general_category (&info[context - 1])))) { @@ -597,7 +602,7 @@ postprocess_glyphs_arabic (const hb_ot_shape_plan_t *plan, HB_BUFFER_DEALLOCATE_VAR (buffer, arabic_shaping_action); } -/* http://www.unicode.org/reports/tr53/ */ +/* https://www.unicode.org/reports/tr53/ */ static hb_codepoint_t modifier_combining_marks[] = @@ -706,3 +711,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_arabic = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ }; + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-default.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-default.cc index 97923ecf692..a755aea098b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-default.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-default.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex.hh" @@ -44,3 +48,26 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_default = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ }; + +/* Same as default but no mark advance zeroing / fallback positioning. + * Dumbest shaper ever, basically. */ +const hb_ot_complex_shaper_t _hb_ot_complex_shaper_dumber = +{ + nullptr, /* collect_features */ + nullptr, /* override_features */ + nullptr, /* data_create */ + nullptr, /* data_destroy */ + nullptr, /* preprocess_text */ + nullptr, /* postprocess_glyphs */ + HB_OT_SHAPE_NORMALIZATION_MODE_DEFAULT, + nullptr, /* decompose */ + nullptr, /* compose */ + nullptr, /* setup_masks */ + HB_TAG_NONE, /* gpos_tag */ + nullptr, /* reorder_marks */ + HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, + false, /* fallback_position */ +}; + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hangul.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hangul.cc index c77cac163e3..d7db43755ec 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hangul.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hangul.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex.hh" @@ -214,7 +218,8 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED, else { /* No valid syllable as base for tone mark; try to insert dotted circle. */ - if (font->has_glyph (0x25CCu)) + if (!(buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) && + font->has_glyph (0x25CCu)) { hb_codepoint_t chars[2]; if (!is_zero_width_char (font, u)) { @@ -429,3 +434,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hangul = HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ }; + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hebrew.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hebrew.cc index 1d80a46bb23..57540805868 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hebrew.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-hebrew.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex.hh" @@ -70,6 +74,10 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c, bool found = (bool) c->unicode->compose (a, b, ab); +#ifdef HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK + return found; +#endif + if (!found && !c->plan->has_gpos_mark) { /* Special-case Hebrew presentation forms that are excluded from @@ -172,3 +180,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_hebrew = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, true, /* fallback_position */ }; + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-machine.hh index 9fc63157ed9..4c04e0ca6ec 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-machine.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-machine.hh @@ -34,711 +34,284 @@ #line 36 "hb-ot-shape-complex-indic-machine.hh" static const unsigned char _indic_syllable_machine_trans_keys[] = { - 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, - 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, - 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, - 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, - 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, - 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 4u, 8u, - 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, - 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, - 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 8u, 8u, 4u, 8u, 5u, 7u, 7u, 7u, - 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, - 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, - 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, 4u, 13u, - 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 8u, 8u, 4u, 8u, 5u, 7u, - 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, 5u, 7u, 7u, 7u, 5u, 8u, - 5u, 7u, 7u, 7u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, - 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 13u, 4u, 8u, - 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 8u, 4u, 13u, 4u, 13u, - 5u, 8u, 8u, 8u, 1u, 19u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, - 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, - 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, - 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, - 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, - 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, - 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, - 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, - 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, - 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, - 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, - 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, - 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, - 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, - 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, - 1u, 16u, 1u, 16u, 1u, 16u, 4u, 8u, 3u, 10u, 3u, 10u, 4u, 10u, 1u, 16u, - 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, - 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, - 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, - 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, - 5u, 10u, 3u, 10u, 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, - 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, - 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 4u, 13u, - 3u, 10u, 4u, 8u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, - 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, - 4u, 10u, 1u, 16u, 3u, 13u, 3u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 5u, 10u, - 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, - 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, 4u, 10u, 5u, 10u, 3u, 10u, - 4u, 10u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, - 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, - 3u, 10u, 3u, 13u, 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 1u, 16u, 3u, 13u, - 1u, 16u, 4u, 13u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, - 3u, 10u, 5u, 10u, 5u, 10u, 10u, 10u, 10u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, - 0 + 8u, 8u, 4u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, + 4u, 13u, 4u, 8u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, 6u, 6u, 16u, 16u, + 4u, 8u, 4u, 13u, 4u, 13u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, 4u, 8u, + 6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 4u, 13u, 8u, 8u, 5u, 7u, 5u, 8u, + 4u, 8u, 6u, 6u, 16u, 16u, 4u, 8u, 4u, 8u, 5u, 8u, 8u, 8u, 1u, 19u, + 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, + 1u, 16u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, + 3u, 10u, 5u, 10u, 3u, 17u, 3u, 17u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, + 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, + 1u, 16u, 3u, 10u, 4u, 10u, 5u, 10u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, + 5u, 10u, 3u, 17u, 3u, 17u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, + 3u, 17u, 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, + 4u, 10u, 5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, + 3u, 17u, 4u, 13u, 4u, 8u, 3u, 17u, 3u, 17u, 4u, 17u, 1u, 16u, 3u, 17u, + 1u, 16u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 1u, 16u, 3u, 10u, 4u, 10u, + 5u, 10u, 3u, 17u, 4u, 10u, 5u, 10u, 5u, 10u, 3u, 10u, 5u, 10u, 1u, 17u, + 3u, 17u, 1u, 17u, 4u, 13u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 3u, 10u, + 5u, 10u, 5u, 10u, 10u, 10u, 5u, 10u, 1u, 16u, 0 }; static const char _indic_syllable_machine_key_spans[] = { - 1, 5, 3, 1, 4, 3, 1, 4, - 3, 1, 4, 3, 1, 5, 1, 1, - 5, 1, 1, 5, 1, 1, 5, 1, - 1, 10, 5, 10, 5, 10, 5, 10, - 5, 10, 1, 5, 3, 1, 4, 3, - 1, 4, 3, 1, 4, 3, 1, 5, - 1, 1, 5, 1, 1, 5, 1, 1, - 5, 1, 1, 10, 5, 10, 5, 10, - 5, 10, 5, 10, 1, 5, 3, 1, - 4, 3, 1, 4, 3, 1, 4, 3, - 1, 5, 1, 1, 5, 1, 1, 5, - 1, 1, 5, 1, 1, 10, 5, 10, - 5, 10, 5, 10, 5, 1, 5, 3, - 1, 4, 3, 1, 4, 3, 1, 4, - 3, 1, 5, 1, 1, 5, 1, 1, - 5, 1, 1, 5, 1, 1, 10, 5, - 10, 5, 10, 5, 10, 5, 10, 10, - 4, 1, 19, 11, 8, 7, 16, 11, - 8, 7, 16, 11, 8, 7, 16, 11, - 8, 7, 16, 11, 8, 7, 6, 6, - 6, 1, 1, 1, 6, 8, 6, 8, - 7, 6, 8, 7, 6, 8, 7, 6, - 8, 7, 8, 11, 16, 16, 16, 8, - 11, 16, 16, 16, 8, 11, 16, 16, - 16, 8, 11, 16, 16, 16, 8, 11, - 11, 8, 7, 16, 11, 8, 7, 16, - 11, 8, 7, 16, 11, 8, 7, 16, - 11, 8, 7, 6, 6, 6, 1, 1, - 1, 6, 8, 6, 8, 7, 6, 8, - 7, 6, 8, 7, 6, 8, 7, 8, - 11, 16, 16, 16, 8, 11, 16, 16, - 16, 8, 11, 16, 16, 16, 8, 11, - 16, 16, 16, 5, 8, 8, 7, 16, - 11, 8, 7, 16, 11, 8, 7, 16, - 11, 8, 7, 16, 11, 8, 7, 6, - 6, 6, 1, 1, 1, 6, 8, 6, - 8, 7, 6, 8, 7, 6, 8, 7, - 6, 8, 7, 8, 11, 16, 16, 16, - 8, 11, 16, 16, 16, 8, 11, 16, - 16, 16, 8, 11, 16, 16, 16, 10, - 8, 5, 11, 8, 7, 16, 11, 8, - 7, 16, 11, 8, 7, 16, 11, 8, - 7, 16, 11, 8, 7, 6, 6, 6, - 1, 1, 1, 6, 8, 6, 8, 7, - 6, 8, 7, 6, 8, 7, 6, 8, - 7, 8, 11, 16, 16, 16, 8, 11, - 16, 16, 16, 8, 11, 16, 16, 16, - 8, 11, 16, 16, 16, 8, 16, 11, - 16, 10, 6, 1, 1, 1, 6, 16, - 8, 6, 6, 1, 1, 1, 6, 16 + 1, 5, 3, 4, 5, 1, 1, 5, + 10, 5, 1, 3, 4, 5, 1, 1, + 5, 10, 10, 10, 1, 3, 4, 5, + 1, 1, 5, 5, 10, 1, 3, 4, + 5, 1, 1, 5, 5, 4, 1, 19, + 15, 15, 14, 16, 6, 6, 1, 6, + 16, 16, 16, 8, 7, 6, 7, 6, + 8, 6, 15, 15, 15, 15, 14, 16, + 15, 15, 14, 16, 6, 1, 6, 16, + 16, 8, 7, 6, 7, 6, 6, 8, + 6, 15, 15, 5, 15, 15, 14, 16, + 15, 16, 6, 1, 6, 16, 16, 8, + 7, 6, 15, 7, 6, 6, 8, 6, + 15, 10, 5, 15, 15, 14, 16, 15, + 16, 6, 1, 6, 16, 16, 8, 7, + 6, 15, 7, 6, 6, 8, 6, 17, + 15, 17, 10, 6, 1, 6, 16, 8, + 6, 6, 1, 6, 16 }; static const short _indic_syllable_machine_index_offsets[] = { - 0, 2, 8, 12, 14, 19, 23, 25, - 30, 34, 36, 41, 45, 47, 53, 55, - 57, 63, 65, 67, 73, 75, 77, 83, - 85, 87, 98, 104, 115, 121, 132, 138, - 149, 155, 166, 168, 174, 178, 180, 185, - 189, 191, 196, 200, 202, 207, 211, 213, - 219, 221, 223, 229, 231, 233, 239, 241, - 243, 249, 251, 253, 264, 270, 281, 287, - 298, 304, 315, 321, 332, 334, 340, 344, - 346, 351, 355, 357, 362, 366, 368, 373, - 377, 379, 385, 387, 389, 395, 397, 399, - 405, 407, 409, 415, 417, 419, 430, 436, - 447, 453, 464, 470, 481, 487, 489, 495, - 499, 501, 506, 510, 512, 517, 521, 523, - 528, 532, 534, 540, 542, 544, 550, 552, - 554, 560, 562, 564, 570, 572, 574, 585, - 591, 602, 608, 619, 625, 636, 642, 653, - 664, 669, 671, 691, 703, 712, 720, 737, - 749, 758, 766, 783, 795, 804, 812, 829, - 841, 850, 858, 875, 887, 896, 904, 911, - 918, 925, 927, 929, 931, 938, 947, 954, - 963, 971, 978, 987, 995, 1002, 1011, 1019, - 1026, 1035, 1043, 1052, 1064, 1081, 1098, 1115, - 1124, 1136, 1153, 1170, 1187, 1196, 1208, 1225, - 1242, 1259, 1268, 1280, 1297, 1314, 1331, 1340, - 1352, 1364, 1373, 1381, 1398, 1410, 1419, 1427, - 1444, 1456, 1465, 1473, 1490, 1502, 1511, 1519, - 1536, 1548, 1557, 1565, 1572, 1579, 1586, 1588, - 1590, 1592, 1599, 1608, 1615, 1624, 1632, 1639, - 1648, 1656, 1663, 1672, 1680, 1687, 1696, 1704, - 1713, 1725, 1742, 1759, 1776, 1785, 1797, 1814, - 1831, 1848, 1857, 1869, 1886, 1903, 1920, 1929, - 1941, 1958, 1975, 1992, 1998, 2007, 2016, 2024, - 2041, 2053, 2062, 2070, 2087, 2099, 2108, 2116, - 2133, 2145, 2154, 2162, 2179, 2191, 2200, 2208, - 2215, 2222, 2229, 2231, 2233, 2235, 2242, 2251, - 2258, 2267, 2275, 2282, 2291, 2299, 2306, 2315, - 2323, 2330, 2339, 2347, 2356, 2368, 2385, 2402, - 2419, 2428, 2440, 2457, 2474, 2491, 2500, 2512, - 2529, 2546, 2563, 2572, 2584, 2601, 2618, 2635, - 2646, 2655, 2661, 2673, 2682, 2690, 2707, 2719, - 2728, 2736, 2753, 2765, 2774, 2782, 2799, 2811, - 2820, 2828, 2845, 2857, 2866, 2874, 2881, 2888, - 2895, 2897, 2899, 2901, 2908, 2917, 2924, 2933, - 2941, 2948, 2957, 2965, 2972, 2981, 2989, 2996, - 3005, 3013, 3022, 3034, 3051, 3068, 3085, 3094, - 3106, 3123, 3140, 3157, 3166, 3178, 3195, 3212, - 3229, 3238, 3250, 3267, 3284, 3301, 3310, 3327, - 3339, 3356, 3367, 3374, 3376, 3378, 3380, 3387, - 3404, 3413, 3420, 3427, 3429, 3431, 3433, 3440 + 0, 2, 8, 12, 17, 23, 25, 27, + 33, 44, 50, 52, 56, 61, 67, 69, + 71, 77, 88, 99, 110, 112, 116, 121, + 127, 129, 131, 137, 143, 154, 156, 160, + 165, 171, 173, 175, 181, 187, 192, 194, + 214, 230, 246, 261, 278, 285, 292, 294, + 301, 318, 335, 352, 361, 369, 376, 384, + 391, 400, 407, 423, 439, 455, 471, 486, + 503, 519, 535, 550, 567, 574, 576, 583, + 600, 617, 626, 634, 641, 649, 656, 663, + 672, 679, 695, 711, 717, 733, 749, 764, + 781, 797, 814, 821, 823, 830, 847, 864, + 873, 881, 888, 904, 912, 919, 926, 935, + 942, 958, 969, 975, 991, 1007, 1022, 1039, + 1055, 1072, 1079, 1081, 1088, 1105, 1122, 1131, + 1139, 1146, 1162, 1170, 1177, 1184, 1193, 1200, + 1218, 1234, 1252, 1263, 1270, 1272, 1279, 1296, + 1305, 1312, 1319, 1321, 1328 }; -static const short _indic_syllable_machine_indicies[] = { +static const unsigned char _indic_syllable_machine_indicies[] = { 1, 0, 2, 3, 3, 4, 1, 0, - 5, 5, 4, 0, 4, 0, 6, 6, - 7, 1, 0, 8, 8, 7, 0, 7, - 0, 9, 9, 10, 1, 0, 11, 11, - 10, 0, 10, 0, 12, 12, 13, 1, - 0, 14, 14, 13, 0, 13, 0, 15, - 0, 0, 0, 1, 0, 16, 0, 17, - 0, 18, 12, 12, 13, 1, 0, 19, - 0, 20, 0, 21, 9, 9, 10, 1, - 0, 22, 0, 23, 0, 24, 6, 6, - 7, 1, 0, 25, 0, 26, 0, 2, - 3, 3, 4, 1, 0, 0, 0, 0, - 27, 0, 28, 3, 3, 4, 1, 0, - 28, 3, 3, 4, 1, 0, 0, 0, - 0, 29, 0, 30, 3, 3, 4, 1, - 0, 30, 3, 3, 4, 1, 0, 0, - 0, 0, 31, 0, 32, 3, 3, 4, - 1, 0, 32, 3, 3, 4, 1, 0, - 0, 0, 0, 33, 0, 34, 3, 3, - 4, 1, 0, 34, 3, 3, 4, 1, - 0, 0, 0, 0, 35, 0, 37, 36, - 38, 39, 39, 40, 37, 36, 41, 41, - 40, 36, 40, 36, 42, 42, 43, 37, - 36, 44, 44, 43, 36, 43, 36, 45, - 45, 46, 37, 36, 47, 47, 46, 36, - 46, 36, 48, 48, 49, 37, 36, 50, - 50, 49, 36, 49, 36, 51, 36, 36, - 36, 37, 36, 52, 36, 53, 36, 54, - 48, 48, 49, 37, 36, 55, 36, 56, - 36, 57, 45, 45, 46, 37, 36, 58, - 36, 59, 36, 60, 42, 42, 43, 37, - 36, 61, 36, 62, 36, 38, 39, 39, - 40, 37, 36, 36, 36, 36, 63, 36, - 64, 39, 39, 40, 37, 36, 64, 39, - 39, 40, 37, 36, 36, 36, 36, 65, - 36, 66, 39, 39, 40, 37, 36, 66, - 39, 39, 40, 37, 36, 36, 36, 36, - 67, 36, 68, 39, 39, 40, 37, 36, - 68, 39, 39, 40, 37, 36, 36, 36, - 36, 69, 36, 70, 39, 39, 40, 37, - 36, 70, 39, 39, 40, 37, 36, 36, - 36, 36, 71, 36, 73, 72, 74, 75, - 75, 76, 73, 72, 78, 78, 76, 77, - 76, 77, 79, 79, 80, 73, 72, 81, - 81, 80, 72, 80, 72, 82, 82, 83, - 73, 72, 84, 84, 83, 72, 83, 72, - 85, 85, 86, 73, 72, 87, 87, 86, - 72, 86, 72, 88, 72, 72, 72, 73, - 72, 89, 72, 90, 72, 91, 85, 85, - 86, 73, 72, 92, 72, 93, 72, 94, - 82, 82, 83, 73, 72, 95, 72, 96, - 72, 97, 79, 79, 80, 73, 72, 98, - 72, 99, 72, 74, 75, 75, 76, 73, - 72, 72, 72, 72, 100, 72, 101, 75, - 75, 76, 73, 72, 101, 75, 75, 76, - 73, 72, 72, 72, 72, 102, 72, 103, - 75, 75, 76, 73, 72, 103, 75, 75, - 76, 73, 72, 72, 72, 72, 104, 72, - 105, 75, 75, 76, 73, 72, 105, 75, - 75, 76, 73, 72, 72, 72, 72, 106, - 72, 107, 75, 75, 76, 73, 72, 109, - 108, 110, 111, 111, 112, 109, 108, 113, - 113, 112, 108, 112, 108, 114, 114, 115, - 109, 108, 116, 116, 115, 108, 115, 108, - 117, 117, 118, 109, 108, 119, 119, 118, - 108, 118, 108, 120, 120, 121, 109, 108, - 122, 122, 121, 108, 121, 108, 123, 108, - 108, 108, 109, 108, 124, 108, 125, 108, - 126, 120, 120, 121, 109, 108, 127, 108, - 128, 108, 129, 117, 117, 118, 109, 108, - 130, 108, 131, 108, 132, 114, 114, 115, - 109, 108, 133, 108, 134, 108, 110, 111, - 111, 112, 109, 108, 108, 108, 108, 135, - 108, 136, 111, 111, 112, 109, 108, 136, - 111, 111, 112, 109, 108, 108, 108, 108, - 137, 108, 138, 111, 111, 112, 109, 108, - 138, 111, 111, 112, 109, 108, 108, 108, - 108, 139, 108, 140, 111, 111, 112, 109, - 108, 140, 111, 111, 112, 109, 108, 108, - 108, 108, 141, 108, 142, 111, 111, 112, - 109, 108, 142, 111, 111, 112, 109, 108, - 108, 108, 108, 143, 108, 107, 75, 75, - 76, 73, 72, 72, 72, 72, 144, 72, - 78, 78, 76, 1, 0, 146, 145, 148, - 149, 150, 151, 152, 153, 76, 73, 147, - 154, 155, 155, 144, 147, 156, 157, 147, - 158, 159, 147, 161, 162, 163, 164, 4, - 1, 160, 165, 160, 160, 35, 160, 166, - 162, 167, 167, 4, 1, 160, 165, 160, - 162, 167, 167, 4, 1, 160, 165, 160, - 168, 160, 160, 160, 17, 169, 160, 1, - 160, 165, 160, 160, 160, 160, 160, 168, - 160, 170, 171, 172, 173, 4, 1, 160, - 165, 160, 160, 33, 160, 174, 171, 175, - 175, 4, 1, 160, 165, 160, 171, 175, - 175, 4, 1, 160, 165, 160, 176, 160, - 160, 160, 17, 177, 160, 1, 160, 165, - 160, 160, 160, 160, 160, 176, 160, 178, - 179, 180, 181, 4, 1, 160, 165, 160, - 160, 31, 160, 182, 179, 183, 183, 4, - 1, 160, 165, 160, 179, 183, 183, 4, - 1, 160, 165, 160, 184, 160, 160, 160, - 17, 185, 160, 1, 160, 165, 160, 160, - 160, 160, 160, 184, 160, 186, 187, 188, - 189, 4, 1, 160, 165, 160, 160, 29, - 160, 190, 187, 191, 191, 4, 1, 160, - 165, 160, 187, 191, 191, 4, 1, 160, - 165, 160, 192, 160, 160, 160, 17, 193, - 160, 1, 160, 165, 160, 160, 160, 160, - 160, 192, 160, 194, 195, 196, 197, 4, - 1, 160, 165, 160, 160, 27, 160, 198, - 195, 199, 199, 4, 1, 160, 165, 160, - 195, 199, 199, 4, 1, 160, 165, 160, - 17, 200, 160, 1, 160, 165, 160, 201, - 201, 160, 1, 160, 165, 160, 202, 160, - 160, 203, 160, 165, 160, 165, 160, 204, - 160, 205, 160, 202, 160, 160, 160, 160, - 165, 160, 17, 160, 201, 201, 160, 1, - 160, 165, 160, 201, 200, 160, 1, 160, - 165, 160, 206, 26, 207, 208, 7, 1, - 160, 165, 160, 26, 207, 208, 7, 1, - 160, 165, 160, 207, 207, 7, 1, 160, - 165, 160, 209, 23, 210, 211, 10, 1, - 160, 165, 160, 23, 210, 211, 10, 1, - 160, 165, 160, 210, 210, 10, 1, 160, - 165, 160, 212, 20, 213, 214, 13, 1, - 160, 165, 160, 20, 213, 214, 13, 1, - 160, 165, 160, 213, 213, 13, 1, 160, - 165, 160, 215, 17, 201, 216, 160, 1, - 160, 165, 160, 17, 201, 216, 160, 1, - 160, 165, 160, 194, 195, 199, 199, 4, - 1, 160, 165, 160, 194, 195, 196, 199, - 4, 1, 160, 165, 160, 160, 27, 160, - 192, 160, 217, 160, 201, 201, 160, 1, - 160, 165, 160, 160, 160, 160, 160, 192, - 160, 192, 160, 160, 160, 201, 201, 160, - 1, 160, 165, 160, 160, 160, 160, 160, - 192, 160, 192, 160, 160, 160, 201, 193, - 160, 1, 160, 165, 160, 160, 160, 160, - 160, 192, 160, 186, 187, 191, 191, 4, - 1, 160, 165, 160, 186, 187, 188, 191, - 4, 1, 160, 165, 160, 160, 29, 160, - 184, 160, 218, 160, 201, 201, 160, 1, - 160, 165, 160, 160, 160, 160, 160, 184, - 160, 184, 160, 160, 160, 201, 201, 160, - 1, 160, 165, 160, 160, 160, 160, 160, - 184, 160, 184, 160, 160, 160, 201, 185, - 160, 1, 160, 165, 160, 160, 160, 160, - 160, 184, 160, 178, 179, 183, 183, 4, - 1, 160, 165, 160, 178, 179, 180, 183, - 4, 1, 160, 165, 160, 160, 31, 160, - 176, 160, 219, 160, 201, 201, 160, 1, - 160, 165, 160, 160, 160, 160, 160, 176, - 160, 176, 160, 160, 160, 201, 201, 160, - 1, 160, 165, 160, 160, 160, 160, 160, - 176, 160, 176, 160, 160, 160, 201, 177, - 160, 1, 160, 165, 160, 160, 160, 160, - 160, 176, 160, 170, 171, 175, 175, 4, - 1, 160, 165, 160, 170, 171, 172, 175, - 4, 1, 160, 165, 160, 160, 33, 160, - 168, 160, 220, 160, 201, 201, 160, 1, - 160, 165, 160, 160, 160, 160, 160, 168, - 160, 168, 160, 160, 160, 201, 201, 160, - 1, 160, 165, 160, 160, 160, 160, 160, - 168, 160, 168, 160, 160, 160, 201, 169, - 160, 1, 160, 165, 160, 160, 160, 160, - 160, 168, 160, 161, 162, 167, 167, 4, - 1, 160, 165, 160, 161, 162, 163, 167, - 4, 1, 160, 165, 160, 160, 35, 160, - 222, 223, 224, 225, 40, 37, 221, 226, - 221, 221, 71, 221, 227, 223, 228, 225, - 40, 37, 221, 226, 221, 223, 228, 225, - 40, 37, 221, 226, 221, 229, 221, 221, - 221, 53, 230, 221, 37, 221, 226, 221, - 221, 221, 221, 221, 229, 221, 231, 232, - 233, 234, 40, 37, 221, 226, 221, 221, - 69, 221, 235, 232, 236, 236, 40, 37, - 221, 226, 221, 232, 236, 236, 40, 37, - 221, 226, 221, 237, 221, 221, 221, 53, - 238, 221, 37, 221, 226, 221, 221, 221, - 221, 221, 237, 221, 239, 240, 241, 242, - 40, 37, 221, 226, 221, 221, 67, 221, - 243, 240, 244, 244, 40, 37, 221, 226, - 221, 240, 244, 244, 40, 37, 221, 226, - 221, 245, 221, 221, 221, 53, 246, 221, - 37, 221, 226, 221, 221, 221, 221, 221, - 245, 221, 247, 248, 249, 250, 40, 37, - 221, 226, 221, 221, 65, 221, 251, 248, - 252, 252, 40, 37, 221, 226, 221, 248, - 252, 252, 40, 37, 221, 226, 221, 253, - 221, 221, 221, 53, 254, 221, 37, 221, - 226, 221, 221, 221, 221, 221, 253, 221, - 255, 256, 257, 258, 40, 37, 221, 226, - 221, 221, 63, 221, 259, 256, 260, 260, - 40, 37, 221, 226, 221, 256, 260, 260, - 40, 37, 221, 226, 221, 53, 261, 221, - 37, 221, 226, 221, 262, 262, 221, 37, - 221, 226, 221, 263, 221, 221, 264, 221, - 226, 221, 226, 221, 265, 221, 266, 221, - 263, 221, 221, 221, 221, 226, 221, 53, - 221, 262, 262, 221, 37, 221, 226, 221, - 262, 261, 221, 37, 221, 226, 221, 267, - 62, 268, 269, 43, 37, 221, 226, 221, - 62, 268, 269, 43, 37, 221, 226, 221, - 268, 268, 43, 37, 221, 226, 221, 270, - 59, 271, 272, 46, 37, 221, 226, 221, - 59, 271, 272, 46, 37, 221, 226, 221, - 271, 271, 46, 37, 221, 226, 221, 273, - 56, 274, 275, 49, 37, 221, 226, 221, - 56, 274, 275, 49, 37, 221, 226, 221, - 274, 274, 49, 37, 221, 226, 221, 276, - 53, 262, 277, 221, 37, 221, 226, 221, - 53, 262, 277, 221, 37, 221, 226, 221, - 255, 256, 260, 260, 40, 37, 221, 226, - 221, 255, 256, 257, 260, 40, 37, 221, - 226, 221, 221, 63, 221, 253, 221, 278, - 221, 262, 262, 221, 37, 221, 226, 221, - 221, 221, 221, 221, 253, 221, 253, 221, - 221, 221, 262, 262, 221, 37, 221, 226, - 221, 221, 221, 221, 221, 253, 221, 253, - 221, 221, 221, 262, 254, 221, 37, 221, - 226, 221, 221, 221, 221, 221, 253, 221, - 247, 248, 252, 252, 40, 37, 221, 226, - 221, 247, 248, 249, 252, 40, 37, 221, - 226, 221, 221, 65, 221, 245, 221, 279, - 221, 262, 262, 221, 37, 221, 226, 221, - 221, 221, 221, 221, 245, 221, 245, 221, - 221, 221, 262, 262, 221, 37, 221, 226, - 221, 221, 221, 221, 221, 245, 221, 245, - 221, 221, 221, 262, 246, 221, 37, 221, - 226, 221, 221, 221, 221, 221, 245, 221, - 239, 240, 244, 244, 40, 37, 221, 226, - 221, 239, 240, 241, 244, 40, 37, 221, - 226, 221, 221, 67, 221, 237, 221, 280, - 221, 262, 262, 221, 37, 221, 226, 221, - 221, 221, 221, 221, 237, 221, 237, 221, - 221, 221, 262, 262, 221, 37, 221, 226, - 221, 221, 221, 221, 221, 237, 221, 237, - 221, 221, 221, 262, 238, 221, 37, 221, - 226, 221, 221, 221, 221, 221, 237, 221, - 231, 232, 236, 236, 40, 37, 221, 226, - 221, 231, 232, 233, 236, 40, 37, 221, - 226, 221, 221, 69, 221, 229, 221, 281, - 221, 262, 262, 221, 37, 221, 226, 221, - 221, 221, 221, 221, 229, 221, 229, 221, - 221, 221, 262, 262, 221, 37, 221, 226, - 221, 221, 221, 221, 221, 229, 221, 229, - 221, 221, 221, 262, 230, 221, 37, 221, - 226, 221, 221, 221, 221, 221, 229, 221, - 70, 39, 39, 40, 37, 221, 222, 223, - 228, 225, 40, 37, 221, 226, 221, 283, - 151, 284, 284, 76, 73, 282, 154, 282, - 151, 284, 284, 76, 73, 282, 154, 282, - 285, 282, 282, 282, 90, 286, 282, 73, - 282, 154, 282, 282, 282, 282, 282, 285, - 282, 287, 288, 289, 290, 76, 73, 282, - 154, 282, 282, 106, 282, 291, 288, 292, - 292, 76, 73, 282, 154, 282, 288, 292, - 292, 76, 73, 282, 154, 282, 293, 282, - 282, 282, 90, 294, 282, 73, 282, 154, - 282, 282, 282, 282, 282, 293, 282, 295, - 296, 297, 298, 76, 73, 282, 154, 282, - 282, 104, 282, 299, 296, 300, 300, 76, - 73, 282, 154, 282, 296, 300, 300, 76, - 73, 282, 154, 282, 301, 282, 282, 282, - 90, 302, 282, 73, 282, 154, 282, 282, - 282, 282, 282, 301, 282, 303, 304, 305, - 306, 76, 73, 282, 154, 282, 282, 102, - 282, 307, 304, 308, 308, 76, 73, 282, - 154, 282, 304, 308, 308, 76, 73, 282, - 154, 282, 309, 282, 282, 282, 90, 310, - 282, 73, 282, 154, 282, 282, 282, 282, - 282, 309, 282, 311, 312, 313, 314, 76, - 73, 282, 154, 282, 282, 100, 282, 315, - 312, 316, 316, 76, 73, 282, 154, 282, - 312, 316, 316, 76, 73, 282, 154, 282, - 90, 317, 282, 73, 282, 154, 282, 318, - 318, 282, 73, 282, 154, 282, 319, 282, - 282, 320, 282, 154, 282, 154, 282, 321, - 282, 322, 282, 319, 282, 282, 282, 282, - 154, 282, 90, 282, 318, 318, 282, 73, - 282, 154, 282, 318, 317, 282, 73, 282, - 154, 282, 323, 99, 324, 325, 80, 73, - 282, 154, 282, 99, 324, 325, 80, 73, - 282, 154, 282, 324, 324, 80, 73, 282, - 154, 282, 326, 96, 327, 328, 83, 73, - 282, 154, 282, 96, 327, 328, 83, 73, - 282, 154, 282, 327, 327, 83, 73, 282, - 154, 282, 329, 93, 330, 331, 86, 73, - 282, 154, 282, 93, 330, 331, 86, 73, - 282, 154, 282, 330, 330, 86, 73, 282, - 154, 282, 332, 90, 318, 333, 282, 73, - 282, 154, 282, 90, 318, 333, 282, 73, - 282, 154, 282, 311, 312, 316, 316, 76, - 73, 282, 154, 282, 311, 312, 313, 316, - 76, 73, 282, 154, 282, 282, 100, 282, - 309, 282, 334, 282, 318, 318, 282, 73, - 282, 154, 282, 282, 282, 282, 282, 309, - 282, 309, 282, 282, 282, 318, 318, 282, - 73, 282, 154, 282, 282, 282, 282, 282, - 309, 282, 309, 282, 282, 282, 318, 310, - 282, 73, 282, 154, 282, 282, 282, 282, - 282, 309, 282, 303, 304, 308, 308, 76, - 73, 282, 154, 282, 303, 304, 305, 308, - 76, 73, 282, 154, 282, 282, 102, 282, - 301, 282, 335, 282, 318, 318, 282, 73, - 282, 154, 282, 282, 282, 282, 282, 301, - 282, 301, 282, 282, 282, 318, 318, 282, - 73, 282, 154, 282, 282, 282, 282, 282, - 301, 282, 301, 282, 282, 282, 318, 302, - 282, 73, 282, 154, 282, 282, 282, 282, - 282, 301, 282, 295, 296, 300, 300, 76, - 73, 282, 154, 282, 295, 296, 297, 300, - 76, 73, 282, 154, 282, 282, 104, 282, - 293, 282, 336, 282, 318, 318, 282, 73, - 282, 154, 282, 282, 282, 282, 282, 293, - 282, 293, 282, 282, 282, 318, 318, 282, - 73, 282, 154, 282, 282, 282, 282, 282, - 293, 282, 293, 282, 282, 282, 318, 294, - 282, 73, 282, 154, 282, 282, 282, 282, - 282, 293, 282, 287, 288, 292, 292, 76, - 73, 282, 154, 282, 287, 288, 289, 292, - 76, 73, 282, 154, 282, 282, 106, 282, - 285, 282, 337, 282, 318, 318, 282, 73, - 282, 154, 282, 282, 282, 282, 282, 285, - 282, 285, 282, 282, 282, 318, 318, 282, - 73, 282, 154, 282, 282, 282, 282, 282, - 285, 282, 285, 282, 282, 282, 318, 286, - 282, 73, 282, 154, 282, 282, 282, 282, - 282, 285, 282, 107, 75, 75, 76, 73, - 338, 338, 338, 338, 144, 338, 150, 151, - 284, 284, 76, 73, 282, 154, 282, 107, - 75, 75, 76, 73, 338, 340, 341, 342, - 343, 112, 109, 339, 344, 339, 339, 143, - 339, 345, 341, 343, 343, 112, 109, 339, - 344, 339, 341, 343, 343, 112, 109, 339, - 344, 339, 346, 339, 339, 339, 125, 347, - 339, 109, 339, 344, 339, 339, 339, 339, - 339, 346, 339, 348, 349, 350, 351, 112, - 109, 339, 344, 339, 339, 141, 339, 352, - 349, 353, 353, 112, 109, 339, 344, 339, - 349, 353, 353, 112, 109, 339, 344, 339, - 354, 339, 339, 339, 125, 355, 339, 109, - 339, 344, 339, 339, 339, 339, 339, 354, - 339, 356, 357, 358, 359, 112, 109, 339, - 344, 339, 339, 139, 339, 360, 357, 361, - 361, 112, 109, 339, 344, 339, 357, 361, - 361, 112, 109, 339, 344, 339, 362, 339, - 339, 339, 125, 363, 339, 109, 339, 344, - 339, 339, 339, 339, 339, 362, 339, 364, - 365, 366, 367, 112, 109, 339, 344, 339, - 339, 137, 339, 368, 365, 369, 369, 112, - 109, 339, 344, 339, 365, 369, 369, 112, - 109, 339, 344, 339, 370, 339, 339, 339, - 125, 371, 339, 109, 339, 344, 339, 339, - 339, 339, 339, 370, 339, 372, 373, 374, - 375, 112, 109, 339, 344, 339, 339, 135, - 339, 376, 373, 377, 377, 112, 109, 339, - 344, 339, 373, 377, 377, 112, 109, 339, - 344, 339, 125, 378, 339, 109, 339, 344, - 339, 379, 379, 339, 109, 339, 344, 339, - 380, 339, 339, 381, 339, 344, 339, 344, - 339, 382, 339, 383, 339, 380, 339, 339, - 339, 339, 344, 339, 125, 339, 379, 379, - 339, 109, 339, 344, 339, 379, 378, 339, - 109, 339, 344, 339, 384, 134, 385, 386, - 115, 109, 339, 344, 339, 134, 385, 386, - 115, 109, 339, 344, 339, 385, 385, 115, - 109, 339, 344, 339, 387, 131, 388, 389, - 118, 109, 339, 344, 339, 131, 388, 389, - 118, 109, 339, 344, 339, 388, 388, 118, - 109, 339, 344, 339, 390, 128, 391, 392, - 121, 109, 339, 344, 339, 128, 391, 392, - 121, 109, 339, 344, 339, 391, 391, 121, - 109, 339, 344, 339, 393, 125, 379, 394, - 339, 109, 339, 344, 339, 125, 379, 394, - 339, 109, 339, 344, 339, 372, 373, 377, - 377, 112, 109, 339, 344, 339, 372, 373, - 374, 377, 112, 109, 339, 344, 339, 339, - 135, 339, 370, 339, 395, 339, 379, 379, - 339, 109, 339, 344, 339, 339, 339, 339, - 339, 370, 339, 370, 339, 339, 339, 379, - 379, 339, 109, 339, 344, 339, 339, 339, - 339, 339, 370, 339, 370, 339, 339, 339, - 379, 371, 339, 109, 339, 344, 339, 339, - 339, 339, 339, 370, 339, 364, 365, 369, - 369, 112, 109, 339, 344, 339, 364, 365, - 366, 369, 112, 109, 339, 344, 339, 339, - 137, 339, 362, 339, 396, 339, 379, 379, - 339, 109, 339, 344, 339, 339, 339, 339, - 339, 362, 339, 362, 339, 339, 339, 379, - 379, 339, 109, 339, 344, 339, 339, 339, - 339, 339, 362, 339, 362, 339, 339, 339, - 379, 363, 339, 109, 339, 344, 339, 339, - 339, 339, 339, 362, 339, 356, 357, 361, - 361, 112, 109, 339, 344, 339, 356, 357, - 358, 361, 112, 109, 339, 344, 339, 339, - 139, 339, 354, 339, 397, 339, 379, 379, - 339, 109, 339, 344, 339, 339, 339, 339, - 339, 354, 339, 354, 339, 339, 339, 379, - 379, 339, 109, 339, 344, 339, 339, 339, - 339, 339, 354, 339, 354, 339, 339, 339, - 379, 355, 339, 109, 339, 344, 339, 339, - 339, 339, 339, 354, 339, 348, 349, 353, - 353, 112, 109, 339, 344, 339, 348, 349, - 350, 353, 112, 109, 339, 344, 339, 339, - 141, 339, 346, 339, 398, 339, 379, 379, - 339, 109, 339, 344, 339, 339, 339, 339, - 339, 346, 339, 346, 339, 339, 339, 379, - 379, 339, 109, 339, 344, 339, 339, 339, - 339, 339, 346, 339, 346, 339, 339, 339, - 379, 347, 339, 109, 339, 344, 339, 339, - 339, 339, 339, 346, 339, 340, 341, 343, - 343, 112, 109, 339, 344, 339, 148, 149, - 150, 151, 399, 284, 76, 73, 282, 154, - 155, 155, 144, 282, 282, 148, 282, 161, - 400, 163, 164, 4, 1, 160, 165, 160, - 160, 35, 160, 168, 149, 150, 151, 401, - 402, 76, 403, 160, 404, 160, 155, 144, - 160, 160, 168, 160, 107, 405, 405, 76, - 403, 160, 165, 160, 160, 144, 160, 406, - 160, 160, 407, 160, 404, 160, 404, 160, - 408, 160, 205, 160, 406, 160, 160, 160, - 160, 404, 160, 168, 160, 220, 107, 405, - 405, 76, 403, 160, 165, 160, 160, 160, - 160, 160, 168, 160, 410, 409, 411, 411, - 409, 146, 409, 412, 409, 411, 411, 409, - 146, 409, 412, 409, 413, 409, 409, 414, - 409, 412, 409, 412, 409, 415, 409, 416, - 409, 413, 409, 409, 409, 409, 412, 409, - 148, 338, 338, 338, 338, 338, 338, 338, - 338, 338, 155, 338, 338, 338, 338, 148, - 338, 0 + 3, 3, 4, 0, 3, 3, 4, 1, + 0, 5, 3, 3, 4, 1, 0, 6, + 0, 7, 0, 8, 3, 3, 4, 1, + 0, 2, 3, 3, 4, 1, 0, 0, + 0, 0, 9, 0, 11, 12, 12, 13, + 14, 10, 14, 10, 12, 12, 13, 10, + 12, 12, 13, 14, 10, 15, 12, 12, + 13, 14, 10, 16, 10, 17, 10, 18, + 12, 12, 13, 14, 10, 11, 12, 12, + 13, 14, 10, 10, 10, 10, 19, 10, + 11, 12, 12, 13, 14, 10, 10, 10, + 10, 20, 10, 22, 23, 23, 24, 25, + 21, 21, 21, 21, 26, 21, 25, 21, + 23, 23, 24, 27, 23, 23, 24, 25, + 21, 28, 23, 23, 24, 25, 21, 29, + 21, 30, 21, 22, 23, 23, 24, 25, + 21, 31, 23, 23, 24, 25, 21, 33, + 34, 34, 35, 36, 32, 32, 32, 32, + 37, 32, 36, 32, 34, 34, 35, 32, + 34, 34, 35, 36, 32, 38, 34, 34, + 35, 36, 32, 39, 32, 40, 32, 33, + 34, 34, 35, 36, 32, 41, 34, 34, + 35, 36, 32, 23, 23, 24, 1, 0, + 43, 42, 45, 46, 47, 48, 49, 50, + 24, 25, 44, 51, 52, 52, 26, 44, + 53, 54, 55, 56, 57, 44, 59, 60, + 61, 62, 4, 1, 58, 63, 58, 58, + 9, 58, 58, 58, 64, 58, 65, 60, + 66, 66, 4, 1, 58, 63, 58, 58, + 58, 58, 58, 58, 64, 58, 60, 66, + 66, 4, 1, 58, 63, 58, 58, 58, + 58, 58, 58, 64, 58, 45, 58, 58, + 58, 67, 68, 58, 1, 58, 63, 58, + 58, 58, 58, 58, 45, 58, 69, 69, + 58, 1, 58, 63, 58, 63, 58, 58, + 70, 58, 63, 58, 63, 58, 63, 58, + 58, 58, 58, 63, 58, 45, 58, 71, + 58, 69, 69, 58, 1, 58, 63, 58, + 58, 58, 58, 58, 45, 58, 45, 58, + 58, 58, 69, 69, 58, 1, 58, 63, + 58, 58, 58, 58, 58, 45, 58, 45, + 58, 58, 58, 69, 68, 58, 1, 58, + 63, 58, 58, 58, 58, 58, 45, 58, + 72, 7, 73, 74, 4, 1, 58, 63, + 58, 7, 73, 74, 4, 1, 58, 63, + 58, 73, 73, 4, 1, 58, 63, 58, + 75, 76, 76, 4, 1, 58, 63, 58, + 67, 77, 58, 1, 58, 63, 58, 67, + 58, 69, 69, 58, 1, 58, 63, 58, + 69, 77, 58, 1, 58, 63, 58, 59, + 60, 66, 66, 4, 1, 58, 63, 58, + 58, 58, 58, 58, 58, 64, 58, 59, + 60, 61, 66, 4, 1, 58, 63, 58, + 58, 9, 58, 58, 58, 64, 58, 79, + 80, 81, 82, 13, 14, 78, 83, 78, + 78, 20, 78, 78, 78, 84, 78, 85, + 80, 86, 82, 13, 14, 78, 83, 78, + 78, 78, 78, 78, 78, 84, 78, 80, + 86, 82, 13, 14, 78, 83, 78, 78, + 78, 78, 78, 78, 84, 78, 87, 78, + 78, 78, 88, 89, 78, 14, 78, 83, + 78, 78, 78, 78, 78, 87, 78, 90, + 80, 91, 92, 13, 14, 78, 83, 78, + 78, 19, 78, 78, 78, 84, 78, 93, + 80, 86, 86, 13, 14, 78, 83, 78, + 78, 78, 78, 78, 78, 84, 78, 80, + 86, 86, 13, 14, 78, 83, 78, 78, + 78, 78, 78, 78, 84, 78, 87, 78, + 78, 78, 94, 89, 78, 14, 78, 83, + 78, 78, 78, 78, 78, 87, 78, 83, + 78, 78, 95, 78, 83, 78, 83, 78, + 83, 78, 78, 78, 78, 83, 78, 87, + 78, 96, 78, 94, 94, 78, 14, 78, + 83, 78, 78, 78, 78, 78, 87, 78, + 87, 78, 78, 78, 94, 94, 78, 14, + 78, 83, 78, 78, 78, 78, 78, 87, + 78, 97, 17, 98, 99, 13, 14, 78, + 83, 78, 17, 98, 99, 13, 14, 78, + 83, 78, 98, 98, 13, 14, 78, 83, + 78, 100, 101, 101, 13, 14, 78, 83, + 78, 88, 102, 78, 14, 78, 83, 78, + 94, 94, 78, 14, 78, 83, 78, 88, + 78, 94, 94, 78, 14, 78, 83, 78, + 94, 102, 78, 14, 78, 83, 78, 90, + 80, 86, 86, 13, 14, 78, 83, 78, + 78, 78, 78, 78, 78, 84, 78, 90, + 80, 91, 86, 13, 14, 78, 83, 78, + 78, 19, 78, 78, 78, 84, 78, 11, + 12, 12, 13, 14, 78, 79, 80, 86, + 82, 13, 14, 78, 83, 78, 78, 78, + 78, 78, 78, 84, 78, 104, 48, 105, + 105, 24, 25, 103, 51, 103, 103, 103, + 103, 103, 103, 55, 103, 48, 105, 105, + 24, 25, 103, 51, 103, 103, 103, 103, + 103, 103, 55, 103, 106, 103, 103, 103, + 107, 108, 103, 25, 103, 51, 103, 103, + 103, 103, 103, 106, 103, 47, 48, 109, + 110, 24, 25, 103, 51, 103, 103, 26, + 103, 103, 103, 55, 103, 106, 103, 103, + 103, 111, 108, 103, 25, 103, 51, 103, + 103, 103, 103, 103, 106, 103, 51, 103, + 103, 112, 103, 51, 103, 51, 103, 51, + 103, 103, 103, 103, 51, 103, 106, 103, + 113, 103, 111, 111, 103, 25, 103, 51, + 103, 103, 103, 103, 103, 106, 103, 106, + 103, 103, 103, 111, 111, 103, 25, 103, + 51, 103, 103, 103, 103, 103, 106, 103, + 114, 30, 115, 116, 24, 25, 103, 51, + 103, 30, 115, 116, 24, 25, 103, 51, + 103, 115, 115, 24, 25, 103, 51, 103, + 47, 48, 105, 105, 24, 25, 103, 51, + 103, 103, 103, 103, 103, 103, 55, 103, + 117, 118, 118, 24, 25, 103, 51, 103, + 107, 119, 103, 25, 103, 51, 103, 111, + 111, 103, 25, 103, 51, 103, 107, 103, + 111, 111, 103, 25, 103, 51, 103, 111, + 119, 103, 25, 103, 51, 103, 47, 48, + 109, 105, 24, 25, 103, 51, 103, 103, + 26, 103, 103, 103, 55, 103, 22, 23, + 23, 24, 25, 120, 120, 120, 120, 26, + 120, 22, 23, 23, 24, 25, 120, 122, + 123, 124, 125, 35, 36, 121, 126, 121, + 121, 37, 121, 121, 121, 127, 121, 128, + 123, 125, 125, 35, 36, 121, 126, 121, + 121, 121, 121, 121, 121, 127, 121, 123, + 125, 125, 35, 36, 121, 126, 121, 121, + 121, 121, 121, 121, 127, 121, 129, 121, + 121, 121, 130, 131, 121, 36, 121, 126, + 121, 121, 121, 121, 121, 129, 121, 122, + 123, 124, 52, 35, 36, 121, 126, 121, + 121, 37, 121, 121, 121, 127, 121, 129, + 121, 121, 121, 132, 131, 121, 36, 121, + 126, 121, 121, 121, 121, 121, 129, 121, + 126, 121, 121, 133, 121, 126, 121, 126, + 121, 126, 121, 121, 121, 121, 126, 121, + 129, 121, 134, 121, 132, 132, 121, 36, + 121, 126, 121, 121, 121, 121, 121, 129, + 121, 129, 121, 121, 121, 132, 132, 121, + 36, 121, 126, 121, 121, 121, 121, 121, + 129, 121, 135, 40, 136, 137, 35, 36, + 121, 126, 121, 40, 136, 137, 35, 36, + 121, 126, 121, 136, 136, 35, 36, 121, + 126, 121, 122, 123, 125, 125, 35, 36, + 121, 126, 121, 121, 121, 121, 121, 121, + 127, 121, 138, 139, 139, 35, 36, 121, + 126, 121, 130, 140, 121, 36, 121, 126, + 121, 132, 132, 121, 36, 121, 126, 121, + 130, 121, 132, 132, 121, 36, 121, 126, + 121, 132, 140, 121, 36, 121, 126, 121, + 45, 46, 47, 48, 109, 105, 24, 25, + 103, 51, 52, 52, 26, 103, 103, 45, + 55, 103, 59, 141, 61, 62, 4, 1, + 58, 63, 58, 58, 9, 58, 58, 58, + 64, 58, 45, 46, 47, 48, 142, 143, + 24, 144, 58, 145, 58, 52, 26, 58, + 58, 45, 55, 58, 22, 146, 146, 24, + 144, 58, 63, 58, 58, 26, 58, 145, + 58, 58, 147, 58, 145, 58, 145, 58, + 145, 58, 58, 58, 58, 145, 58, 45, + 58, 71, 22, 146, 146, 24, 144, 58, + 63, 58, 58, 58, 58, 58, 45, 58, + 149, 148, 150, 150, 148, 43, 148, 151, + 148, 150, 150, 148, 43, 148, 151, 148, + 151, 148, 148, 152, 148, 151, 148, 151, + 148, 151, 148, 148, 148, 148, 151, 148, + 45, 120, 120, 120, 120, 120, 120, 120, + 120, 120, 52, 120, 120, 120, 120, 45, + 120, 0 }; -static const short _indic_syllable_machine_trans_targs[] = { - 138, 160, 166, 2, 167, 3, 5, 170, - 6, 8, 173, 9, 11, 176, 12, 14, - 15, 159, 17, 18, 175, 20, 21, 172, - 23, 24, 169, 178, 182, 183, 187, 188, - 192, 193, 197, 198, 138, 221, 227, 36, - 228, 37, 39, 231, 40, 42, 234, 43, - 45, 237, 46, 48, 49, 220, 51, 52, - 236, 54, 55, 233, 57, 58, 230, 239, - 243, 244, 248, 249, 253, 254, 258, 260, - 138, 281, 287, 70, 288, 138, 71, 73, - 291, 74, 76, 294, 77, 79, 297, 80, - 82, 83, 280, 85, 86, 296, 88, 89, - 293, 91, 92, 290, 299, 303, 304, 308, - 309, 313, 314, 318, 138, 343, 349, 103, - 350, 104, 106, 353, 107, 109, 356, 110, - 112, 359, 113, 115, 116, 342, 118, 119, - 358, 121, 122, 355, 124, 125, 352, 361, - 365, 366, 370, 371, 375, 376, 380, 381, - 320, 138, 394, 138, 139, 200, 261, 263, - 319, 321, 283, 322, 382, 383, 392, 399, - 138, 140, 142, 33, 199, 162, 141, 32, - 143, 195, 144, 146, 31, 194, 145, 30, - 147, 190, 148, 150, 29, 189, 149, 28, - 151, 185, 152, 154, 27, 184, 153, 26, - 155, 180, 156, 158, 25, 179, 157, 1, - 165, 0, 161, 164, 163, 138, 168, 4, - 22, 171, 7, 19, 174, 10, 16, 177, - 13, 181, 186, 191, 196, 138, 201, 203, - 67, 259, 223, 202, 66, 204, 256, 205, - 207, 65, 255, 206, 64, 208, 251, 209, - 211, 63, 250, 210, 62, 212, 246, 213, - 215, 61, 245, 214, 60, 216, 241, 217, - 219, 59, 240, 218, 35, 226, 34, 222, - 225, 224, 138, 229, 38, 56, 232, 41, - 53, 235, 44, 50, 238, 47, 242, 247, - 252, 257, 138, 262, 100, 264, 316, 265, - 267, 99, 315, 266, 98, 268, 311, 269, - 271, 97, 310, 270, 96, 272, 306, 273, - 275, 95, 305, 274, 94, 276, 301, 277, - 279, 93, 300, 278, 69, 286, 68, 282, - 285, 284, 138, 289, 72, 90, 292, 75, - 87, 295, 78, 84, 298, 81, 302, 307, - 312, 317, 138, 138, 323, 325, 134, 133, - 345, 324, 326, 378, 327, 329, 132, 377, - 328, 131, 330, 373, 331, 333, 130, 372, - 332, 129, 334, 368, 335, 337, 128, 367, - 336, 127, 338, 363, 339, 341, 126, 362, - 340, 102, 348, 101, 344, 347, 346, 138, - 351, 105, 123, 354, 108, 120, 357, 111, - 117, 360, 114, 364, 369, 374, 379, 135, - 384, 385, 391, 386, 388, 136, 387, 390, - 389, 138, 393, 137, 396, 395, 398, 397, - 138 +static const unsigned char _indic_syllable_machine_trans_targs[] = { + 39, 45, 50, 2, 51, 5, 6, 53, + 57, 58, 39, 67, 11, 73, 68, 14, + 15, 75, 80, 81, 84, 39, 89, 21, + 95, 90, 98, 39, 24, 25, 97, 103, + 39, 112, 30, 118, 113, 121, 33, 34, + 120, 126, 39, 137, 39, 40, 60, 85, + 87, 105, 106, 91, 107, 127, 128, 99, + 135, 140, 39, 41, 43, 8, 59, 46, + 54, 42, 1, 44, 48, 0, 47, 49, + 52, 3, 4, 55, 7, 56, 39, 61, + 63, 18, 83, 69, 76, 62, 9, 64, + 78, 71, 65, 17, 82, 66, 10, 70, + 72, 74, 12, 13, 77, 16, 79, 39, + 86, 26, 88, 101, 93, 19, 104, 20, + 92, 94, 96, 22, 23, 100, 27, 102, + 39, 39, 108, 110, 28, 35, 114, 122, + 109, 111, 124, 116, 29, 115, 117, 119, + 31, 32, 123, 36, 125, 129, 130, 134, + 131, 132, 37, 133, 39, 136, 38, 138, + 139 }; static const char _indic_syllable_machine_trans_actions[] = { 1, 0, 2, 0, 2, 0, 0, 2, - 0, 0, 2, 0, 0, 2, 0, 0, - 0, 2, 0, 0, 2, 0, 0, 2, - 0, 0, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 0, 2, 0, - 2, 0, 0, 2, 0, 0, 2, 0, - 0, 2, 0, 0, 0, 2, 0, 0, - 2, 0, 0, 2, 0, 0, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 4, 0, 2, 0, 2, 5, 0, 0, - 2, 0, 0, 2, 0, 0, 2, 0, - 0, 0, 2, 0, 0, 2, 0, 0, - 2, 0, 0, 2, 6, 2, 6, 2, - 6, 2, 6, 2, 7, 0, 2, 0, - 2, 0, 0, 2, 0, 0, 2, 0, - 0, 2, 0, 0, 0, 2, 0, 0, - 2, 0, 0, 2, 0, 0, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 6, 8, 0, 11, 2, 2, 6, 0, - 12, 12, 0, 2, 6, 2, 2, 0, - 13, 2, 0, 0, 2, 0, 2, 0, - 2, 2, 2, 0, 0, 2, 2, 0, - 2, 2, 2, 0, 0, 2, 2, 0, - 2, 2, 2, 0, 0, 2, 2, 0, - 2, 2, 2, 0, 0, 2, 2, 0, - 2, 0, 0, 0, 0, 14, 2, 0, - 0, 2, 0, 0, 2, 0, 0, 2, - 0, 2, 2, 2, 2, 15, 2, 0, - 0, 2, 0, 2, 0, 2, 2, 2, - 0, 0, 2, 2, 0, 2, 2, 2, - 0, 0, 2, 2, 0, 2, 2, 2, - 0, 0, 2, 2, 0, 2, 2, 2, - 0, 0, 2, 2, 0, 2, 0, 0, - 0, 0, 16, 2, 0, 0, 2, 0, - 0, 2, 0, 0, 2, 0, 2, 2, - 2, 2, 17, 6, 0, 6, 2, 6, - 0, 0, 6, 6, 0, 6, 2, 6, - 0, 0, 6, 6, 0, 6, 2, 6, - 0, 0, 6, 6, 0, 6, 2, 6, - 0, 0, 6, 6, 0, 2, 0, 0, - 0, 0, 18, 2, 0, 0, 2, 0, - 0, 2, 0, 0, 2, 0, 2, 2, - 2, 2, 19, 20, 2, 0, 0, 0, - 0, 2, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 2, 2, 0, 0, 2, - 2, 0, 2, 0, 0, 0, 0, 21, - 2, 0, 0, 2, 0, 0, 2, 0, - 0, 2, 0, 2, 2, 2, 2, 0, - 0, 22, 22, 0, 0, 0, 0, 0, - 0, 23, 2, 0, 0, 0, 0, 0, - 24 + 2, 2, 3, 2, 0, 2, 0, 0, + 0, 2, 2, 2, 2, 4, 2, 0, + 5, 0, 5, 6, 0, 0, 5, 2, + 7, 2, 0, 2, 0, 2, 0, 0, + 2, 2, 8, 0, 11, 2, 2, 5, + 0, 12, 12, 0, 2, 5, 2, 5, + 2, 0, 13, 2, 0, 0, 2, 0, + 2, 2, 0, 2, 2, 0, 0, 2, + 2, 0, 0, 0, 0, 2, 14, 2, + 0, 0, 2, 0, 2, 2, 0, 2, + 2, 2, 2, 0, 2, 2, 0, 0, + 2, 2, 0, 0, 0, 0, 2, 15, + 5, 0, 5, 2, 2, 0, 5, 0, + 0, 2, 5, 0, 0, 0, 0, 2, + 16, 17, 2, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 0, 0, 2, 2, + 0, 0, 0, 0, 2, 0, 18, 18, + 0, 0, 0, 0, 19, 2, 0, 0, + 0 }; static const char _indic_syllable_machine_to_state_actions[] = { @@ -746,6 +319,7 @@ static const char _indic_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -758,40 +332,7 @@ static const char _indic_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 9, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0 }; static const char _indic_syllable_machine_from_state_actions[] = { @@ -799,6 +340,7 @@ static const char _indic_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -811,126 +353,61 @@ static const char _indic_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 10, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0 }; static const short _indic_syllable_machine_eof_trans[] = { 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 73, 73, 78, 78, - 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 109, 109, 109, - 109, 109, 109, 109, 109, 109, 109, 109, - 109, 109, 109, 109, 109, 109, 109, 109, - 109, 109, 109, 109, 109, 109, 109, 109, - 109, 109, 109, 109, 109, 109, 109, 73, - 1, 146, 0, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, - 161, 161, 161, 161, 161, 161, 161, 161, - 222, 222, 222, 222, 222, 222, 222, 222, - 222, 222, 222, 222, 222, 222, 222, 222, - 222, 222, 222, 222, 222, 222, 222, 222, - 222, 222, 222, 222, 222, 222, 222, 222, - 222, 222, 222, 222, 222, 222, 222, 222, - 222, 222, 222, 222, 222, 222, 222, 222, - 222, 222, 222, 222, 222, 222, 222, 222, - 222, 222, 222, 222, 222, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 283, - 283, 283, 283, 283, 283, 283, 283, 339, - 283, 339, 340, 340, 340, 340, 340, 340, - 340, 340, 340, 340, 340, 340, 340, 340, - 340, 340, 340, 340, 340, 340, 340, 340, - 340, 340, 340, 340, 340, 340, 340, 340, - 340, 340, 340, 340, 340, 340, 340, 340, - 340, 340, 340, 340, 340, 340, 340, 340, - 340, 340, 340, 340, 340, 340, 340, 340, - 340, 340, 340, 340, 340, 340, 283, 161, - 161, 161, 161, 161, 161, 161, 161, 161, - 410, 410, 410, 410, 410, 410, 410, 339 + 1, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 22, 22, 28, 22, 22, + 22, 22, 22, 22, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 1, 43, 0, + 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 104, 104, 104, + 104, 104, 104, 104, 104, 104, 104, 104, + 104, 104, 104, 104, 104, 104, 104, 104, + 104, 121, 121, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 122, + 122, 122, 122, 122, 122, 122, 122, 104, + 59, 59, 59, 59, 59, 59, 59, 149, + 149, 149, 149, 149, 121 }; -static const int indic_syllable_machine_start = 138; -static const int indic_syllable_machine_first_final = 138; +static const int indic_syllable_machine_start = 39; +static const int indic_syllable_machine_first_final = 39; static const int indic_syllable_machine_error = -1; -static const int indic_syllable_machine_en_main = 138; +static const int indic_syllable_machine_en_main = 39; #line 36 "hb-ot-shape-complex-indic-machine.rl" -#line 92 "hb-ot-shape-complex-indic-machine.rl" +#line 93 "hb-ot-shape-complex-indic-machine.rl" #define found_syllable(syllable_type) \ HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | indic_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_indic (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; -#line 934 "hb-ot-shape-complex-indic-machine.hh" +#line 411 "hb-ot-shape-complex-indic-machine.hh" { cs = indic_syllable_machine_start; ts = 0; @@ -938,7 +415,7 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 112 "hb-ot-shape-complex-indic-machine.rl" +#line 113 "hb-ot-shape-complex-indic-machine.rl" p = 0; @@ -946,12 +423,12 @@ find_syllables (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 950 "hb-ot-shape-complex-indic-machine.hh" +#line 427 "hb-ot-shape-complex-indic-machine.hh" { int _slen; int _trans; const unsigned char *_keys; - const short *_inds; + const unsigned char *_inds; if ( p == pe ) goto _test_eof; _resume: @@ -960,7 +437,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 964 "hb-ot-shape-complex-indic-machine.hh" +#line 441 "hb-ot-shape-complex-indic-machine.hh" } _keys = _indic_syllable_machine_trans_keys + (cs<<1); @@ -982,75 +459,55 @@ _eof_trans: #line 1 "NONE" {te = p+1;} break; - case 14: -#line 83 "hb-ot-shape-complex-indic-machine.rl" - {te = p+1;{ found_syllable (consonant_syllable); }} - break; - case 16: -#line 84 "hb-ot-shape-complex-indic-machine.rl" - {te = p+1;{ found_syllable (vowel_syllable); }} - break; - case 21: -#line 85 "hb-ot-shape-complex-indic-machine.rl" - {te = p+1;{ found_syllable (standalone_cluster); }} - break; - case 24: -#line 86 "hb-ot-shape-complex-indic-machine.rl" - {te = p+1;{ found_syllable (symbol_cluster); }} - break; - case 18: -#line 87 "hb-ot-shape-complex-indic-machine.rl" - {te = p+1;{ found_syllable (broken_cluster); }} - break; case 11: -#line 88 "hb-ot-shape-complex-indic-machine.rl" +#line 89 "hb-ot-shape-complex-indic-machine.rl" {te = p+1;{ found_syllable (non_indic_cluster); }} break; case 13: -#line 83 "hb-ot-shape-complex-indic-machine.rl" +#line 84 "hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (consonant_syllable); }} break; - case 15: -#line 84 "hb-ot-shape-complex-indic-machine.rl" + case 14: +#line 85 "hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (vowel_syllable); }} break; - case 20: -#line 85 "hb-ot-shape-complex-indic-machine.rl" + case 17: +#line 86 "hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (standalone_cluster); }} break; - case 23: -#line 86 "hb-ot-shape-complex-indic-machine.rl" + case 19: +#line 87 "hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (symbol_cluster); }} break; - case 17: -#line 87 "hb-ot-shape-complex-indic-machine.rl" + case 15: +#line 88 "hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (broken_cluster); }} break; - case 19: -#line 88 "hb-ot-shape-complex-indic-machine.rl" + case 16: +#line 89 "hb-ot-shape-complex-indic-machine.rl" {te = p;p--;{ found_syllable (non_indic_cluster); }} break; case 1: -#line 83 "hb-ot-shape-complex-indic-machine.rl" +#line 84 "hb-ot-shape-complex-indic-machine.rl" {{p = ((te))-1;}{ found_syllable (consonant_syllable); }} break; case 3: -#line 84 "hb-ot-shape-complex-indic-machine.rl" +#line 85 "hb-ot-shape-complex-indic-machine.rl" {{p = ((te))-1;}{ found_syllable (vowel_syllable); }} break; case 7: -#line 85 "hb-ot-shape-complex-indic-machine.rl" +#line 86 "hb-ot-shape-complex-indic-machine.rl" {{p = ((te))-1;}{ found_syllable (standalone_cluster); }} break; case 8: -#line 86 "hb-ot-shape-complex-indic-machine.rl" +#line 87 "hb-ot-shape-complex-indic-machine.rl" {{p = ((te))-1;}{ found_syllable (symbol_cluster); }} break; case 4: -#line 87 "hb-ot-shape-complex-indic-machine.rl" +#line 88 "hb-ot-shape-complex-indic-machine.rl" {{p = ((te))-1;}{ found_syllable (broken_cluster); }} break; - case 5: + case 6: #line 1 "NONE" { switch( act ) { case 1: @@ -1065,25 +522,25 @@ _eof_trans: } } break; - case 22: + case 18: #line 1 "NONE" {te = p+1;} -#line 83 "hb-ot-shape-complex-indic-machine.rl" +#line 84 "hb-ot-shape-complex-indic-machine.rl" {act = 1;} break; - case 6: + case 5: #line 1 "NONE" {te = p+1;} -#line 87 "hb-ot-shape-complex-indic-machine.rl" +#line 88 "hb-ot-shape-complex-indic-machine.rl" {act = 5;} break; case 12: #line 1 "NONE" {te = p+1;} -#line 88 "hb-ot-shape-complex-indic-machine.rl" +#line 89 "hb-ot-shape-complex-indic-machine.rl" {act = 6;} break; -#line 1087 "hb-ot-shape-complex-indic-machine.hh" +#line 544 "hb-ot-shape-complex-indic-machine.hh" } _again: @@ -1092,7 +549,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 1096 "hb-ot-shape-complex-indic-machine.hh" +#line 553 "hb-ot-shape-complex-indic-machine.hh" } if ( ++p != pe ) @@ -1108,8 +565,10 @@ _again: } -#line 120 "hb-ot-shape-complex-indic-machine.rl" +#line 121 "hb-ot-shape-complex-indic-machine.rl" } +#undef found_syllable + #endif /* HB_OT_SHAPE_COMPLEX_INDIC_MACHINE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-table.cc index c061ed1a78c..a150fd24866 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic-table.cc @@ -6,71 +6,77 @@ * * on files with these headers: * - * # IndicSyllabicCategory-11.0.0.txt - * # Date: 2018-05-21, 18:33:00 GMT [KW, RP] - * # IndicPositionalCategory-11.0.0.txt - * # Date: 2018-02-05, 16:21:00 GMT [KW, RP] - * # Blocks-11.0.0.txt - * # Date: 2017-10-16, 24:39:00 GMT [KW] + * # IndicSyllabicCategory-13.0.0.txt + * # Date: 2019-07-22, 19:55:00 GMT [KW, RP] + * # IndicPositionalCategory-13.0.0.txt + * # Date: 2019-07-23, 00:01:00 GMT [KW, RP] + * # Blocks-13.0.0.txt + * # Date: 2019-07-10, 19:06:00 GMT [KW] */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex-indic.hh" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wunused-macros" -#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 16 chars; Avagraha */ -#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 83 chars; Bindu */ -#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */ -#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 58 chars; Cantillation_Mark */ -#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 2110 chars; Consonant */ -#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 10 chars; Consonant_Dead */ -#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 67 chars; Consonant_Final */ -#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */ -#define ISC_CIP INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED /* 1 chars; Consonant_Initial_Postfixed */ -#define ISC_CK INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER /* 2 chars; Consonant_Killer */ -#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 28 chars; Consonant_Medial */ -#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 21 chars; Consonant_Placeholder */ -#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 2 chars; Consonant_Preceding_Repha */ -#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED /* 7 chars; Consonant_Prefixed */ -#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 95 chars; Consonant_Subjoined */ -#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 4 chars; Consonant_Succeeding_Repha */ -#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER /* 6 chars; Consonant_With_Stacker */ -#define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK /* 3 chars; Gemination_Mark */ -#define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER /* 11 chars; Invisible_Stacker */ -#define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER /* 1 chars; Joiner */ -#define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */ -#define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */ -#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 30 chars; Nukta */ -#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 480 chars; Number */ -#define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */ -#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */ -#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 21 chars; Pure_Killer */ -#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 2 chars; Register_Shifter */ -#define ISC_SM INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER /* 25 chars; Syllable_Modifier */ -#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */ -#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 42 chars; Tone_Mark */ -#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 25 chars; Virama */ -#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 36 chars; Visarga */ -#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */ -#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 660 chars; Vowel_Dependent */ -#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 464 chars; Vowel_Independent */ - -#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 340 chars; Bottom */ -#define IMC_BL INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT /* 1 chars; Bottom_And_Left */ -#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 2 chars; Bottom_And_Right */ -#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 59 chars; Left */ -#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 21 chars; Left_And_Right */ -#define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */ -#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 10 chars; Overstruck */ -#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 276 chars; Right */ -#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 393 chars; Top */ -#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 10 chars; Top_And_Bottom */ -#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */ -#define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 6 chars; Top_And_Left */ -#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */ -#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */ -#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 19 chars; Visual_Order_Left */ +#define ISC_A INDIC_SYLLABIC_CATEGORY_AVAGRAHA /* 17 chars; Avagraha */ +#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 91 chars; Bindu */ +#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */ +#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 59 chars; Cantillation_Mark */ +#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 2195 chars; Consonant */ +#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 12 chars; Consonant_Dead */ +#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 67 chars; Consonant_Final */ +#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */ +#define ISC_CIP INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED /* 1 chars; Consonant_Initial_Postfixed */ +#define ISC_CK INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER /* 2 chars; Consonant_Killer */ +#define ISC_CM INDIC_SYLLABIC_CATEGORY_CONSONANT_MEDIAL /* 31 chars; Consonant_Medial */ +#define ISC_CP INDIC_SYLLABIC_CATEGORY_CONSONANT_PLACEHOLDER /* 22 chars; Consonant_Placeholder */ +#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 3 chars; Consonant_Preceding_Repha */ +#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED /* 10 chars; Consonant_Prefixed */ +#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 94 chars; Consonant_Subjoined */ +#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 4 chars; Consonant_Succeeding_Repha */ +#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER /* 8 chars; Consonant_With_Stacker */ +#define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK /* 3 chars; Gemination_Mark */ +#define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER /* 12 chars; Invisible_Stacker */ +#define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER /* 1 chars; Joiner */ +#define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */ +#define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */ +#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 31 chars; Nukta */ +#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 491 chars; Number */ +#define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */ +#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */ +#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 23 chars; Pure_Killer */ +#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 2 chars; Register_Shifter */ +#define ISC_SM INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER /* 25 chars; Syllable_Modifier */ +#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */ +#define ISC_TM INDIC_SYLLABIC_CATEGORY_TONE_MARK /* 42 chars; Tone_Mark */ +#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 27 chars; Virama */ +#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 35 chars; Visarga */ +#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */ +#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 683 chars; Vowel_Dependent */ +#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 484 chars; Vowel_Independent */ + +#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 351 chars; Bottom */ +#define IMC_BL INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT /* 1 chars; Bottom_And_Left */ +#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 4 chars; Bottom_And_Right */ +#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 64 chars; Left */ +#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 22 chars; Left_And_Right */ +#define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */ +#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 10 chars; Overstruck */ +#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 288 chars; Right */ +#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 415 chars; Top */ +#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 10 chars; Top_And_Bottom */ +#define IMC_TBL INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT /* 2 chars; Top_And_Bottom_And_Left */ +#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */ +#define IMC_TL INDIC_MATRA_CATEGORY_TOP_AND_LEFT /* 6 chars; Top_And_Left */ +#define IMC_TLR INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT /* 4 chars; Top_And_Left_And_Right */ +#define IMC_TR INDIC_MATRA_CATEGORY_TOP_AND_RIGHT /* 13 chars; Top_And_Right */ +#define IMC_VOL INDIC_MATRA_CATEGORY_VISUAL_ORDER_LEFT /* 19 chars; Visual_Order_Left */ + #pragma GCC diagnostic pop #define _(S,M) INDIC_COMBINE_CATEGORIES (ISC_##S, IMC_##M) @@ -152,7 +158,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = { /* 0A38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(x,x), _(M,R), _(M,L), /* 0A40 */ _(M,R), _(M,B), _(M,B), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), /* 0A48 */ _(M,T), _(x,x), _(x,x), _(M,T), _(M,T), _(V,B), _(x,x), _(x,x), - /* 0A50 */ _(x,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 0A50 */ _(x,x), _(Ca,B), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), /* 0A58 */ _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(x,x), _(C,x), _(x,x), /* 0A60 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(Nd,x), _(Nd,x), /* 0A68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), @@ -190,7 +196,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = { /* 0B38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,R), _(M,T), /* 0B40 */ _(M,R), _(M,B), _(M,B), _(M,B), _(M,B), _(x,x), _(x,x), _(M,L), /* 0B48 */ _(M,TL), _(x,x), _(x,x), _(M,LR),_(M,TLR), _(V,B), _(x,x), _(x,x), - /* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,TR), + /* 0B50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,T), _(M,TR), /* 0B58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(C,x), _(x,x), _(C,x), /* 0B60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x), /* 0B68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), @@ -237,7 +243,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = { /* Kannada */ - /* 0C80 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0C80 */ _(Bi,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), /* 0C88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), /* 0C90 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), /* 0C98 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), @@ -256,7 +262,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = { /* Malayalam */ - /* 0D00 */ _(Bi,T), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0D00 */ _(Bi,T), _(Bi,T), _(Bi,R), _(Vs,R), _(Bi,x), _(VI,x), _(VI,x), _(VI,x), /* 0D08 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), _(VI,x), _(VI,x), /* 0D10 */ _(VI,x), _(x,x), _(VI,x), _(VI,x), _(VI,x), _(C,x), _(C,x), _(C,x), /* 0D18 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), @@ -265,7 +271,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = { /* 0D30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), /* 0D38 */ _(C,x), _(C,x), _(C,x), _(PK,T), _(PK,T), _(A,x), _(M,R), _(M,R), /* 0D40 */ _(M,R), _(M,R), _(M,R), _(M,B), _(M,B), _(x,x), _(M,L), _(M,L), - /* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T),_(CPR,x), _(x,x), + /* 0D48 */ _(M,L), _(x,x), _(M,LR), _(M,LR), _(M,LR), _(V,T),_(CPR,T), _(x,x), /* 0D50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(CD,x), _(CD,x), _(CD,x), _(M,R), /* 0D58 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(VI,x), /* 0D60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x), @@ -275,7 +281,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = { /* Sinhala */ - /* 0D80 */ _(x,x), _(x,x), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), + /* 0D80 */ _(x,x), _(Bi,T), _(Bi,R), _(Vs,R), _(x,x), _(VI,x), _(VI,x), _(VI,x), /* 0D88 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), /* 0D90 */ _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(x,x), /* 0D98 */ _(x,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), @@ -303,7 +309,7 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = { /* 1020 */ _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), /* 1028 */ _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), _(M,T), _(M,T), _(M,B), /* 1030 */ _(M,B), _(M,L), _(M,T), _(M,T), _(M,T), _(M,T), _(Bi,T), _(TM,B), - /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R), _(CM,x), _(CM,B), _(CM,B), _(C,x), + /* 1038 */ _(Vs,R), _(IS,x), _(PK,T), _(CM,R),_(CM,TBL), _(CM,B), _(CM,B), _(C,x), /* 1040 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), /* 1048 */ _(Nd,x), _(Nd,x), _(x,x), _(CP,x), _(x,x), _(x,x), _(CP,x), _(x,x), /* 1050 */ _(C,x), _(C,x), _(VI,x), _(VI,x), _(VI,x), _(VI,x), _(M,R), _(M,R), @@ -346,8 +352,8 @@ static const INDIC_TABLE_ELEMENT_TYPE indic_table[] = { /* 1CD8 */ _(Ca,B), _(Ca,B), _(Ca,T), _(Ca,T), _(Ca,B), _(Ca,B), _(Ca,B), _(Ca,B), /* 1CE0 */ _(Ca,T), _(Ca,R), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O), _(x,O), /* 1CE8 */ _(x,O), _(x,x), _(x,x), _(x,x), _(x,x), _(x,B), _(x,x), _(x,x), - /* 1CF0 */ _(x,x), _(x,x), _(Vs,x), _(Vs,x), _(Ca,T),_(CWS,x),_(CWS,x), _(Ca,R), - /* 1CF8 */ _(Ca,x), _(Ca,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), + /* 1CF0 */ _(x,x), _(x,x), _(CD,x), _(CD,x), _(Ca,T),_(CWS,x),_(CWS,x), _(Ca,R), + /* 1CF8 */ _(Ca,x), _(Ca,x), _(CP,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), #define indic_offset_0x2008u 1656 @@ -435,6 +441,7 @@ hb_indic_get_categories (hb_codepoint_t u) } #undef _ + #undef ISC_A #undef ISC_Bi #undef ISC_BJN @@ -471,6 +478,7 @@ hb_indic_get_categories (hb_codepoint_t u) #undef ISC_Vo #undef ISC_M #undef ISC_VI + #undef IMC_B #undef IMC_BL #undef IMC_BR @@ -481,10 +489,13 @@ hb_indic_get_categories (hb_codepoint_t u) #undef IMC_R #undef IMC_T #undef IMC_TB +#undef IMC_TBL #undef IMC_TBR #undef IMC_TL #undef IMC_TLR #undef IMC_TR #undef IMC_VOL +#endif + /* == End of generated table == */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.cc index 38b47fa63e4..e011f510d32 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex-indic.hh" #include "hb-ot-shape-complex-vowel-constraints.hh" #include "hb-ot-layout.hh" @@ -127,62 +131,47 @@ indic_features[] = {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('h','a','l','n'), F_GLOBAL_MANUAL_JOINERS}, - /* - * Positioning features. - * We don't care about the types. - */ - {HB_TAG('d','i','s','t'), F_GLOBAL}, - {HB_TAG('a','b','v','m'), F_GLOBAL}, - {HB_TAG('b','l','w','m'), F_GLOBAL}, }; /* * Must be in the same order as the indic_features array. */ enum { - _NUKT, - _AKHN, - RPHF, - _RKRF, - PREF, - BLWF, - ABVF, - HALF, - PSTF, - _VATU, - _CJCT, - - INIT, - _PRES, - _ABVS, - _BLWS, - _PSTS, - _HALN, - - _DIST, - _ABVM, - _BLWM, + _INDIC_NUKT, + _INDIC_AKHN, + INDIC_RPHF, + _INDIC_RKRF, + INDIC_PREF, + INDIC_BLWF, + INDIC_ABVF, + INDIC_HALF, + INDIC_PSTF, + _INDIC_VATU, + _INDIC_CJCT, + + INDIC_INIT, + _INDIC_PRES, + _INDIC_ABVS, + _INDIC_BLWS, + _INDIC_PSTS, + _INDIC_HALN, INDIC_NUM_FEATURES, - INDIC_BASIC_FEATURES = INIT, /* Don't forget to update this! */ + INDIC_BASIC_FEATURES = INDIC_INIT, /* Don't forget to update this! */ }; static void -setup_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -initial_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +setup_syllables_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -final_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +initial_reordering_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -clear_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +final_reordering_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void collect_features_indic (hb_ot_shape_planner_t *plan) @@ -190,7 +179,7 @@ collect_features_indic (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; /* Do this before any lookups have been applied. */ - map->add_gsub_pause (setup_syllables); + map->add_gsub_pause (setup_syllables_indic); map->enable_feature (HB_TAG('l','o','c','l')); /* The Indic specs do not require ccmp, but we apply it here since if @@ -199,14 +188,14 @@ collect_features_indic (hb_ot_shape_planner_t *plan) unsigned int i = 0; - map->add_gsub_pause (initial_reordering); + map->add_gsub_pause (initial_reordering_indic); for (; i < INDIC_BASIC_FEATURES; i++) { map->add_feature (indic_features[i]); map->add_gsub_pause (nullptr); } - map->add_gsub_pause (final_reordering); + map->add_gsub_pause (final_reordering_indic); for (; i < INDIC_NUM_FEATURES; i++) map->add_feature (indic_features[i]); @@ -214,7 +203,7 @@ collect_features_indic (hb_ot_shape_planner_t *plan) map->enable_feature (HB_TAG('c','a','l','t')); map->enable_feature (HB_TAG('c','l','i','g')); - map->add_gsub_pause (clear_syllables); + map->add_gsub_pause (_hb_clear_syllables); } static void @@ -224,32 +213,6 @@ override_features_indic (hb_ot_shape_planner_t *plan) } -struct would_substitute_feature_t -{ - void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) - { - zero_context = zero_context_; - map->get_stage_lookups (0/*GSUB*/, - map->get_feature_stage (0/*GSUB*/, feature_tag), - &lookups, &count); - } - - bool would_substitute (const hb_codepoint_t *glyphs, - unsigned int glyphs_count, - hb_face_t *face) const - { - for (unsigned int i = 0; i < count; i++) - if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) - return true; - return false; - } - - private: - const hb_ot_map_t::lookup_map_t *lookups; - unsigned int count; - bool zero_context; -}; - struct indic_shape_plan_t { bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const @@ -274,13 +237,18 @@ struct indic_shape_plan_t const indic_config_t *config; bool is_old_spec; +#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE bool uniscribe_bug_compatible; +#else + static constexpr bool uniscribe_bug_compatible = false; +#endif mutable hb_atomic_int_t virama_glyph; - would_substitute_feature_t rphf; - would_substitute_feature_t pref; - would_substitute_feature_t blwf; - would_substitute_feature_t pstf; + hb_indic_would_substitute_feature_t rphf; + hb_indic_would_substitute_feature_t pref; + hb_indic_would_substitute_feature_t blwf; + hb_indic_would_substitute_feature_t pstf; + hb_indic_would_substitute_feature_t vatu; hb_mask_t mask_array[INDIC_NUM_FEATURES]; }; @@ -300,7 +268,9 @@ data_create_indic (const hb_ot_shape_plan_t *plan) } indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2'); +#ifndef HB_NO_UNISCRIBE_BUG_COMPATIBLE indic_plan->uniscribe_bug_compatible = hb_options ().uniscribe_bug_compatible; +#endif indic_plan->virama_glyph.set_relaxed (-1); /* Use zero-context would_substitute() matching for new-spec of the main @@ -317,6 +287,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan) indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), zero_context); indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'), zero_context); indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'), zero_context); + indic_plan->vatu.init (&plan->map, HB_TAG('v','a','t','u'), zero_context); for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++) indic_plan->mask_array[i] = (indic_features[i].flags & F_GLOBAL) ? @@ -346,10 +317,16 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan, * base at 0. The font however, only has lookups matching * 930,94D in 'blwf', not the expected 94D,930 (with new-spec * table). As such, we simply match both sequences. Seems - * to work. */ + * to work. + * + * Vatu is done as well, for: + * https://github.com/harfbuzz/harfbuzz/issues/1587 + */ hb_codepoint_t glyphs[3] = {virama, consonant, virama}; if (indic_plan->blwf.would_substitute (glyphs , 2, face) || - indic_plan->blwf.would_substitute (glyphs+1, 2, face)) + indic_plan->blwf.would_substitute (glyphs+1, 2, face) || + indic_plan->vatu.would_substitute (glyphs , 2, face) || + indic_plan->vatu.would_substitute (glyphs+1, 2, face)) return POS_BELOW_C; if (indic_plan->pstf.would_substitute (glyphs , 2, face) || indic_plan->pstf.would_substitute (glyphs+1, 2, face)) @@ -361,13 +338,13 @@ consonant_position_from_face (const indic_shape_plan_t *indic_plan, } -enum syllable_type_t { - consonant_syllable, - vowel_syllable, - standalone_cluster, - symbol_cluster, - broken_cluster, - non_indic_cluster, +enum indic_syllable_type_t { + indic_consonant_syllable, + indic_vowel_syllable, + indic_standalone_cluster, + indic_symbol_cluster, + indic_broken_cluster, + indic_non_indic_cluster, }; #include "hb-ot-shape-complex-indic-machine.hh" @@ -391,11 +368,11 @@ setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +setup_syllables_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { - find_syllables (buffer); + find_syllables_indic (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); } @@ -412,9 +389,9 @@ compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb) static void -update_consonant_positions (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +update_consonant_positions_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; @@ -487,7 +464,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * and has more than one consonant, Ra is excluded from candidates for * base consonants. */ unsigned int limit = start; - if (indic_plan->mask_array[RPHF] && + if (indic_plan->mask_array[INDIC_RPHF] && start + 3 <= end && ( (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) || @@ -645,7 +622,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, /* Reorder characters */ for (unsigned int i = start; i < base; i++) - info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position()); + info[i].indic_position() = hb_min (POS_PRE_C, (indic_position_t) info[i].indic_position()); if (base < end) info[base].indic_position() = POS_BASE_C; @@ -673,7 +650,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, * is *not* a Halant after last consonant already. We know that is the * case for Kannada, while it reorders unconditionally in other scripts, * eg. Malayalam, Bengali, and Devanagari. We don't currently know about - * other scripts, so we blacklist Kannada. + * other scripts, so we block Kannada. * * Kannada test case: * U+0C9A,U+0CCD,U+0C9A,U+0CCD @@ -720,7 +697,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, indic_position_t last_pos = POS_START; for (unsigned int i = start; i < end; i++) { - if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | FLAG (OT_H)))) + if ((FLAG_UNSAFE (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_H)))) { info[i].indic_position() = last_pos; if (unlikely (info[i].indic_category() == OT_H && @@ -801,7 +778,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, unsigned int j = start + info[i].syllable(); while (j != i) { - max = MAX (max, j); + max = hb_max (max, j); unsigned int next = start + info[j].syllable(); info[j].syllable() = 255; /* So we don't process j later again. */ j = next; @@ -823,13 +800,13 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, /* Reph */ for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++) - info[i].mask |= indic_plan->mask_array[RPHF]; + info[i].mask |= indic_plan->mask_array[INDIC_RPHF]; /* Pre-base */ - mask = indic_plan->mask_array[HALF]; + mask = indic_plan->mask_array[INDIC_HALF]; if (!indic_plan->is_old_spec && indic_plan->config->blwf_mode == BLWF_MODE_PRE_AND_POST) - mask |= indic_plan->mask_array[BLWF]; + mask |= indic_plan->mask_array[INDIC_BLWF]; for (unsigned int i = start; i < base; i++) info[i].mask |= mask; /* Base */ @@ -837,7 +814,9 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, if (base < end) info[base].mask |= mask; /* Post-base */ - mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF]; + mask = indic_plan->mask_array[INDIC_BLWF] | + indic_plan->mask_array[INDIC_ABVF] | + indic_plan->mask_array[INDIC_PSTF]; for (unsigned int i = base + 1; i < end; i++) info[i].mask |= mask; } @@ -869,13 +848,13 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, (i + 2 == base || info[i+2].indic_category() != OT_ZWJ)) { - info[i ].mask |= indic_plan->mask_array[BLWF]; - info[i+1].mask |= indic_plan->mask_array[BLWF]; + info[i ].mask |= indic_plan->mask_array[INDIC_BLWF]; + info[i+1].mask |= indic_plan->mask_array[INDIC_BLWF]; } } unsigned int pref_len = 2; - if (indic_plan->mask_array[PREF] && base + pref_len < end) + if (indic_plan->mask_array[INDIC_PREF] && base + pref_len < end) { /* Find a Halant,Ra sequence and mark it for pre-base-reordering processing. */ for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) { @@ -885,7 +864,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, if (indic_plan->pref.would_substitute (glyphs, pref_len, face)) { for (unsigned int j = 0; j < pref_len; j++) - info[i++].mask |= indic_plan->mask_array[PREF]; + info[i++].mask |= indic_plan->mask_array[INDIC_PREF]; break; } } @@ -906,7 +885,7 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, /* A ZWNJ disables HALF. */ if (non_joiner) - info[j].mask &= ~indic_plan->mask_array[HALF]; + info[j].mask &= ~indic_plan->mask_array[INDIC_HALF]; } while (j > start && !is_consonant (info[j])); } @@ -918,11 +897,10 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, unsigned int start, unsigned int end) { - const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; - /* We treat placeholder/dotted-circle as if they are consonants, so we * should just chain. Only if not in compatibility mode that is... */ + const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; if (indic_plan->uniscribe_bug_compatible) { /* For dotted-circle, this is what Uniscribe does: @@ -936,42 +914,45 @@ initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan, } static void -initial_reordering_syllable (const hb_ot_shape_plan_t *plan, - hb_face_t *face, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) +initial_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, + hb_face_t *face, + hb_buffer_t *buffer, + unsigned int start, unsigned int end) { - syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); + indic_syllable_type_t syllable_type = (indic_syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) { - case vowel_syllable: /* We made the vowels look like consonants. So let's call the consonant logic! */ - case consonant_syllable: + case indic_vowel_syllable: /* We made the vowels look like consonants. So let's call the consonant logic! */ + case indic_consonant_syllable: initial_reordering_consonant_syllable (plan, face, buffer, start, end); break; - case broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */ - case standalone_cluster: + case indic_broken_cluster: /* We already inserted dotted-circles, so just call the standalone_cluster. */ + case indic_standalone_cluster: initial_reordering_standalone_cluster (plan, face, buffer, start, end); break; - case symbol_cluster: - case non_indic_cluster: + case indic_symbol_cluster: + case indic_non_indic_cluster: break; } } static inline void -insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font, - hb_buffer_t *buffer) +insert_dotted_circles_indic (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font, + hb_buffer_t *buffer) { + if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) + return; + /* Note: This loop is extra overhead, but should not be measurable. * TODO Use a buffer scratch flag to remove the loop. */ bool has_broken_syllables = false; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - if ((info[i].syllable() & 0x0F) == broken_cluster) + if ((info[i].syllable() & 0x0F) == indic_broken_cluster) { has_broken_syllables = true; break; @@ -996,8 +977,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, while (buffer->idx < buffer->len && buffer->successful) { unsigned int syllable = buffer->cur().syllable(); - syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); - if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) + indic_syllable_type_t syllable_type = (indic_syllable_type_t) (syllable & 0x0F); + if (unlikely (last_syllable != syllable && syllable_type == indic_broken_cluster)) { last_syllable = syllable; @@ -1005,7 +986,6 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, ginfo.cluster = buffer->cur().cluster; ginfo.mask = buffer->cur().mask; ginfo.syllable() = buffer->cur().syllable(); - /* TODO Set glyph_props? */ /* Insert dottedcircle after possible Repha. */ while (buffer->idx < buffer->len && buffer->successful && @@ -1022,21 +1002,21 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -initial_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +initial_reordering_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { - update_consonant_positions (plan, font, buffer); - insert_dotted_circles (plan, font, buffer); + update_consonant_positions_indic (plan, font, buffer); + insert_dotted_circles_indic (plan, font, buffer); foreach_syllable (buffer, start, end) - initial_reordering_syllable (plan, font->face, buffer, start, end); + initial_reordering_syllable_indic (plan, font->face, buffer, start, end); } static void -final_reordering_syllable (const hb_ot_shape_plan_t *plan, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) +final_reordering_syllable_indic (const hb_ot_shape_plan_t *plan, + hb_buffer_t *buffer, + unsigned int start, unsigned int end) { const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data; hb_glyph_info_t *info = buffer->info; @@ -1072,7 +1052,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, * syllable. */ - bool try_pref = !!indic_plan->mask_array[PREF]; + bool try_pref = !!indic_plan->mask_array[INDIC_PREF]; /* Find base again */ unsigned int base; @@ -1082,7 +1062,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, if (try_pref && base + 1 < end) { for (unsigned int i = base + 1; i < end; i++) - if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) + if ((info[i].mask & indic_plan->mask_array[INDIC_PREF]) != 0) { if (!(_hb_glyph_info_substituted (&info[i]) && _hb_glyph_info_ligated_and_didnt_multiply (&info[i]))) @@ -1199,9 +1179,14 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, goto search; } } - /* -> If ZWNJ follows this halant, position is moved after it. */ - if (info[new_pos + 1].indic_category() == OT_ZWNJ) - new_pos++; + /* -> If ZWNJ follows this halant, position is moved after it. + * + * IMPLEMENTATION NOTES: + * + * This is taken care of by the state-machine. A Halant,ZWNJ is a terminating + * sequence for a consonant syllable; any pre-base matras occurring after it + * will belong to the subsequent syllable. + */ } } else @@ -1224,14 +1209,14 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, /* Note: this merge_clusters() is intentionally *after* the reordering. * Indic matra reordering is special and tricky... */ - buffer->merge_clusters (new_pos, MIN (end, base + 1)); + buffer->merge_clusters (new_pos, hb_min (end, base + 1)); new_pos--; } } else { for (unsigned int i = start; i < base; i++) if (info[i].indic_position () == POS_PRE_M) { - buffer->merge_clusters (i, MIN (end, base + 1)); + buffer->merge_clusters (i, hb_min (end, base + 1)); break; } } @@ -1348,6 +1333,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, goto reph_move; } } + /* See https://github.com/harfbuzz/harfbuzz/issues/2298#issuecomment-615318654 */ /* 6. Otherwise, reorder reph to the end of the syllable. */ @@ -1364,13 +1350,15 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, * TEST: U+0930,U+094D,U+0915,U+094B,U+094D */ if (!indic_plan->uniscribe_bug_compatible && - unlikely (is_halant (info[new_reph_pos]))) { + unlikely (is_halant (info[new_reph_pos]))) + { for (unsigned int i = base + 1; i < new_reph_pos; i++) if (info[i].indic_category() == OT_M) { /* Ok, got it. */ new_reph_pos--; } } + goto reph_move; } @@ -1397,7 +1385,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base-reordering Ra. */ { for (unsigned int i = base + 1; i < end; i++) - if ((info[i].mask & indic_plan->mask_array[PREF]) != 0) + if ((info[i].mask & indic_plan->mask_array[INDIC_PREF]) != 0) { /* 1. Only reorder a glyph produced by substitution during application * of the feature. (Note that a font may shape a Ra consonant with @@ -1460,7 +1448,7 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, if (!start || !(FLAG_UNSAFE (_hb_glyph_info_get_general_category (&info[start - 1])) & FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))) - info[start].mask |= indic_plan->mask_array[INIT]; + info[start].mask |= indic_plan->mask_array[INDIC_INIT]; else buffer->unsafe_to_break (start - 1, start + 1); } @@ -1490,33 +1478,21 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan, static void -final_reordering (const hb_ot_shape_plan_t *plan, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +final_reordering_indic (const hb_ot_shape_plan_t *plan, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { unsigned int count = buffer->len; if (unlikely (!count)) return; foreach_syllable (buffer, start, end) - final_reordering_syllable (plan, buffer, start, end); + final_reordering_syllable_indic (plan, buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category); HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position); } -static void -clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - info[i].syllable() = 0; -} - - static void preprocess_text_indic (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, @@ -1583,11 +1559,10 @@ decompose_indic (const hb_ot_shape_normalize_context_t *c, * https://docs.microsoft.com/en-us/typography/script-development/sinhala#shaping */ - const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; + const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) c->plan->data; hb_codepoint_t glyph; - - if (hb_options ().uniscribe_bug_compatible || + if (indic_plan->uniscribe_bug_compatible || (c->font->get_nominal_glyph (ab, &glyph) && indic_plan->pstf.would_substitute (&glyph, 1, c->font->face))) { @@ -1635,3 +1610,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic = HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ }; + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.hh index 0aae0d3953a..5b3347b9f52 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-indic.hh @@ -62,17 +62,26 @@ enum indic_category_t { OT_Coeng = 14, /* Khmer-style Virama. */ OT_Repha = 15, /* Atomically-encoded logical or visual repha. */ OT_Ra = 16, - OT_CM = 17, /* Consonant-Medial; Unused by Indic shaper. */ + OT_CM = 17, /* Consonant-Medial. */ OT_Symbol = 18, /* Avagraha, etc that take marks (SM,A,VD). */ - OT_CS = 19 + OT_CS = 19, + + /* The following are used by Khmer & Myanmar shapers. Defined + * here for them to share. */ + OT_VAbv = 26, + OT_VBlw = 27, + OT_VPre = 28, + OT_VPst = 29, }; +#define MEDIAL_FLAGS (FLAG (OT_CM)) + /* Note: * * We treat Vowels and placeholders as if they were consonants. This is safe because Vowels * cannot happen in a consonant syllable. The plus side however is, we can call the * consonant syllable logic from the vowel syllable function and get it all right! */ -#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE)) +#define CONSONANT_FLAGS (FLAG (OT_C) | FLAG (OT_CS) | FLAG (OT_Ra) | MEDIAL_FLAGS | FLAG (OT_V) | FLAG (OT_PLACEHOLDER) | FLAG (OT_DOTTEDCIRCLE)) #define JOINER_FLAGS (FLAG (OT_ZWJ) | FLAG (OT_ZWNJ)) @@ -156,6 +165,7 @@ enum indic_matra_category_t { INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM = INDIC_MATRA_CATEGORY_BOTTOM, + INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT = INDIC_MATRA_CATEGORY_BOTTOM, INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, INDIC_MATRA_CATEGORY_TOP_AND_LEFT = INDIC_MATRA_CATEGORY_TOP, INDIC_MATRA_CATEGORY_TOP_AND_LEFT_AND_RIGHT = INDIC_MATRA_CATEGORY_RIGHT, @@ -276,7 +286,7 @@ matra_position_indic (hb_codepoint_t u, indic_position_t side) case POS_POST_C: return MATRA_POS_RIGHT (u); case POS_ABOVE_C: return MATRA_POS_TOP (u); case POS_BELOW_C: return MATRA_POS_BOTTOM (u); - }; + } return side; } @@ -357,11 +367,12 @@ set_indic_properties (hb_glyph_info_t &info) /* According to ScriptExtensions.txt, these Grantha marks may also be used in Tamil, * so the Indic shaper needs to know their categories. */ else if (unlikely (u == 0x11301u || u == 0x11303u)) cat = OT_SM; - else if (unlikely (u == 0x1133cu)) cat = OT_N; + else if (unlikely (u == 0x1133Bu || u == 0x1133Cu)) cat = OT_N; else if (unlikely (u == 0x0AFBu)) cat = OT_N; /* https://github.com/harfbuzz/harfbuzz/issues/552 */ else if (unlikely (u == 0x0980u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/issues/538 */ + else if (unlikely (u == 0x09FCu)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/1613 */ else if (unlikely (u == 0x0C80u)) cat = OT_PLACEHOLDER; /* https://github.com/harfbuzz/harfbuzz/pull/623 */ else if (unlikely (hb_in_range (u, 0x2010u, 0x2011u))) cat = OT_PLACEHOLDER; @@ -395,5 +406,31 @@ set_indic_properties (hb_glyph_info_t &info) info.indic_position() = pos; } +struct hb_indic_would_substitute_feature_t +{ + void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) + { + zero_context = zero_context_; + map->get_stage_lookups (0/*GSUB*/, + map->get_feature_stage (0/*GSUB*/, feature_tag), + &lookups, &count); + } + + bool would_substitute (const hb_codepoint_t *glyphs, + unsigned int glyphs_count, + hb_face_t *face) const + { + for (unsigned int i = 0; i < count; i++) + if (hb_ot_layout_lookup_would_substitute (face, lookups[i].index, glyphs, glyphs_count, zero_context)) + return true; + return false; + } + + private: + const hb_ot_map_t::lookup_map_t *lookups; + unsigned int count; + bool zero_context; +}; + #endif /* HB_OT_SHAPE_COMPLEX_INDIC_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer-machine.hh index 2b59a50e724..4d737dad05c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer-machine.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer-machine.hh @@ -35,29 +35,27 @@ #line 36 "hb-ot-shape-complex-khmer-machine.hh" static const unsigned char _khmer_syllable_machine_trans_keys[] = { 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, - 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, - 5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 16u, 1u, 29u, 5u, 29u, - 5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 5u, 26u, - 5u, 29u, 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, - 5u, 29u, 0 + 5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, + 5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u, + 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 26u, 5u, 29u, + 5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 5u, 29u, + 0 }; static const char _khmer_syllable_machine_key_spans[] = { 22, 17, 22, 17, 16, 17, 22, 17, - 22, 17, 16, 17, 22, 17, 16, 17, - 22, 17, 22, 17, 22, 16, 29, 25, - 25, 25, 1, 18, 25, 25, 25, 22, - 25, 25, 1, 18, 25, 25, 16, 25, - 25 + 22, 17, 17, 22, 17, 16, 17, 22, + 17, 22, 17, 22, 29, 25, 25, 25, + 1, 18, 25, 25, 25, 16, 22, 25, + 25, 1, 18, 25, 25, 16, 25, 25 }; static const short _khmer_syllable_machine_index_offsets[] = { 0, 23, 41, 64, 82, 99, 117, 140, - 158, 181, 199, 216, 234, 257, 275, 292, - 310, 333, 351, 374, 392, 415, 432, 462, - 488, 514, 540, 542, 561, 587, 613, 639, - 662, 688, 714, 716, 735, 761, 787, 804, - 830 + 158, 181, 199, 217, 240, 258, 275, 293, + 316, 334, 357, 375, 398, 428, 454, 480, + 506, 508, 527, 553, 579, 605, 622, 645, + 671, 697, 699, 718, 744, 770, 787, 813 }; static const char _khmer_syllable_machine_indicies[] = { @@ -85,142 +83,136 @@ static const char _khmer_syllable_machine_indicies[] = { 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 0, 4, 0, 11, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 12, 0, 13, - 13, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 13, 0, - 15, 15, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 16, 14, 15, 15, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 16, 17, 17, 17, 17, 18, - 17, 19, 19, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 18, 17, 20, 20, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 20, 17, 21, 21, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 22, 17, 23, 23, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 24, 17, - 17, 17, 17, 18, 17, 23, 23, 17, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 24, 17, 25, - 25, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 26, - 17, 17, 17, 17, 18, 17, 25, 25, - 17, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 26, 17, - 15, 15, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 17, 27, - 16, 17, 17, 17, 17, 18, 17, 28, - 28, 17, 17, 17, 17, 17, 17, 17, - 17, 17, 17, 17, 17, 17, 28, 17, - 13, 13, 29, 29, 30, 30, 29, 29, - 29, 29, 2, 2, 29, 31, 29, 13, - 29, 29, 29, 29, 16, 20, 29, 29, - 29, 18, 24, 26, 22, 29, 33, 33, - 32, 32, 32, 32, 32, 32, 32, 34, - 32, 32, 32, 32, 32, 2, 3, 6, - 32, 32, 32, 4, 10, 12, 8, 32, - 35, 35, 32, 32, 32, 32, 32, 32, - 32, 36, 32, 32, 32, 32, 32, 32, - 3, 6, 32, 32, 32, 4, 10, 12, - 8, 32, 5, 5, 32, 32, 32, 32, - 32, 32, 32, 36, 32, 32, 32, 32, - 32, 32, 4, 6, 32, 32, 32, 32, - 32, 32, 8, 32, 6, 32, 7, 7, - 32, 32, 32, 32, 32, 32, 32, 36, - 32, 32, 32, 32, 32, 32, 8, 6, - 32, 37, 37, 32, 32, 32, 32, 32, - 32, 32, 36, 32, 32, 32, 32, 32, - 32, 10, 6, 32, 32, 32, 4, 32, - 32, 8, 32, 38, 38, 32, 32, 32, - 32, 32, 32, 32, 36, 32, 32, 32, - 32, 32, 32, 12, 6, 32, 32, 32, - 4, 10, 32, 8, 32, 35, 35, 32, - 32, 32, 32, 32, 32, 32, 34, 32, - 32, 32, 32, 32, 32, 3, 6, 32, - 32, 32, 4, 10, 12, 8, 32, 15, - 15, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 39, 39, 39, 39, 39, 16, - 39, 39, 39, 39, 18, 39, 41, 41, - 40, 40, 40, 40, 40, 40, 40, 42, - 40, 40, 40, 40, 40, 40, 16, 20, - 40, 40, 40, 18, 24, 26, 22, 40, - 19, 19, 40, 40, 40, 40, 40, 40, - 40, 42, 40, 40, 40, 40, 40, 40, - 18, 20, 40, 40, 40, 40, 40, 40, - 22, 40, 20, 40, 21, 21, 40, 40, - 40, 40, 40, 40, 40, 42, 40, 40, - 40, 40, 40, 40, 22, 20, 40, 43, - 43, 40, 40, 40, 40, 40, 40, 40, - 42, 40, 40, 40, 40, 40, 40, 24, - 20, 40, 40, 40, 18, 40, 40, 22, - 40, 44, 44, 40, 40, 40, 40, 40, - 40, 40, 42, 40, 40, 40, 40, 40, - 40, 26, 20, 40, 40, 40, 18, 24, - 40, 22, 40, 28, 28, 39, 39, 39, + 0, 0, 0, 0, 0, 12, 0, 14, + 14, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 15, + 13, 14, 14, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 15, 16, 16, 16, 16, 17, 16, + 18, 18, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 17, 16, 19, 19, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 19, 16, 20, 20, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 21, 16, 22, 22, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 23, 16, 16, + 16, 16, 17, 16, 22, 22, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 23, 16, 24, 24, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 25, 16, + 16, 16, 16, 17, 16, 24, 24, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 25, 16, 14, + 14, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 26, 15, + 16, 16, 16, 16, 17, 16, 28, 28, + 27, 27, 29, 29, 27, 27, 27, 27, + 2, 2, 27, 30, 27, 28, 27, 27, + 27, 27, 15, 19, 27, 27, 27, 17, + 23, 25, 21, 27, 32, 32, 31, 31, + 31, 31, 31, 31, 31, 33, 31, 31, + 31, 31, 31, 2, 3, 6, 31, 31, + 31, 4, 10, 12, 8, 31, 34, 34, + 31, 31, 31, 31, 31, 31, 31, 35, + 31, 31, 31, 31, 31, 31, 3, 6, + 31, 31, 31, 4, 10, 12, 8, 31, + 5, 5, 31, 31, 31, 31, 31, 31, + 31, 35, 31, 31, 31, 31, 31, 31, + 4, 6, 31, 31, 31, 31, 31, 31, + 8, 31, 6, 31, 7, 7, 31, 31, + 31, 31, 31, 31, 31, 35, 31, 31, + 31, 31, 31, 31, 8, 6, 31, 36, + 36, 31, 31, 31, 31, 31, 31, 31, + 35, 31, 31, 31, 31, 31, 31, 10, + 6, 31, 31, 31, 4, 31, 31, 8, + 31, 37, 37, 31, 31, 31, 31, 31, + 31, 31, 35, 31, 31, 31, 31, 31, + 31, 12, 6, 31, 31, 31, 4, 10, + 31, 8, 31, 34, 34, 31, 31, 31, + 31, 31, 31, 31, 33, 31, 31, 31, + 31, 31, 31, 3, 6, 31, 31, 31, + 4, 10, 12, 8, 31, 28, 28, 31, + 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 28, 31, 14, 14, + 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 15, 38, + 38, 38, 38, 17, 38, 40, 40, 39, + 39, 39, 39, 39, 39, 39, 41, 39, + 39, 39, 39, 39, 39, 15, 19, 39, + 39, 39, 17, 23, 25, 21, 39, 18, + 18, 39, 39, 39, 39, 39, 39, 39, + 41, 39, 39, 39, 39, 39, 39, 17, + 19, 39, 39, 39, 39, 39, 39, 21, + 39, 19, 39, 20, 20, 39, 39, 39, + 39, 39, 39, 39, 41, 39, 39, 39, + 39, 39, 39, 21, 19, 39, 42, 42, + 39, 39, 39, 39, 39, 39, 39, 41, + 39, 39, 39, 39, 39, 39, 23, 19, + 39, 39, 39, 17, 39, 39, 21, 39, + 43, 43, 39, 39, 39, 39, 39, 39, + 39, 41, 39, 39, 39, 39, 39, 39, + 25, 19, 39, 39, 39, 17, 23, 39, + 21, 39, 44, 44, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, - 39, 39, 28, 39, 45, 45, 40, 40, - 40, 40, 40, 40, 40, 46, 40, 40, - 40, 40, 40, 27, 16, 20, 40, 40, - 40, 18, 24, 26, 22, 40, 41, 41, - 40, 40, 40, 40, 40, 40, 40, 46, - 40, 40, 40, 40, 40, 40, 16, 20, - 40, 40, 40, 18, 24, 26, 22, 40, - 0 + 39, 44, 39, 45, 45, 39, 39, 39, + 39, 39, 39, 39, 30, 39, 39, 39, + 39, 39, 26, 15, 19, 39, 39, 39, + 17, 23, 25, 21, 39, 40, 40, 39, + 39, 39, 39, 39, 39, 39, 30, 39, + 39, 39, 39, 39, 39, 15, 19, 39, + 39, 39, 17, 23, 25, 21, 39, 0 }; static const char _khmer_syllable_machine_trans_targs[] = { - 22, 1, 30, 24, 25, 3, 26, 5, - 27, 7, 28, 9, 29, 23, 22, 11, - 32, 22, 33, 13, 34, 15, 35, 17, - 36, 19, 37, 40, 39, 22, 31, 38, - 22, 0, 10, 2, 4, 6, 8, 22, - 22, 12, 14, 16, 18, 20, 21 + 20, 1, 28, 22, 23, 3, 24, 5, + 25, 7, 26, 9, 27, 20, 10, 31, + 20, 32, 12, 33, 14, 34, 16, 35, + 18, 36, 39, 20, 21, 30, 37, 20, + 0, 29, 2, 4, 6, 8, 20, 20, + 11, 13, 15, 17, 38, 19 }; static const char _khmer_syllable_machine_trans_actions[] = { 1, 0, 2, 2, 2, 0, 0, 0, - 2, 0, 2, 0, 2, 2, 3, 0, - 4, 5, 2, 0, 0, 0, 2, 0, - 2, 0, 2, 4, 4, 8, 9, 0, - 10, 0, 0, 0, 0, 0, 0, 11, - 12, 0, 0, 0, 0, 0, 0 + 2, 0, 2, 0, 2, 3, 0, 4, + 5, 2, 0, 0, 0, 2, 0, 2, + 0, 2, 4, 8, 2, 9, 0, 10, + 0, 0, 0, 0, 0, 0, 11, 12, + 0, 0, 0, 0, 4, 0 }; static const char _khmer_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 6, 0, + 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0 + 0, 0, 0, 0, 0, 0, 0, 0 }; static const char _khmer_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 7, 0, + 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0 + 0, 0, 0, 0, 0, 0, 0, 0 }; static const unsigned char _khmer_syllable_machine_eof_trans[] = { 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 15, 18, 18, 18, 18, - 18, 18, 18, 18, 18, 18, 0, 33, - 33, 33, 33, 33, 33, 33, 33, 40, - 41, 41, 41, 41, 41, 41, 40, 41, - 41 + 1, 1, 14, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 0, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 39, 40, + 40, 40, 40, 40, 40, 40, 40, 40 }; -static const int khmer_syllable_machine_start = 22; -static const int khmer_syllable_machine_first_final = 22; +static const int khmer_syllable_machine_start = 20; +static const int khmer_syllable_machine_first_final = 20; static const int khmer_syllable_machine_error = -1; -static const int khmer_syllable_machine_en_main = 22; +static const int khmer_syllable_machine_en_main = 20; #line 36 "hb-ot-shape-complex-khmer-machine.rl" @@ -234,19 +226,19 @@ static const int khmer_syllable_machine_en_main = 22; HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | khmer_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_khmer (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; -#line 250 "hb-ot-shape-complex-khmer-machine.hh" +#line 242 "hb-ot-shape-complex-khmer-machine.hh" { cs = khmer_syllable_machine_start; ts = 0; @@ -262,7 +254,7 @@ find_syllables (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 266 "hb-ot-shape-complex-khmer-machine.hh" +#line 258 "hb-ot-shape-complex-khmer-machine.hh" { int _slen; int _trans; @@ -276,7 +268,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 280 "hb-ot-shape-complex-khmer-machine.hh" +#line 272 "hb-ot-shape-complex-khmer-machine.hh" } _keys = _khmer_syllable_machine_trans_keys + (cs<<1); @@ -346,7 +338,7 @@ _eof_trans: #line 76 "hb-ot-shape-complex-khmer-machine.rl" {act = 3;} break; -#line 350 "hb-ot-shape-complex-khmer-machine.hh" +#line 342 "hb-ot-shape-complex-khmer-machine.hh" } _again: @@ -355,7 +347,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 359 "hb-ot-shape-complex-khmer-machine.hh" +#line 351 "hb-ot-shape-complex-khmer-machine.hh" } if ( ++p != pe ) @@ -375,4 +367,6 @@ _again: } +#undef found_syllable + #endif /* HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.cc index f5437b39713..6be5d3731bf 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex-khmer.hh" #include "hb-ot-layout.hh" @@ -52,50 +56,35 @@ khmer_features[] = {HB_TAG('a','b','v','s'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('b','l','w','s'), F_GLOBAL_MANUAL_JOINERS}, {HB_TAG('p','s','t','s'), F_GLOBAL_MANUAL_JOINERS}, - /* - * Positioning features. - * We don't care about the types. - */ - {HB_TAG('d','i','s','t'), F_GLOBAL}, - {HB_TAG('a','b','v','m'), F_GLOBAL}, - {HB_TAG('b','l','w','m'), F_GLOBAL}, }; /* * Must be in the same order as the khmer_features array. */ enum { - PREF, - BLWF, - ABVF, - PSTF, - CFAR, - - _PRES, - _ABVS, - _BLWS, - _PSTS, + KHMER_PREF, + KHMER_BLWF, + KHMER_ABVF, + KHMER_PSTF, + KHMER_CFAR, - _DIST, - _ABVM, - _BLWM, + _KHMER_PRES, + _KHMER_ABVS, + _KHMER_BLWS, + _KHMER_PSTS, KHMER_NUM_FEATURES, - KHMER_BASIC_FEATURES = _PRES, /* Don't forget to update this! */ + KHMER_BASIC_FEATURES = _KHMER_PRES, /* Don't forget to update this! */ }; static void -setup_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +setup_syllables_khmer (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -clear_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +reorder_khmer (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void collect_features_khmer (hb_ot_shape_planner_t *plan) @@ -103,8 +92,8 @@ collect_features_khmer (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; /* Do this before any lookups have been applied. */ - map->add_gsub_pause (setup_syllables); - map->add_gsub_pause (reorder); + map->add_gsub_pause (setup_syllables_khmer); + map->add_gsub_pause (reorder_khmer); /* Testing suggests that Uniscribe does NOT pause between basic * features. Test with KhmerUI.ttf and the following three @@ -123,7 +112,7 @@ collect_features_khmer (hb_ot_shape_planner_t *plan) for (; i < KHMER_BASIC_FEATURES; i++) map->add_feature (khmer_features[i]); - map->add_gsub_pause (clear_syllables); + map->add_gsub_pause (_hb_clear_syllables); for (; i < KHMER_NUM_FEATURES; i++) map->add_feature (khmer_features[i]); @@ -149,32 +138,6 @@ override_features_khmer (hb_ot_shape_planner_t *plan) } -struct would_substitute_feature_t -{ - void init (const hb_ot_map_t *map, hb_tag_t feature_tag, bool zero_context_) - { - zero_context = zero_context_; - map->get_stage_lookups (0/*GSUB*/, - map->get_feature_stage (0/*GSUB*/, feature_tag), - &lookups, &count); - } - - bool would_substitute (const hb_codepoint_t *glyphs, - unsigned int glyphs_count, - hb_face_t *face) const - { - for (unsigned int i = 0; i < count; i++) - if (hb_ot_layout_lookup_would_substitute_fast (face, lookups[i].index, glyphs, glyphs_count, zero_context)) - return true; - return false; - } - - private: - const hb_ot_map_t::lookup_map_t *lookups; - unsigned int count; - bool zero_context; -}; - struct khmer_shape_plan_t { bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const @@ -198,8 +161,6 @@ struct khmer_shape_plan_t mutable hb_codepoint_t virama_glyph; - would_substitute_feature_t pref; - hb_mask_t mask_array[KHMER_NUM_FEATURES]; }; @@ -212,8 +173,6 @@ data_create_khmer (const hb_ot_shape_plan_t *plan) khmer_plan->virama_glyph = (hb_codepoint_t) -1; - khmer_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'), true); - for (unsigned int i = 0; i < ARRAY_LENGTH (khmer_plan->mask_array); i++) khmer_plan->mask_array[i] = (khmer_features[i].flags & F_GLOBAL) ? 0 : plan->map.get_1_mask (khmer_features[i].tag); @@ -228,10 +187,10 @@ data_destroy_khmer (void *data) } -enum syllable_type_t { - consonant_syllable, - broken_cluster, - non_khmer_cluster, +enum khmer_syllable_type_t { + khmer_consonant_syllable, + khmer_broken_cluster, + khmer_non_khmer_cluster, }; #include "hb-ot-shape-complex-khmer-machine.hh" @@ -253,11 +212,11 @@ setup_masks_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +setup_syllables_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { - find_syllables (buffer); + find_syllables_khmer (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); } @@ -278,7 +237,9 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, /* Setup masks. */ { /* Post-base */ - hb_mask_t mask = khmer_plan->mask_array[BLWF] | khmer_plan->mask_array[ABVF] | khmer_plan->mask_array[PSTF]; + hb_mask_t mask = khmer_plan->mask_array[KHMER_BLWF] | + khmer_plan->mask_array[KHMER_ABVF] | + khmer_plan->mask_array[KHMER_PSTF]; for (unsigned int i = start + 1; i < end; i++) info[i].mask |= mask; } @@ -305,7 +266,7 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, if (info[i + 1].khmer_category() == OT_Ra) { for (unsigned int j = 0; j < 2; j++) - info[i + j].mask |= khmer_plan->mask_array[PREF]; + info[i + j].mask |= khmer_plan->mask_array[KHMER_PREF]; /* Move the Coeng,Ro sequence to the start. */ buffer->merge_clusters (start, i + 2); @@ -321,9 +282,9 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, * U+1784,U+17D2,U+179A,U+17D2,U+1782 * U+1784,U+17D2,U+1782,U+17D2,U+179A */ - if (khmer_plan->mask_array[CFAR]) + if (khmer_plan->mask_array[KHMER_CFAR]) for (unsigned int j = i + 2; j < end; j++) - info[j].mask |= khmer_plan->mask_array[CFAR]; + info[j].mask |= khmer_plan->mask_array[KHMER_CFAR]; num_coengs = 2; /* Done. */ } @@ -342,35 +303,39 @@ reorder_consonant_syllable (const hb_ot_shape_plan_t *plan, } static void -initial_reordering_syllable (const hb_ot_shape_plan_t *plan, - hb_face_t *face, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) +reorder_syllable_khmer (const hb_ot_shape_plan_t *plan, + hb_face_t *face, + hb_buffer_t *buffer, + unsigned int start, unsigned int end) { - syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); + khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) { - case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */ - case consonant_syllable: + case khmer_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */ + case khmer_consonant_syllable: reorder_consonant_syllable (plan, face, buffer, start, end); break; - case non_khmer_cluster: + case khmer_non_khmer_cluster: break; } } static inline void -insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font, - hb_buffer_t *buffer) +insert_dotted_circles_khmer (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font, + hb_buffer_t *buffer) { - /* Note: This loop is extra overhead, but should not be measurable. */ + if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) + return; + + /* Note: This loop is extra overhead, but should not be measurable. + * TODO Use a buffer scratch flag to remove the loop. */ bool has_broken_syllables = false; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - if ((info[i].syllable() & 0x0F) == broken_cluster) + if ((info[i].syllable() & 0x0F) == khmer_broken_cluster) { has_broken_syllables = true; break; @@ -395,8 +360,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, while (buffer->idx < buffer->len && buffer->successful) { unsigned int syllable = buffer->cur().syllable(); - syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); - if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) + khmer_syllable_type_t syllable_type = (khmer_syllable_type_t) (syllable & 0x0F); + if (unlikely (last_syllable != syllable && syllable_type == khmer_broken_cluster)) { last_syllable = syllable; @@ -404,7 +369,6 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, ginfo.cluster = buffer->cur().cluster; ginfo.mask = buffer->cur().mask; ginfo.syllable() = buffer->cur().syllable(); - /* TODO Set glyph_props? */ /* Insert dottedcircle after possible Repha. */ while (buffer->idx < buffer->len && buffer->successful && @@ -421,29 +385,18 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +reorder_khmer (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { - insert_dotted_circles (plan, font, buffer); + insert_dotted_circles_khmer (plan, font, buffer); foreach_syllable (buffer, start, end) - initial_reordering_syllable (plan, font->face, buffer, start, end); + reorder_syllable_khmer (plan, font->face, buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category); } -static void -clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - info[i].syllable() = 0; -} - static bool decompose_khmer (const hb_ot_shape_normalize_context_t *c, @@ -499,3 +452,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_khmer = HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ }; + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.hh index 4b94cae1f13..b809d8e4f66 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-khmer.hh @@ -43,11 +43,10 @@ enum khmer_category_t OT_Robatic = 20, OT_Xgroup = 21, OT_Ygroup = 22, - - OT_VAbv = 26, - OT_VBlw = 27, - OT_VPre = 28, - OT_VPst = 29, + //OT_VAbv = 26, + //OT_VBlw = 27, + //OT_VPre = 28, + //OT_VPst = 29, }; static inline void @@ -100,12 +99,12 @@ set_khmer_properties (hb_glyph_info_t &info) if (cat == (khmer_category_t) OT_M) switch ((int) pos) { - case POS_PRE_C: cat = OT_VPre; break; - case POS_BELOW_C: cat = OT_VBlw; break; - case POS_ABOVE_C: cat = OT_VAbv; break; - case POS_POST_C: cat = OT_VPst; break; + case POS_PRE_C: cat = (khmer_category_t) OT_VPre; break; + case POS_BELOW_C: cat = (khmer_category_t) OT_VBlw; break; + case POS_ABOVE_C: cat = (khmer_category_t) OT_VAbv; break; + case POS_POST_C: cat = (khmer_category_t) OT_VPst; break; default: assert (0); - }; + } info.khmer_category() = cat; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar-machine.hh index 7364d6b400d..c011c9f6a38 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar-machine.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar-machine.hh @@ -36,29 +36,31 @@ static const unsigned char _myanmar_syllable_machine_trans_keys[] = { 1u, 32u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u, - 3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 5u, 29u, - 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u, 3u, 29u, - 3u, 29u, 3u, 30u, 3u, 29u, 1u, 32u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, - 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 32u, 8u, 8u, - 0 + 3u, 29u, 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, + 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u, 3u, 29u, 3u, 29u, + 3u, 29u, 3u, 29u, 1u, 16u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, + 3u, 29u, 3u, 30u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 3u, 30u, + 3u, 29u, 1u, 32u, 1u, 32u, 8u, 8u, 0 }; static const char _myanmar_syllable_machine_key_spans[] = { 32, 28, 25, 4, 25, 23, 21, 21, 27, 27, 27, 27, 16, 27, 27, 27, - 27, 27, 28, 27, 27, 27, 27, 25, - 4, 25, 23, 21, 21, 27, 27, 27, - 27, 28, 27, 32, 27, 27, 27, 27, - 27, 28, 27, 27, 27, 27, 32, 1 + 27, 27, 28, 27, 27, 27, 27, 27, + 25, 4, 25, 23, 21, 21, 27, 27, + 27, 27, 16, 28, 27, 27, 27, 27, + 27, 28, 27, 27, 27, 27, 27, 28, + 27, 32, 32, 1 }; static const short _myanmar_syllable_machine_index_offsets[] = { 0, 33, 62, 88, 93, 119, 143, 165, 187, 215, 243, 271, 299, 316, 344, 372, 400, 428, 456, 485, 513, 541, 569, 597, - 623, 628, 654, 678, 700, 722, 750, 778, - 806, 834, 863, 891, 924, 952, 980, 1008, - 1036, 1064, 1093, 1121, 1149, 1177, 1205, 1238 + 625, 651, 656, 682, 706, 728, 750, 778, + 806, 834, 862, 879, 908, 936, 964, 992, + 1020, 1048, 1077, 1105, 1133, 1161, 1189, 1217, + 1246, 1274, 1307, 1340 }; static const char _myanmar_syllable_machine_indicies[] = { @@ -124,120 +126,134 @@ static const char _myanmar_syllable_machine_indicies[] = { 21, 21, 21, 21, 21, 21, 32, 33, 34, 35, 36, 43, 21, 22, 21, 24, 24, 21, 25, 21, 26, 21, 21, 21, - 21, 21, 21, 21, 43, 21, 21, 28, + 21, 21, 21, 21, 21, 21, 21, 28, 21, 30, 21, 32, 33, 34, 35, 36, 21, 22, 21, 24, 24, 21, 25, 21, 26, 21, 21, 21, 21, 21, 21, 21, 43, 21, 21, 28, 21, 21, 21, 32, 33, 34, 35, 36, 21, 22, 21, 24, 24, 21, 25, 21, 26, 21, 21, 21, - 21, 21, 21, 21, 43, 21, 21, 28, + 21, 21, 21, 21, 44, 21, 21, 28, 29, 30, 21, 32, 33, 34, 35, 36, - 21, 22, 23, 24, 24, 21, 25, 21, + 21, 22, 21, 24, 24, 21, 25, 21, 26, 21, 21, 21, 21, 21, 21, 21, - 27, 21, 21, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 21, 3, 3, 44, - 5, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 45, 44, 44, 44, 44, 44, - 44, 14, 44, 44, 44, 18, 44, 3, - 3, 44, 5, 44, 3, 3, 44, 5, - 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, - 14, 44, 44, 44, 18, 44, 46, 44, - 3, 3, 44, 5, 44, 14, 44, 44, - 44, 44, 44, 44, 44, 47, 44, 44, - 44, 44, 44, 44, 14, 44, 3, 3, - 44, 5, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 47, 44, 44, 44, 44, - 44, 44, 14, 44, 3, 3, 44, 5, - 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, - 14, 44, 2, 44, 3, 3, 44, 5, - 44, 6, 44, 44, 44, 44, 44, 44, - 44, 48, 44, 44, 48, 44, 44, 44, - 14, 49, 44, 44, 18, 44, 2, 44, - 3, 3, 44, 5, 44, 6, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 14, 44, 44, 44, - 18, 44, 2, 44, 3, 3, 44, 5, - 44, 6, 44, 44, 44, 44, 44, 44, - 44, 48, 44, 44, 44, 44, 44, 44, - 14, 49, 44, 44, 18, 44, 2, 44, - 3, 3, 44, 5, 44, 6, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 14, 49, 44, 44, - 18, 44, 22, 23, 24, 24, 21, 25, - 21, 26, 21, 21, 21, 21, 21, 21, - 21, 50, 21, 21, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 21, 22, - 51, 24, 24, 21, 25, 21, 26, 21, - 21, 21, 21, 21, 21, 21, 27, 21, - 21, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 21, 1, 1, 2, 3, 3, - 3, 44, 5, 44, 6, 1, 44, 44, - 44, 44, 1, 44, 8, 44, 44, 10, + 21, 21, 21, 28, 29, 30, 21, 32, + 33, 34, 35, 36, 21, 22, 23, 24, + 24, 21, 25, 21, 26, 21, 21, 21, + 21, 21, 21, 21, 27, 21, 21, 28, + 29, 30, 31, 32, 33, 34, 35, 36, + 21, 46, 46, 45, 5, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 47, 45, + 45, 45, 45, 45, 45, 14, 45, 45, + 45, 18, 45, 46, 46, 45, 5, 45, + 46, 46, 45, 5, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 14, 45, 45, 45, + 18, 45, 48, 45, 46, 46, 45, 5, + 45, 14, 45, 45, 45, 45, 45, 45, + 45, 49, 45, 45, 45, 45, 45, 45, + 14, 45, 46, 46, 45, 5, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 49, + 45, 45, 45, 45, 45, 45, 14, 45, + 46, 46, 45, 5, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 14, 45, 2, 45, + 46, 46, 45, 5, 45, 6, 45, 45, + 45, 45, 45, 45, 45, 50, 45, 45, + 50, 45, 45, 45, 14, 51, 45, 45, + 18, 45, 2, 45, 46, 46, 45, 5, + 45, 6, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 14, 45, 45, 45, 18, 45, 2, 45, + 46, 46, 45, 5, 45, 6, 45, 45, + 45, 45, 45, 45, 45, 50, 45, 45, + 45, 45, 45, 45, 14, 51, 45, 45, + 18, 45, 2, 45, 46, 46, 45, 5, + 45, 6, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 14, 51, 45, 45, 18, 45, 52, 52, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 52, 45, 2, + 3, 46, 46, 45, 5, 45, 6, 45, + 45, 45, 45, 45, 45, 45, 8, 45, + 45, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 45, 2, 45, 46, 46, + 45, 5, 45, 6, 45, 45, 45, 45, + 45, 45, 45, 8, 45, 45, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 45, + 2, 45, 46, 46, 45, 5, 45, 6, + 45, 45, 45, 45, 45, 45, 45, 53, + 45, 45, 45, 45, 45, 45, 14, 15, + 16, 17, 18, 45, 2, 45, 46, 46, + 45, 5, 45, 6, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 14, 15, 16, 17, 18, 45, + 2, 45, 46, 46, 45, 5, 45, 6, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 14, 15, + 16, 45, 18, 45, 2, 45, 46, 46, + 45, 5, 45, 6, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 14, 45, 16, 45, 18, 45, + 2, 45, 46, 46, 45, 5, 45, 6, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 14, 15, + 16, 17, 18, 53, 45, 2, 45, 46, + 46, 45, 5, 45, 6, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 10, + 45, 12, 45, 14, 15, 16, 17, 18, + 45, 2, 45, 46, 46, 45, 5, 45, + 6, 45, 45, 45, 45, 45, 45, 45, + 53, 45, 45, 10, 45, 45, 45, 14, + 15, 16, 17, 18, 45, 2, 45, 46, + 46, 45, 5, 45, 6, 45, 45, 45, + 45, 45, 45, 45, 54, 45, 45, 10, + 11, 12, 45, 14, 15, 16, 17, 18, + 45, 2, 45, 46, 46, 45, 5, 45, + 6, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 10, 11, 12, 45, 14, + 15, 16, 17, 18, 45, 2, 3, 46, + 46, 45, 5, 45, 6, 45, 45, 45, + 45, 45, 45, 45, 8, 45, 45, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 44, 1, 44, 2, 44, 3, 3, - 44, 5, 44, 6, 44, 44, 44, 44, - 44, 44, 44, 8, 44, 44, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 44, - 2, 44, 3, 3, 44, 5, 44, 6, - 44, 44, 44, 44, 44, 44, 44, 52, - 44, 44, 44, 44, 44, 44, 14, 15, - 16, 17, 18, 44, 2, 44, 3, 3, - 44, 5, 44, 6, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 14, 15, 16, 17, 18, 44, - 2, 44, 3, 3, 44, 5, 44, 6, - 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 14, 15, - 16, 44, 18, 44, 2, 44, 3, 3, - 44, 5, 44, 6, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 14, 44, 16, 44, 18, 44, - 2, 44, 3, 3, 44, 5, 44, 6, - 44, 44, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 14, 15, - 16, 17, 18, 52, 44, 2, 44, 3, - 3, 44, 5, 44, 6, 44, 44, 44, - 44, 44, 44, 44, 52, 44, 44, 10, - 44, 12, 44, 14, 15, 16, 17, 18, - 44, 2, 44, 3, 3, 44, 5, 44, - 6, 44, 44, 44, 44, 44, 44, 44, - 52, 44, 44, 10, 44, 44, 44, 14, - 15, 16, 17, 18, 44, 2, 44, 3, - 3, 44, 5, 44, 6, 44, 44, 44, - 44, 44, 44, 44, 52, 44, 44, 10, - 11, 12, 44, 14, 15, 16, 17, 18, - 44, 2, 3, 3, 3, 44, 5, 44, - 6, 44, 44, 44, 44, 44, 44, 44, - 8, 44, 44, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 44, 1, 1, 53, - 53, 53, 53, 53, 53, 53, 53, 1, - 53, 53, 53, 53, 1, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 1, 53, 54, 53, - 0 + 45, 22, 23, 24, 24, 21, 25, 21, + 26, 21, 21, 21, 21, 21, 21, 21, + 55, 21, 21, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 21, 22, 56, + 24, 24, 21, 25, 21, 26, 21, 21, + 21, 21, 21, 21, 21, 27, 21, 21, + 28, 29, 30, 31, 32, 33, 34, 35, + 36, 21, 1, 1, 2, 3, 46, 46, + 45, 5, 45, 6, 1, 45, 45, 45, + 45, 1, 45, 8, 45, 45, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 19, + 45, 1, 45, 1, 1, 57, 57, 57, + 57, 57, 57, 57, 57, 1, 57, 57, + 57, 57, 1, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 1, 57, 58, 57, 0 }; static const char _myanmar_syllable_machine_trans_targs[] = { - 0, 1, 23, 0, 0, 24, 30, 33, - 36, 46, 37, 42, 43, 44, 26, 39, - 40, 41, 29, 45, 47, 0, 2, 12, + 0, 1, 24, 34, 0, 25, 31, 47, + 36, 50, 37, 42, 43, 44, 27, 39, + 40, 41, 30, 46, 51, 0, 2, 12, 0, 3, 9, 13, 14, 19, 20, 21, - 5, 16, 17, 18, 8, 22, 4, 6, - 7, 10, 11, 15, 0, 25, 27, 28, - 31, 32, 34, 35, 38, 0, 0 + 5, 16, 17, 18, 8, 23, 4, 6, + 7, 10, 11, 15, 22, 0, 0, 26, + 28, 29, 32, 33, 35, 38, 45, 48, + 49, 0, 0 }; static const char _myanmar_syllable_machine_trans_actions[] = { - 3, 0, 0, 4, 5, 0, 0, 0, + 3, 0, 0, 0, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5, 0, 0, + 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 6, 0, 0, - 7, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 8, 0, 0, 0, - 0, 0, 0, 0, 0, 9, 10 + 0, 9, 10 }; static const char _myanmar_syllable_machine_to_state_actions[] = { @@ -246,7 +262,8 @@ static const char _myanmar_syllable_machine_to_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 }; static const char _myanmar_syllable_machine_from_state_actions[] = { @@ -255,16 +272,18 @@ static const char _myanmar_syllable_machine_from_state_actions[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0 }; static const short _myanmar_syllable_machine_eof_trans[] = { 0, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 45, - 45, 45, 45, 45, 45, 45, 45, 45, - 45, 22, 22, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 45, 45, 54, 54 + 22, 22, 22, 22, 22, 22, 22, 22, + 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 22, + 22, 46, 58, 58 }; static const int myanmar_syllable_machine_start = 0; @@ -285,19 +304,19 @@ static const int myanmar_syllable_machine_en_main = 0; HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | myanmar_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_myanmar (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act HB_UNUSED; int cs; hb_glyph_info_t *info = buffer->info; -#line 301 "hb-ot-shape-complex-myanmar-machine.hh" +#line 320 "hb-ot-shape-complex-myanmar-machine.hh" { cs = myanmar_syllable_machine_start; ts = 0; @@ -313,7 +332,7 @@ find_syllables (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 317 "hb-ot-shape-complex-myanmar-machine.hh" +#line 336 "hb-ot-shape-complex-myanmar-machine.hh" { int _slen; int _trans; @@ -327,7 +346,7 @@ _resume: #line 1 "NONE" {ts = p;} break; -#line 331 "hb-ot-shape-complex-myanmar-machine.hh" +#line 350 "hb-ot-shape-complex-myanmar-machine.hh" } _keys = _myanmar_syllable_machine_trans_keys + (cs<<1); @@ -345,11 +364,11 @@ _eof_trans: goto _again; switch ( _myanmar_syllable_machine_trans_actions[_trans] ) { - case 7: + case 6: #line 86 "hb-ot-shape-complex-myanmar-machine.rl" {te = p+1;{ found_syllable (consonant_syllable); }} break; - case 5: + case 4: #line 87 "hb-ot-shape-complex-myanmar-machine.rl" {te = p+1;{ found_syllable (non_myanmar_cluster); }} break; @@ -357,7 +376,7 @@ _eof_trans: #line 88 "hb-ot-shape-complex-myanmar-machine.rl" {te = p+1;{ found_syllable (punctuation_cluster); }} break; - case 4: + case 8: #line 89 "hb-ot-shape-complex-myanmar-machine.rl" {te = p+1;{ found_syllable (broken_cluster); }} break; @@ -365,11 +384,11 @@ _eof_trans: #line 90 "hb-ot-shape-complex-myanmar-machine.rl" {te = p+1;{ found_syllable (non_myanmar_cluster); }} break; - case 6: + case 5: #line 86 "hb-ot-shape-complex-myanmar-machine.rl" {te = p;p--;{ found_syllable (consonant_syllable); }} break; - case 8: + case 7: #line 89 "hb-ot-shape-complex-myanmar-machine.rl" {te = p;p--;{ found_syllable (broken_cluster); }} break; @@ -377,7 +396,7 @@ _eof_trans: #line 90 "hb-ot-shape-complex-myanmar-machine.rl" {te = p;p--;{ found_syllable (non_myanmar_cluster); }} break; -#line 381 "hb-ot-shape-complex-myanmar-machine.hh" +#line 400 "hb-ot-shape-complex-myanmar-machine.hh" } _again: @@ -386,7 +405,7 @@ _again: #line 1 "NONE" {ts = 0;} break; -#line 390 "hb-ot-shape-complex-myanmar-machine.hh" +#line 409 "hb-ot-shape-complex-myanmar-machine.hh" } if ( ++p != pe ) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.cc index e84c8f4adc6..03b93a63548 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex-myanmar.hh" @@ -32,7 +36,7 @@ */ static const hb_tag_t -basic_features[] = +myanmar_basic_features[] = { /* * Basic features. @@ -44,7 +48,7 @@ basic_features[] = HB_TAG('p','s','t','f'), }; static const hb_tag_t -other_features[] = +myanmar_other_features[] = { /* * Other features. @@ -55,36 +59,13 @@ other_features[] = HB_TAG('b','l','w','s'), HB_TAG('p','s','t','s'), }; -static const hb_tag_t -positioning_features[] = -{ - /* - * Positioning features. - * We don't care about the types. - */ - HB_TAG('d','i','s','t'), - /* Pre-release version of Windows 8 Myanmar font had abvm,blwm - * features. The released Windows 8 version of the font (as well - * as the released spec) used 'mark' instead. The Windows 8 - * shaper however didn't apply 'mark' but did apply 'mkmk'. - * Perhaps it applied abvm/blwm. This was fixed in a Windows 8 - * update, so now it applies mark/mkmk. We are guessing that - * it still applies abvm/blwm too. - */ - HB_TAG('a','b','v','m'), - HB_TAG('b','l','w','m'), -}; static void -setup_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +setup_syllables_myanmar (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -clear_syllables (const hb_ot_shape_plan_t *plan, +reorder_myanmar (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); @@ -94,7 +75,7 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; /* Do this before any lookups have been applied. */ - map->add_gsub_pause (setup_syllables); + map->add_gsub_pause (setup_syllables_myanmar); map->enable_feature (HB_TAG('l','o','c','l')); /* The Indic specs do not require ccmp, but we apply it here since if @@ -102,21 +83,18 @@ collect_features_myanmar (hb_ot_shape_planner_t *plan) map->enable_feature (HB_TAG('c','c','m','p')); - map->add_gsub_pause (reorder); + map->add_gsub_pause (reorder_myanmar); - for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) + for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++) { - map->enable_feature (basic_features[i], F_MANUAL_ZWJ); + map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ); map->add_gsub_pause (nullptr); } - map->add_gsub_pause (clear_syllables); + map->add_gsub_pause (_hb_clear_syllables); - for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) - map->enable_feature (other_features[i], F_MANUAL_ZWJ); - - for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++) - map->enable_feature (positioning_features[i]); + for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++) + map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ); } static void @@ -126,11 +104,11 @@ override_features_myanmar (hb_ot_shape_planner_t *plan) } -enum syllable_type_t { - consonant_syllable, - punctuation_cluster, - broken_cluster, - non_myanmar_cluster, +enum myanmar_syllable_type_t { + myanmar_consonant_syllable, + myanmar_punctuation_cluster, + myanmar_broken_cluster, + myanmar_non_myanmar_cluster, }; #include "hb-ot-shape-complex-myanmar-machine.hh" @@ -138,8 +116,8 @@ enum syllable_type_t { static void setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_buffer_t *buffer, - hb_font_t *font HB_UNUSED) + hb_buffer_t *buffer, + hb_font_t *font HB_UNUSED) { HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category); HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position); @@ -154,11 +132,11 @@ setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { - find_syllables (buffer); + find_syllables_myanmar (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); } @@ -274,36 +252,40 @@ initial_reordering_consonant_syllable (hb_buffer_t *buffer, } static void -initial_reordering_syllable (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_face_t *face HB_UNUSED, - hb_buffer_t *buffer, - unsigned int start, unsigned int end) +reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_face_t *face HB_UNUSED, + hb_buffer_t *buffer, + unsigned int start, unsigned int end) { - syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); + myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (buffer->info[start].syllable() & 0x0F); switch (syllable_type) { - case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */ - case consonant_syllable: + case myanmar_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */ + case myanmar_consonant_syllable: initial_reordering_consonant_syllable (buffer, start, end); break; - case punctuation_cluster: - case non_myanmar_cluster: + case myanmar_punctuation_cluster: + case myanmar_non_myanmar_cluster: break; } } static inline void -insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font, - hb_buffer_t *buffer) +insert_dotted_circles_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font, + hb_buffer_t *buffer) { - /* Note: This loop is extra overhead, but should not be measurable. */ + if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) + return; + + /* Note: This loop is extra overhead, but should not be measurable. + * TODO Use a buffer scratch flag to remove the loop. */ bool has_broken_syllables = false; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - if ((info[i].syllable() & 0x0F) == broken_cluster) + if ((info[i].syllable() & 0x0F) == myanmar_broken_cluster) { has_broken_syllables = true; break; @@ -328,8 +310,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, while (buffer->idx < buffer->len && buffer->successful) { unsigned int syllable = buffer->cur().syllable(); - syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); - if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) + myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (syllable & 0x0F); + if (unlikely (last_syllable != syllable && syllable_type == myanmar_broken_cluster)) { last_syllable = syllable; @@ -347,30 +329,19 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +reorder_myanmar (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { - insert_dotted_circles (plan, font, buffer); + insert_dotted_circles_myanmar (plan, font, buffer); foreach_syllable (buffer, start, end) - initial_reordering_syllable (plan, font->face, buffer, start, end); + reorder_syllable_myanmar (plan, font->face, buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category); HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position); } -static void -clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - info[i].syllable() = 0; -} - const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar = { @@ -411,3 +382,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi = HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE, false, /* fallback_position */ }; + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.hh index 86717a95004..4adbc5ae3d3 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-myanmar.hh @@ -49,10 +49,10 @@ enum myanmar_category_t { OT_MW = 23, /* Various consonant medial types */ OT_MY = 24, /* Various consonant medial types */ OT_PT = 25, /* Pwo and other tones */ - OT_VAbv = 26, - OT_VBlw = 27, - OT_VPre = 28, - OT_VPst = 29, + //OT_VAbv = 26, + //OT_VBlw = 27, + //OT_VPre = 28, + //OT_VPst = 29, OT_VS = 30, /* Variation selectors */ OT_P = 31, /* Punctuation */ OT_D = 32, /* Digits except zero */ @@ -146,7 +146,7 @@ set_myanmar_properties (hb_glyph_info_t &info) break; case 0xAA74u: case 0xAA75u: case 0xAA76u: - /* https://github.com/roozbehp/unicode-data/issues/3 */ + /* https://github.com/harfbuzz/harfbuzz/issues/218 */ cat = OT_C; break; } @@ -155,11 +155,11 @@ set_myanmar_properties (hb_glyph_info_t &info) { switch ((int) pos) { - case POS_PRE_C: cat = OT_VPre; + case POS_PRE_C: cat = (myanmar_category_t) OT_VPre; pos = POS_PRE_M; break; - case POS_ABOVE_C: cat = OT_VAbv; break; - case POS_BELOW_C: cat = OT_VBlw; break; - case POS_POST_C: cat = OT_VPst; break; + case POS_ABOVE_C: cat = (myanmar_category_t) OT_VAbv; break; + case POS_BELOW_C: cat = (myanmar_category_t) OT_VBlw; break; + case POS_POST_C: cat = (myanmar_category_t) OT_VPst; break; } } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-thai.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-thai.cc index b13697b9e18..e18a06baa12 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-thai.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-thai.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex.hh" @@ -218,6 +222,10 @@ do_thai_pua_shaping (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_buffer_t *buffer, hb_font_t *font) { +#ifdef HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK + return; +#endif + thai_above_state_t above_state = thai_above_start_state[NOT_CONSONANT]; thai_below_state_t below_state = thai_below_start_state[NOT_CONSONANT]; unsigned int base = 0; @@ -381,3 +389,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_thai = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE, false,/* fallback_position */ }; + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-machine.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-machine.hh index 3d0271b1ee4..796b611ba66 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-machine.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-machine.hh @@ -36,36 +36,42 @@ #line 38 "hb-ot-shape-complex-use-machine.hh" static const unsigned char _use_syllable_machine_trans_keys[] = { - 12u, 44u, 1u, 15u, 1u, 1u, 12u, 44u, 0u, 44u, 21u, 21u, 8u, 44u, 8u, 44u, - 1u, 15u, 1u, 1u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, - 8u, 39u, 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, - 8u, 44u, 8u, 44u, 8u, 44u, 1u, 39u, 8u, 44u, 13u, 21u, 4u, 4u, 13u, 13u, - 8u, 44u, 8u, 44u, 8u, 44u, 8u, 39u, 8u, 26u, 8u, 26u, 8u, 26u, 8u, 39u, - 8u, 39u, 8u, 39u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, 8u, 44u, - 8u, 44u, 8u, 44u, 1u, 39u, 1u, 15u, 12u, 44u, 1u, 44u, 8u, 44u, 21u, 42u, - 41u, 42u, 42u, 42u, 1u, 5u, 0 + 12u, 48u, 1u, 15u, 1u, 1u, 12u, 48u, 1u, 1u, 0u, 48u, 21u, 21u, 11u, 48u, + 11u, 48u, 1u, 15u, 1u, 1u, 11u, 48u, 22u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, + 26u, 47u, 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 1u, 1u, 24u, 48u, + 23u, 48u, 23u, 48u, 23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 11u, 48u, + 1u, 48u, 11u, 48u, 13u, 21u, 4u, 4u, 13u, 13u, 11u, 48u, 11u, 48u, 41u, 42u, + 42u, 42u, 11u, 48u, 11u, 48u, 22u, 48u, 23u, 48u, 24u, 47u, 25u, 47u, 26u, 47u, + 45u, 46u, 46u, 46u, 24u, 48u, 24u, 48u, 24u, 48u, 24u, 48u, 23u, 48u, 23u, 48u, + 23u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 22u, 48u, 11u, 48u, 1u, 48u, 1u, 15u, + 4u, 4u, 13u, 21u, 13u, 13u, 12u, 48u, 1u, 48u, 11u, 48u, 41u, 42u, 42u, 42u, + 21u, 42u, 1u, 5u, 0 }; static const char _use_syllable_machine_key_spans[] = { - 33, 15, 1, 33, 45, 1, 37, 37, - 15, 1, 37, 37, 32, 19, 19, 19, - 32, 32, 32, 37, 37, 37, 37, 37, - 37, 37, 37, 39, 37, 9, 1, 1, - 37, 37, 37, 32, 19, 19, 19, 32, - 32, 32, 37, 37, 37, 37, 37, 37, - 37, 37, 39, 15, 33, 44, 37, 22, - 2, 1, 5 + 37, 15, 1, 37, 1, 49, 1, 38, + 38, 15, 1, 38, 27, 26, 24, 23, + 22, 2, 1, 25, 25, 25, 1, 25, + 26, 26, 26, 27, 27, 27, 27, 38, + 48, 38, 9, 1, 1, 38, 38, 2, + 1, 38, 38, 27, 26, 24, 23, 22, + 2, 1, 25, 25, 25, 25, 26, 26, + 26, 27, 27, 27, 27, 38, 48, 15, + 1, 9, 1, 37, 48, 38, 2, 1, + 22, 5 }; static const short _use_syllable_machine_index_offsets[] = { - 0, 34, 50, 52, 86, 132, 134, 172, - 210, 226, 228, 266, 304, 337, 357, 377, - 397, 430, 463, 496, 534, 572, 610, 648, - 686, 724, 762, 800, 840, 878, 888, 890, - 892, 930, 968, 1006, 1039, 1059, 1079, 1099, - 1132, 1165, 1198, 1236, 1274, 1312, 1350, 1388, - 1426, 1464, 1502, 1542, 1558, 1592, 1637, 1675, - 1698, 1701, 1703 + 0, 38, 54, 56, 94, 96, 146, 148, + 187, 226, 242, 244, 283, 311, 338, 363, + 387, 410, 413, 415, 441, 467, 493, 495, + 521, 548, 575, 602, 630, 658, 686, 714, + 753, 802, 841, 851, 853, 855, 894, 933, + 936, 938, 977, 1016, 1044, 1071, 1096, 1120, + 1143, 1146, 1148, 1174, 1200, 1226, 1252, 1279, + 1306, 1333, 1361, 1389, 1417, 1445, 1484, 1533, + 1549, 1551, 1561, 1563, 1601, 1650, 1689, 1692, + 1694, 1717 }; static const char _use_syllable_machine_indicies[] = { @@ -73,308 +79,320 @@ static const char _use_syllable_machine_indicies[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 0, 3, 2, 2, 2, 2, 2, + 1, 0, 0, 0, 1, 0, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 4, 2, 3, 2, 6, 5, 5, 5, + 2, 2, 2, 2, 4, 2, 3, 2, + 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 6, 5, 7, 8, - 9, 7, 10, 8, 9, 9, 11, 9, - 9, 3, 12, 9, 9, 13, 7, 7, - 14, 15, 9, 9, 16, 17, 18, 19, - 20, 21, 22, 16, 23, 24, 25, 26, - 27, 28, 9, 29, 30, 31, 9, 9, - 9, 32, 33, 9, 35, 34, 37, 36, - 36, 38, 1, 36, 36, 39, 36, 36, - 36, 36, 36, 40, 41, 42, 43, 44, - 45, 46, 47, 41, 48, 40, 49, 50, - 51, 52, 36, 53, 54, 55, 36, 36, - 36, 36, 56, 36, 37, 36, 36, 38, - 1, 36, 36, 39, 36, 36, 36, 36, - 36, 57, 41, 42, 43, 44, 45, 46, - 47, 41, 48, 49, 49, 50, 51, 52, - 36, 53, 54, 55, 36, 36, 36, 36, - 56, 36, 38, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, - 59, 58, 38, 58, 37, 36, 36, 38, - 1, 36, 36, 39, 36, 36, 36, 36, - 36, 36, 41, 42, 43, 44, 45, 46, - 47, 41, 48, 49, 49, 50, 51, 52, - 36, 53, 54, 55, 36, 36, 36, 36, - 56, 36, 37, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 41, 42, 43, 44, 45, 36, 36, 36, - 36, 36, 36, 50, 51, 52, 36, 53, - 54, 55, 36, 36, 36, 36, 42, 36, - 37, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 42, - 43, 44, 45, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 53, 54, 55, - 36, 37, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 43, 44, 45, 36, 37, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 44, 45, - 36, 37, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 45, 36, 37, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 43, 44, 45, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 53, 54, 55, 36, 37, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 43, 44, - 45, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 54, 55, 36, 37, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 43, - 44, 45, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 55, 36, - 37, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 42, - 43, 44, 45, 36, 36, 36, 36, 36, - 36, 50, 51, 52, 36, 53, 54, 55, - 36, 36, 36, 36, 42, 36, 37, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 42, 43, 44, - 45, 36, 36, 36, 36, 36, 36, 36, - 51, 52, 36, 53, 54, 55, 36, 36, - 36, 36, 42, 36, 37, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 42, 43, 44, 45, 36, - 36, 36, 36, 36, 36, 36, 36, 52, - 36, 53, 54, 55, 36, 36, 36, 36, - 42, 36, 37, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 41, 42, 43, 44, 45, 36, 47, 41, - 36, 36, 36, 50, 51, 52, 36, 53, - 54, 55, 36, 36, 36, 36, 42, 36, - 37, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 41, 42, - 43, 44, 45, 36, 60, 41, 36, 36, - 36, 50, 51, 52, 36, 53, 54, 55, - 36, 36, 36, 36, 42, 36, 37, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 41, 42, 43, 44, - 45, 36, 36, 41, 36, 36, 36, 50, - 51, 52, 36, 53, 54, 55, 36, 36, - 36, 36, 42, 36, 37, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 41, 42, 43, 44, 45, 46, - 47, 41, 36, 36, 36, 50, 51, 52, - 36, 53, 54, 55, 36, 36, 36, 36, - 42, 36, 37, 36, 36, 38, 1, 36, - 36, 39, 36, 36, 36, 36, 36, 36, - 41, 42, 43, 44, 45, 46, 47, 41, - 48, 36, 49, 50, 51, 52, 36, 53, - 54, 55, 36, 36, 36, 36, 56, 36, - 38, 58, 58, 58, 58, 58, 58, 37, - 58, 58, 58, 58, 58, 58, 59, 58, - 58, 58, 58, 58, 58, 58, 42, 43, - 44, 45, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 53, 54, 55, 58, - 37, 36, 36, 38, 1, 36, 36, 39, - 36, 36, 36, 36, 36, 36, 41, 42, - 43, 44, 45, 46, 47, 41, 48, 40, - 49, 50, 51, 52, 36, 53, 54, 55, - 36, 36, 36, 36, 56, 36, 62, 61, - 61, 61, 61, 61, 61, 61, 63, 61, - 10, 64, 62, 61, 11, 65, 65, 3, - 6, 65, 65, 66, 65, 65, 65, 65, - 65, 67, 16, 17, 18, 19, 20, 21, - 22, 16, 23, 25, 25, 26, 27, 28, - 65, 29, 30, 31, 65, 65, 65, 65, - 33, 65, 11, 65, 65, 3, 6, 65, - 65, 66, 65, 65, 65, 65, 65, 65, - 16, 17, 18, 19, 20, 21, 22, 16, - 23, 25, 25, 26, 27, 28, 65, 29, - 30, 31, 65, 65, 65, 65, 33, 65, - 11, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 16, 17, - 18, 19, 20, 65, 65, 65, 65, 65, - 65, 26, 27, 28, 65, 29, 30, 31, - 65, 65, 65, 65, 17, 65, 11, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 17, 18, 19, - 20, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 29, 30, 31, 65, 11, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 18, - 19, 20, 65, 11, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 19, 20, 65, 11, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 20, 65, 11, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 18, 19, 20, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 29, 30, 31, 65, 11, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 18, 19, 20, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 30, 31, 65, 11, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 18, 19, 20, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 31, 65, 11, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 17, 18, 19, - 20, 65, 65, 65, 65, 65, 65, 26, - 27, 28, 65, 29, 30, 31, 65, 65, - 65, 65, 17, 65, 11, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 17, 18, 19, 20, 65, - 65, 65, 65, 65, 65, 65, 27, 28, - 65, 29, 30, 31, 65, 65, 65, 65, - 17, 65, 11, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 17, 18, 19, 20, 65, 65, 65, - 65, 65, 65, 65, 65, 28, 65, 29, - 30, 31, 65, 65, 65, 65, 17, 65, - 11, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 16, 17, - 18, 19, 20, 65, 22, 16, 65, 65, - 65, 26, 27, 28, 65, 29, 30, 31, - 65, 65, 65, 65, 17, 65, 11, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 16, 17, 18, 19, - 20, 65, 68, 16, 65, 65, 65, 26, - 27, 28, 65, 29, 30, 31, 65, 65, - 65, 65, 17, 65, 11, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 16, 17, 18, 19, 20, 65, - 65, 16, 65, 65, 65, 26, 27, 28, - 65, 29, 30, 31, 65, 65, 65, 65, - 17, 65, 11, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, - 16, 17, 18, 19, 20, 21, 22, 16, - 65, 65, 65, 26, 27, 28, 65, 29, - 30, 31, 65, 65, 65, 65, 17, 65, - 11, 65, 65, 3, 6, 65, 65, 66, - 65, 65, 65, 65, 65, 65, 16, 17, - 18, 19, 20, 21, 22, 16, 23, 65, - 25, 26, 27, 28, 65, 29, 30, 31, - 65, 65, 65, 65, 33, 65, 3, 65, - 65, 65, 65, 65, 65, 11, 65, 65, - 65, 65, 65, 65, 4, 65, 65, 65, - 65, 65, 65, 65, 17, 18, 19, 20, - 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 29, 30, 31, 65, 3, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 4, 69, 6, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 69, 6, 69, - 8, 65, 65, 65, 8, 65, 65, 11, - 65, 65, 3, 6, 65, 65, 66, 65, - 65, 65, 65, 65, 65, 16, 17, 18, - 19, 20, 21, 22, 16, 23, 24, 25, - 26, 27, 28, 65, 29, 30, 31, 65, - 65, 65, 65, 33, 65, 11, 65, 65, - 3, 6, 65, 65, 66, 65, 65, 65, - 65, 65, 65, 16, 17, 18, 19, 20, - 21, 22, 16, 23, 24, 25, 26, 27, - 28, 65, 29, 30, 31, 65, 65, 65, - 65, 33, 65, 71, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 71, - 72, 70, 71, 72, 70, 72, 70, 8, - 69, 69, 69, 8, 69, 0 + 6, 5, 5, 5, 6, 5, 7, 5, + 8, 9, 10, 8, 11, 12, 10, 10, + 10, 10, 10, 3, 13, 14, 10, 15, + 8, 8, 16, 17, 10, 10, 18, 19, + 20, 21, 22, 23, 24, 18, 25, 26, + 27, 28, 29, 30, 10, 31, 32, 33, + 10, 34, 35, 36, 37, 38, 39, 40, + 13, 10, 42, 41, 44, 1, 43, 43, + 45, 43, 43, 43, 43, 43, 46, 47, + 48, 49, 50, 51, 52, 53, 47, 54, + 46, 55, 56, 57, 58, 43, 59, 60, + 61, 43, 43, 43, 43, 62, 63, 64, + 65, 1, 43, 44, 1, 43, 43, 45, + 43, 43, 43, 43, 43, 66, 47, 48, + 49, 50, 51, 52, 53, 47, 54, 55, + 55, 56, 57, 58, 43, 59, 60, 61, + 43, 43, 43, 43, 62, 63, 64, 65, + 1, 43, 44, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 67, + 68, 67, 44, 67, 44, 1, 43, 43, + 45, 43, 43, 43, 43, 43, 43, 47, + 48, 49, 50, 51, 52, 53, 47, 54, + 55, 55, 56, 57, 58, 43, 59, 60, + 61, 43, 43, 43, 43, 62, 63, 64, + 65, 1, 43, 47, 48, 49, 50, 51, + 43, 43, 43, 43, 43, 43, 56, 57, + 58, 43, 59, 60, 61, 43, 43, 43, + 43, 48, 63, 64, 65, 69, 43, 48, + 49, 50, 51, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 59, 60, 61, + 43, 43, 43, 43, 43, 63, 64, 65, + 69, 43, 49, 50, 51, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 63, + 64, 65, 43, 50, 51, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 63, + 64, 65, 43, 51, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 63, 64, + 65, 43, 63, 64, 43, 64, 43, 49, + 50, 51, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 59, 60, 61, 43, + 43, 43, 43, 43, 63, 64, 65, 69, + 43, 49, 50, 51, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 60, + 61, 43, 43, 43, 43, 43, 63, 64, + 65, 69, 43, 49, 50, 51, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 61, 43, 43, 43, 43, 43, + 63, 64, 65, 69, 43, 71, 70, 49, + 50, 51, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 63, 64, 65, 69, + 43, 48, 49, 50, 51, 43, 43, 43, + 43, 43, 43, 56, 57, 58, 43, 59, + 60, 61, 43, 43, 43, 43, 48, 63, + 64, 65, 69, 43, 48, 49, 50, 51, + 43, 43, 43, 43, 43, 43, 43, 57, + 58, 43, 59, 60, 61, 43, 43, 43, + 43, 48, 63, 64, 65, 69, 43, 48, + 49, 50, 51, 43, 43, 43, 43, 43, + 43, 43, 43, 58, 43, 59, 60, 61, + 43, 43, 43, 43, 48, 63, 64, 65, + 69, 43, 47, 48, 49, 50, 51, 43, + 53, 47, 43, 43, 43, 56, 57, 58, + 43, 59, 60, 61, 43, 43, 43, 43, + 48, 63, 64, 65, 69, 43, 47, 48, + 49, 50, 51, 43, 72, 47, 43, 43, + 43, 56, 57, 58, 43, 59, 60, 61, + 43, 43, 43, 43, 48, 63, 64, 65, + 69, 43, 47, 48, 49, 50, 51, 43, + 43, 47, 43, 43, 43, 56, 57, 58, + 43, 59, 60, 61, 43, 43, 43, 43, + 48, 63, 64, 65, 69, 43, 47, 48, + 49, 50, 51, 52, 53, 47, 43, 43, + 43, 56, 57, 58, 43, 59, 60, 61, + 43, 43, 43, 43, 48, 63, 64, 65, + 69, 43, 44, 1, 43, 43, 45, 43, + 43, 43, 43, 43, 43, 47, 48, 49, + 50, 51, 52, 53, 47, 54, 43, 55, + 56, 57, 58, 43, 59, 60, 61, 43, + 43, 43, 43, 62, 63, 64, 65, 1, + 43, 44, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 68, + 67, 67, 67, 67, 67, 67, 67, 48, + 49, 50, 51, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 59, 60, 61, + 67, 67, 67, 67, 67, 63, 64, 65, + 69, 67, 44, 1, 43, 43, 45, 43, + 43, 43, 43, 43, 43, 47, 48, 49, + 50, 51, 52, 53, 47, 54, 46, 55, + 56, 57, 58, 43, 59, 60, 61, 43, + 43, 43, 43, 62, 63, 64, 65, 1, + 43, 74, 73, 73, 73, 73, 73, 73, + 73, 75, 73, 11, 76, 74, 73, 44, + 1, 43, 43, 45, 43, 43, 43, 43, + 43, 77, 47, 48, 49, 50, 51, 52, + 53, 47, 54, 46, 55, 56, 57, 58, + 43, 59, 60, 61, 43, 78, 79, 43, + 62, 63, 64, 65, 1, 43, 44, 1, + 43, 43, 45, 43, 43, 43, 43, 43, + 43, 47, 48, 49, 50, 51, 52, 53, + 47, 54, 46, 55, 56, 57, 58, 43, + 59, 60, 61, 43, 78, 79, 43, 62, + 63, 64, 65, 1, 43, 78, 79, 80, + 79, 80, 3, 6, 81, 81, 82, 81, + 81, 81, 81, 81, 83, 18, 19, 20, + 21, 22, 23, 24, 18, 25, 27, 27, + 28, 29, 30, 81, 31, 32, 33, 81, + 81, 81, 81, 37, 38, 39, 40, 6, + 81, 3, 6, 81, 81, 82, 81, 81, + 81, 81, 81, 81, 18, 19, 20, 21, + 22, 23, 24, 18, 25, 27, 27, 28, + 29, 30, 81, 31, 32, 33, 81, 81, + 81, 81, 37, 38, 39, 40, 6, 81, + 18, 19, 20, 21, 22, 81, 81, 81, + 81, 81, 81, 28, 29, 30, 81, 31, + 32, 33, 81, 81, 81, 81, 19, 38, + 39, 40, 84, 81, 19, 20, 21, 22, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 31, 32, 33, 81, 81, 81, + 81, 81, 38, 39, 40, 84, 81, 20, + 21, 22, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 38, 39, 40, 81, + 21, 22, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 38, 39, 40, 81, + 22, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 38, 39, 40, 81, 38, + 39, 81, 39, 81, 20, 21, 22, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 31, 32, 33, 81, 81, 81, 81, + 81, 38, 39, 40, 84, 81, 20, 21, + 22, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 32, 33, 81, 81, + 81, 81, 81, 38, 39, 40, 84, 81, + 20, 21, 22, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 33, + 81, 81, 81, 81, 81, 38, 39, 40, + 84, 81, 20, 21, 22, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 38, + 39, 40, 84, 81, 19, 20, 21, 22, + 81, 81, 81, 81, 81, 81, 28, 29, + 30, 81, 31, 32, 33, 81, 81, 81, + 81, 19, 38, 39, 40, 84, 81, 19, + 20, 21, 22, 81, 81, 81, 81, 81, + 81, 81, 29, 30, 81, 31, 32, 33, + 81, 81, 81, 81, 19, 38, 39, 40, + 84, 81, 19, 20, 21, 22, 81, 81, + 81, 81, 81, 81, 81, 81, 30, 81, + 31, 32, 33, 81, 81, 81, 81, 19, + 38, 39, 40, 84, 81, 18, 19, 20, + 21, 22, 81, 24, 18, 81, 81, 81, + 28, 29, 30, 81, 31, 32, 33, 81, + 81, 81, 81, 19, 38, 39, 40, 84, + 81, 18, 19, 20, 21, 22, 81, 85, + 18, 81, 81, 81, 28, 29, 30, 81, + 31, 32, 33, 81, 81, 81, 81, 19, + 38, 39, 40, 84, 81, 18, 19, 20, + 21, 22, 81, 81, 18, 81, 81, 81, + 28, 29, 30, 81, 31, 32, 33, 81, + 81, 81, 81, 19, 38, 39, 40, 84, + 81, 18, 19, 20, 21, 22, 23, 24, + 18, 81, 81, 81, 28, 29, 30, 81, + 31, 32, 33, 81, 81, 81, 81, 19, + 38, 39, 40, 84, 81, 3, 6, 81, + 81, 82, 81, 81, 81, 81, 81, 81, + 18, 19, 20, 21, 22, 23, 24, 18, + 25, 81, 27, 28, 29, 30, 81, 31, + 32, 33, 81, 81, 81, 81, 37, 38, + 39, 40, 6, 81, 3, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 4, 81, 81, 81, 81, 81, + 81, 81, 19, 20, 21, 22, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, + 31, 32, 33, 81, 81, 81, 81, 81, + 38, 39, 40, 84, 81, 3, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 4, 86, 87, 81, 14, + 81, 81, 81, 81, 81, 81, 81, 88, + 81, 14, 81, 6, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 6, 86, 86, 86, 6, + 86, 9, 81, 81, 81, 9, 81, 81, + 81, 81, 81, 3, 6, 14, 81, 82, + 81, 81, 81, 81, 81, 81, 18, 19, + 20, 21, 22, 23, 24, 18, 25, 26, + 27, 28, 29, 30, 81, 31, 32, 33, + 81, 34, 35, 81, 37, 38, 39, 40, + 6, 81, 3, 6, 81, 81, 82, 81, + 81, 81, 81, 81, 81, 18, 19, 20, + 21, 22, 23, 24, 18, 25, 26, 27, + 28, 29, 30, 81, 31, 32, 33, 81, + 81, 81, 81, 37, 38, 39, 40, 6, + 81, 34, 35, 81, 35, 81, 78, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 78, 79, 80, 9, 86, 86, + 86, 9, 86, 0 }; static const char _use_syllable_machine_trans_targs[] = { - 4, 8, 4, 32, 2, 4, 1, 5, - 6, 4, 29, 4, 51, 52, 53, 55, - 34, 35, 36, 37, 38, 45, 46, 48, - 54, 49, 42, 43, 44, 39, 40, 41, - 58, 50, 4, 4, 4, 4, 7, 0, - 28, 11, 12, 13, 14, 15, 22, 23, - 25, 26, 19, 20, 21, 16, 17, 18, - 27, 10, 4, 9, 24, 4, 30, 31, - 4, 4, 3, 33, 47, 4, 4, 56, - 57 + 5, 9, 5, 41, 2, 5, 1, 53, + 6, 7, 5, 34, 37, 63, 64, 67, + 68, 72, 43, 44, 45, 46, 47, 57, + 58, 60, 69, 61, 54, 55, 56, 50, + 51, 52, 70, 71, 73, 62, 48, 49, + 5, 5, 5, 5, 8, 0, 33, 12, + 13, 14, 15, 16, 27, 28, 30, 31, + 24, 25, 26, 19, 20, 21, 32, 17, + 18, 5, 11, 5, 10, 22, 5, 23, + 29, 5, 35, 36, 5, 38, 39, 40, + 5, 5, 3, 42, 4, 59, 5, 65, + 66 }; static const char _use_syllable_machine_trans_actions[] = { - 1, 0, 2, 3, 0, 4, 0, 0, - 7, 8, 0, 9, 10, 10, 3, 0, + 1, 0, 2, 3, 0, 4, 0, 5, + 0, 5, 8, 0, 5, 9, 0, 9, + 3, 0, 5, 5, 0, 0, 0, 5, + 5, 5, 3, 3, 5, 5, 5, 5, + 5, 5, 0, 0, 0, 3, 0, 0, + 10, 11, 12, 13, 5, 0, 5, 0, + 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, - 3, 3, 0, 0, 0, 0, 0, 0, - 0, 3, 11, 12, 13, 14, 7, 0, - 7, 0, 0, 0, 0, 0, 0, 0, - 0, 7, 0, 0, 0, 0, 0, 0, - 0, 7, 15, 0, 0, 16, 0, 0, - 17, 18, 0, 3, 0, 19, 20, 0, + 0, 14, 5, 15, 0, 0, 16, 0, + 0, 17, 0, 0, 18, 5, 0, 0, + 19, 20, 0, 3, 0, 5, 21, 0, 0 }; static const char _use_syllable_machine_to_state_actions[] = { - 0, 0, 0, 0, 5, 0, 0, 0, + 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0 }; static const char _use_syllable_machine_from_state_actions[] = { - 0, 0, 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 7, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0 + 0, 0 }; static const short _use_syllable_machine_eof_trans[] = { - 1, 3, 3, 6, 0, 35, 37, 37, - 59, 59, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 37, 37, 37, 37, 37, - 37, 37, 37, 59, 37, 62, 65, 62, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 70, 70, 66, 66, 71, - 71, 71, 70 + 1, 3, 3, 6, 6, 0, 42, 44, + 44, 68, 68, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 71, 44, + 44, 44, 44, 44, 44, 44, 44, 44, + 68, 44, 74, 77, 74, 44, 44, 81, + 81, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 87, + 82, 82, 82, 87, 82, 82, 82, 82, + 81, 87 }; -static const int use_syllable_machine_start = 4; -static const int use_syllable_machine_first_final = 4; +static const int use_syllable_machine_start = 5; +static const int use_syllable_machine_first_final = 5; static const int use_syllable_machine_error = -1; -static const int use_syllable_machine_en_main = 4; +static const int use_syllable_machine_en_main = 5; #line 38 "hb-ot-shape-complex-use-machine.rl" -#line 143 "hb-ot-shape-complex-use-machine.rl" +#line 162 "hb-ot-shape-complex-use-machine.rl" #define found_syllable(syllable_type) \ HB_STMT_START { \ if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \ for (unsigned int i = ts; i < te; i++) \ - info[i].syllable() = (syllable_serial << 4) | syllable_type; \ + info[i].syllable() = (syllable_serial << 4) | use_##syllable_type; \ syllable_serial++; \ if (unlikely (syllable_serial == 16)) syllable_serial = 1; \ } HB_STMT_END static void -find_syllables (hb_buffer_t *buffer) +find_syllables_use (hb_buffer_t *buffer) { unsigned int p, pe, eof, ts, te, act; int cs; hb_glyph_info_t *info = buffer->info; -#line 378 "hb-ot-shape-complex-use-machine.hh" +#line 396 "hb-ot-shape-complex-use-machine.hh" { cs = use_syllable_machine_start; ts = 0; @@ -382,7 +400,7 @@ find_syllables (hb_buffer_t *buffer) act = 0; } -#line 163 "hb-ot-shape-complex-use-machine.rl" +#line 182 "hb-ot-shape-complex-use-machine.rl" p = 0; @@ -390,7 +408,7 @@ find_syllables (hb_buffer_t *buffer) unsigned int syllable_serial = 1; -#line 394 "hb-ot-shape-complex-use-machine.hh" +#line 412 "hb-ot-shape-complex-use-machine.hh" { int _slen; int _trans; @@ -400,11 +418,11 @@ find_syllables (hb_buffer_t *buffer) goto _test_eof; _resume: switch ( _use_syllable_machine_from_state_actions[cs] ) { - case 6: + case 7: #line 1 "NONE" {ts = p;} break; -#line 408 "hb-ot-shape-complex-use-machine.hh" +#line 426 "hb-ot-shape-complex-use-machine.hh" } _keys = _use_syllable_machine_trans_keys + (cs<<1); @@ -422,73 +440,77 @@ _eof_trans: goto _again; switch ( _use_syllable_machine_trans_actions[_trans] ) { - case 7: + case 5: #line 1 "NONE" {te = p+1;} break; case 12: -#line 132 "hb-ot-shape-complex-use-machine.rl" +#line 150 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (independent_cluster); }} break; case 14: -#line 134 "hb-ot-shape-complex-use-machine.rl" +#line 153 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (standard_cluster); }} break; - case 9: -#line 138 "hb-ot-shape-complex-use-machine.rl" + case 10: +#line 157 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (broken_cluster); }} break; case 8: -#line 139 "hb-ot-shape-complex-use-machine.rl" +#line 158 "hb-ot-shape-complex-use-machine.rl" {te = p+1;{ found_syllable (non_cluster); }} break; case 11: -#line 132 "hb-ot-shape-complex-use-machine.rl" +#line 150 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (independent_cluster); }} break; case 15: -#line 133 "hb-ot-shape-complex-use-machine.rl" +#line 151 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (virama_terminated_cluster); }} break; + case 16: +#line 152 "hb-ot-shape-complex-use-machine.rl" + {te = p;p--;{ found_syllable (sakot_terminated_cluster); }} + break; case 13: -#line 134 "hb-ot-shape-complex-use-machine.rl" +#line 153 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (standard_cluster); }} break; - case 17: -#line 135 "hb-ot-shape-complex-use-machine.rl" + case 18: +#line 154 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (number_joiner_terminated_cluster); }} break; - case 16: -#line 136 "hb-ot-shape-complex-use-machine.rl" + case 17: +#line 155 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (numeral_cluster); }} break; - case 20: -#line 137 "hb-ot-shape-complex-use-machine.rl" + case 19: +#line 156 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (symbol_cluster); }} break; - case 18: -#line 138 "hb-ot-shape-complex-use-machine.rl" + case 20: +#line 157 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (broken_cluster); }} break; - case 19: -#line 139 "hb-ot-shape-complex-use-machine.rl" + case 21: +#line 158 "hb-ot-shape-complex-use-machine.rl" {te = p;p--;{ found_syllable (non_cluster); }} break; case 1: -#line 134 "hb-ot-shape-complex-use-machine.rl" +#line 153 "hb-ot-shape-complex-use-machine.rl" {{p = ((te))-1;}{ found_syllable (standard_cluster); }} break; case 4: -#line 138 "hb-ot-shape-complex-use-machine.rl" +#line 157 "hb-ot-shape-complex-use-machine.rl" {{p = ((te))-1;}{ found_syllable (broken_cluster); }} break; case 2: #line 1 "NONE" { switch( act ) { - case 7: + case 8: {{p = ((te))-1;} found_syllable (broken_cluster); } break; - case 8: + case 9: {{p = ((te))-1;} found_syllable (non_cluster); } break; } @@ -497,25 +519,25 @@ _eof_trans: case 3: #line 1 "NONE" {te = p+1;} -#line 138 "hb-ot-shape-complex-use-machine.rl" - {act = 7;} +#line 157 "hb-ot-shape-complex-use-machine.rl" + {act = 8;} break; - case 10: + case 9: #line 1 "NONE" {te = p+1;} -#line 139 "hb-ot-shape-complex-use-machine.rl" - {act = 8;} +#line 158 "hb-ot-shape-complex-use-machine.rl" + {act = 9;} break; -#line 510 "hb-ot-shape-complex-use-machine.hh" +#line 532 "hb-ot-shape-complex-use-machine.hh" } _again: switch ( _use_syllable_machine_to_state_actions[cs] ) { - case 5: + case 6: #line 1 "NONE" {ts = 0;} break; -#line 519 "hb-ot-shape-complex-use-machine.hh" +#line 541 "hb-ot-shape-complex-use-machine.hh" } if ( ++p != pe ) @@ -531,7 +553,7 @@ _again: } -#line 171 "hb-ot-shape-complex-use-machine.rl" +#line 190 "hb-ot-shape-complex-use-machine.rl" } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-table.cc index 9411e28e435..910b01a32af 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use-table.cc @@ -6,15 +6,19 @@ * * on files with these headers: * - * # IndicSyllabicCategory-11.0.0.txt - * # Date: 2018-05-21, 18:33:00 GMT [KW, RP] - * # IndicPositionalCategory-11.0.0.txt - * # Date: 2018-02-05, 16:21:00 GMT [KW, RP] - * # Blocks-11.0.0.txt - * # Date: 2017-10-16, 24:39:00 GMT [KW] + * # IndicSyllabicCategory-13.0.0.txt + * # Date: 2019-07-22, 19:55:00 GMT [KW, RP] + * # IndicPositionalCategory-13.0.0.txt + * # Date: 2019-07-23, 00:01:00 GMT [KW, RP] + * # Blocks-13.0.0.txt + * # Date: 2019-07-10, 19:06:00 GMT [KW] * UnicodeData.txt does not have a header. */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex-use.hh" #pragma GCC diagnostic push @@ -22,7 +26,6 @@ #define B USE_B /* BASE */ #define CGJ USE_CGJ /* CGJ */ #define CS USE_CS /* CONS_WITH_STACKER */ -#define FM USE_FM /* CONS_FINAL_MOD */ #define GB USE_GB /* BASE_OTHER */ #define H USE_H /* HALANT */ #define HN USE_HN /* HALANT_NUM */ @@ -34,29 +37,33 @@ #define Rsv USE_Rsv /* Reserved */ #define S USE_S /* SYM */ #define SUB USE_SUB /* CONS_SUB */ +#define Sk USE_Sk /* SAKOT */ #define VS USE_VS /* VARIATION_SELECTOR */ #define WJ USE_WJ /* Word_Joiner */ #define ZWJ USE_ZWJ /* ZWJ */ #define ZWNJ USE_ZWNJ /* ZWNJ */ -#define CMBlw USE_CMBlw #define CMAbv USE_CMAbv +#define CMBlw USE_CMBlw +#define FAbv USE_FAbv #define FBlw USE_FBlw #define FPst USE_FPst -#define FAbv USE_FAbv -#define MPre USE_MPre +#define FMAbv USE_FMAbv +#define FMBlw USE_FMBlw +#define FMPst USE_FMPst +#define MAbv USE_MAbv #define MBlw USE_MBlw #define MPst USE_MPst -#define MAbv USE_MAbv -#define SMBlw USE_SMBlw +#define MPre USE_MPre #define SMAbv USE_SMAbv -#define VPre USE_VPre +#define SMBlw USE_SMBlw +#define VAbv USE_VAbv #define VBlw USE_VBlw #define VPst USE_VPst -#define VAbv USE_VAbv -#define VMPre USE_VMPre +#define VPre USE_VPre +#define VMAbv USE_VMAbv #define VMBlw USE_VMBlw #define VMPst USE_VMPst -#define VMAbv USE_VMAbv +#define VMPre USE_VMPre #pragma GCC diagnostic pop static const USE_TABLE_ELEMENT_TYPE use_table[] = { @@ -75,7 +82,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* Latin-1 Supplement */ /* 00A0 */ GB, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, - /* 00B0 */ O, O, FM, FM, O, O, O, O, O, O, O, O, O, O, O, O, + /* 00B0 */ O, O, FMPst, FMPst, O, O, O, O, O, O, O, O, O, O, O, O, /* 00C0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* 00D0 */ O, O, O, O, O, O, O, GB, @@ -108,7 +115,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 09C0 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPre, O, O, VPst, VPst, H, IND, O, /* 09D0 */ O, O, O, O, O, O, O, VPst, O, O, O, O, B, B, O, B, /* 09E0 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, - /* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, B, O, FM, O, + /* 09F0 */ B, B, O, O, O, O, O, O, O, O, O, O, B, O, FMAbv, O, /* Gurmukhi */ @@ -139,7 +146,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0B20 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 0B30 */ B, O, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv, /* 0B40 */ VPst, VBlw, VBlw, VBlw, VBlw, O, O, VPre, VPst, O, O, VPst, VPst, H, O, O, - /* 0B50 */ O, O, O, O, O, O, VAbv, VAbv, O, O, O, O, B, B, O, B, + /* 0B50 */ O, O, O, O, O, VAbv, VAbv, VAbv, O, O, O, O, B, B, O, B, /* 0B60 */ B, B, VBlw, VBlw, O, O, B, B, B, B, B, B, B, B, B, B, /* 0B70 */ O, B, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -167,7 +174,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* Kannada */ - /* 0C80 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, B, B, + /* 0C80 */ B, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, B, B, /* 0C90 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0CA0 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 0CB0 */ B, B, B, B, O, B, B, B, B, B, O, O, CMBlw, B, VPst, VAbv, @@ -178,7 +185,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* Malayalam */ - /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, O, B, B, + /* 0D00 */ VMAbv, VMAbv, VMPst, VMPst, B, B, B, B, B, B, B, B, B, O, B, B, /* 0D10 */ B, O, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0D20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0D30 */ B, B, B, B, B, B, B, B, B, B, B, VAbv, VAbv, B, VPst, VPst, @@ -189,7 +196,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* Sinhala */ - /* 0D80 */ O, O, VMPst, VMPst, O, B, B, B, B, B, B, B, B, B, B, B, + /* 0D80 */ O, VMAbv, VMPst, VMPst, O, B, B, B, B, B, B, B, B, B, B, B, /* 0D90 */ B, B, B, B, B, B, B, O, O, O, B, B, B, B, B, B, /* 0DA0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0DB0 */ B, B, O, B, B, B, B, B, B, B, B, B, O, B, O, O, @@ -204,7 +211,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* Tibetan */ VBlw, VBlw, O, O, O, O, O, O, /* 0F20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 0F30 */ B, B, B, B, O, FM, O, FM, O, CMAbv, O, O, O, O, VPst, VPre, + /* 0F30 */ B, B, B, B, O, FMBlw, O, FMBlw, O, CMAbv, O, O, O, O, VPst, VPre, /* 0F40 */ B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, B, /* 0F50 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 0F60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, @@ -213,7 +220,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 0F90 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, /* 0FA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, /* 0FB0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, O, O, - /* 0FC0 */ O, O, O, O, O, O, FM, O, + /* 0FC0 */ O, O, O, O, O, O, FMBlw, O, #define use_offset_0x1000u 1536 @@ -260,8 +267,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1790 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 17A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 17B0 */ B, B, B, B, O, O, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VBlw, VPst, VPst, - /* 17C0 */ VPst, VPre, VPre, VPre, VPst, VPst, VMAbv, VMPst, VPst, VMAbv, VMAbv, FM, FAbv, CMAbv, FM, FM, - /* 17D0 */ FM, VAbv, H, FM, O, O, O, O, O, O, O, O, B, VAbv, O, O, + /* 17C0 */ VPst, VPre, VPre, VPre, VPst, VPst, VMAbv, VMPst, VPst, VMAbv, VMAbv, FMAbv, FAbv, CMAbv, FMAbv, FMAbv, + /* 17D0 */ FMAbv, VAbv, H, FMAbv, O, O, O, O, O, O, O, O, B, FMAbv, O, O, /* 17E0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, #define use_offset_0x1900u 1936 @@ -272,7 +279,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1900 */ GB, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1910 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, O, /* 1920 */ VAbv, VAbv, VBlw, VPst, VPst, VAbv, VAbv, VAbv, VAbv, SUB, SUB, SUB, O, O, O, O, - /* 1930 */ FPst, FPst, VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw, VAbv, FM, O, O, O, O, + /* 1930 */ FPst, FPst, VMBlw, FPst, FPst, FPst, FPst, FPst, FPst, FBlw, VAbv, FMBlw, O, O, O, O, /* 1940 */ O, O, O, O, O, O, B, B, B, B, B, B, B, B, B, B, /* Tai Le */ @@ -288,7 +295,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 19A0 */ B, B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, /* 19B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 19C0 */ B, B, B, B, B, B, B, B, VMPst, VMPst, O, O, O, O, O, O, - /* 19D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, + /* 19D0 */ B, B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, /* 19E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* 19F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -302,9 +309,9 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1A30 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1A40 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1A50 */ B, B, B, B, B, MPre, MBlw, SUB, FAbv, FAbv, FAbv, SUB, SUB, SUB, SUB, O, - /* 1A60 */ H, VPst, VAbv, VPst, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre, - /* 1A70 */ VPre, VPre, VPre, VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VAbv, FM, FM, O, O, FBlw, + /* 1A50 */ B, B, B, B, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, SUB, SUB, SUB, O, + /* 1A60 */ Sk, VPst, VAbv, VPst, VPst, VAbv, VAbv, VAbv, VAbv, VBlw, VBlw, VAbv, VBlw, VPst, VPre, VPre, + /* 1A70 */ VPre, VPre, VPre, VAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VMAbv, VAbv, FMAbv, FMAbv, O, O, FMBlw, /* 1A80 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, /* 1A90 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, @@ -318,8 +325,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1B20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1B30 */ B, B, B, B, CMAbv, VPst, VAbv, VAbv, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VPre, /* 1B40 */ VPst, VPst, VAbv, VAbv, H, B, B, B, B, B, B, B, O, O, O, O, - /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, - /* 1B60 */ O, O, O, O, O, O, O, O, O, O, O, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv, + /* 1B50 */ B, B, B, B, B, B, B, B, B, B, O, GB, GB, O, O, GB, + /* 1B60 */ O, S, GB, S, S, S, S, S, GB, S, S, SMAbv, SMBlw, SMAbv, SMAbv, SMAbv, /* 1B70 */ SMAbv, SMAbv, SMAbv, SMAbv, O, O, O, O, O, O, O, O, O, O, O, O, /* Sundanese */ @@ -340,8 +347,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1C00 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 1C10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPst, VPst, VPst, VBlw, FAbv, FAbv, FAbv, - /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FM, CMBlw, O, O, O, O, O, O, O, O, + /* 1C20 */ B, B, B, B, SUB, SUB, VPst, VPre, VPre, VPre, VPst, VPst, VBlw, FAbv, FAbv, FAbv, + /* 1C30 */ FAbv, FAbv, FAbv, FAbv, VMPre, VMPre, FMAbv, CMBlw, O, O, O, O, O, O, O, O, /* 1C40 */ B, B, B, B, B, B, B, B, B, B, O, O, O, B, B, B, #define use_offset_0x1cd0u 2688 @@ -351,13 +358,13 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 1CD0 */ VMAbv, VMAbv, VMAbv, O, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMAbv, VMAbv, VMBlw, VMBlw, VMBlw, VMBlw, /* 1CE0 */ VMAbv, VMPst, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, VMBlw, O, O, O, O, VMBlw, O, O, - /* 1CF0 */ O, O, VMPst, VMPst, VMAbv, CS, CS, VMPst, VMAbv, VMAbv, O, O, O, O, O, O, + /* 1CF0 */ O, O, IND, IND, VMAbv, CS, CS, VMPst, VMAbv, VMAbv, GB, O, O, O, O, O, #define use_offset_0x1df8u 2736 /* Combining Diacritical Marks Supplement */ - O, O, O, FM, O, O, O, O, + O, O, O, FMAbv, O, O, O, O, #define use_offset_0x2008u 2744 @@ -372,8 +379,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* Superscripts and Subscripts */ - /* 2070 */ O, O, O, O, FM, O, O, O, O, O, O, O, O, O, O, O, - /* 2080 */ O, O, FM, FM, FM, O, O, O, + /* 2070 */ O, O, O, O, FMPst, O, O, O, O, O, O, O, O, O, O, O, + /* 2080 */ O, O, FMPst, FMPst, FMPst, O, O, O, #define use_offset_0x20f0u 2800 @@ -393,9 +400,9 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* Syloti Nagri */ - /* A800 */ B, B, O, B, B, B, VAbv, B, B, B, B, VMAbv, B, B, B, B, + /* A800 */ B, B, VAbv, B, B, B, H, B, B, B, B, VMAbv, B, B, B, B, /* A810 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* A820 */ B, B, B, VPst, VPst, VBlw, VAbv, VPst, O, O, O, O, O, O, O, O, + /* A820 */ B, B, B, VPst, VPst, VBlw, VAbv, VPst, O, O, O, O, VBlw, O, O, O, /* A830 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* Phags-pa */ @@ -438,7 +445,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* A980 */ VMAbv, VMAbv, FAbv, VMPst, B, B, B, B, B, B, B, B, B, B, B, B, /* A990 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* A9A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* A9B0 */ B, B, B, CMAbv, VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VPre, VAbv, SUB, MPst, MBlw, + /* A9B0 */ B, B, B, CMAbv, VPst, VPst, VAbv, VAbv, VBlw, VBlw, VPre, VPre, VAbv, MBlw, MBlw, MBlw, /* A9C0 */ H, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* A9D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, @@ -533,7 +540,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11120 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VBlw, VAbv, VAbv, /* 11130 */ VBlw, VAbv, VAbv, H, CMBlw, O, B, B, B, B, B, B, B, B, B, B, - /* 11140 */ O, O, O, O, B, VPst, VPst, O, O, O, O, O, O, O, O, O, + /* 11140 */ O, O, O, O, B, VPst, VPst, B, O, O, O, O, O, O, O, O, /* Mahajani */ @@ -547,7 +554,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11190 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 111A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 111B0 */ B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, - /* 111C0 */ H, B, R, R, O, O, O, O, GB, FBlw, CMBlw, VAbv, VBlw, O, O, O, + /* 111C0 */ H, B, R, R, O, O, O, O, GB, FMBlw, CMBlw, VAbv, VBlw, O, VPre, VMAbv, /* 111D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, /* Sinhala Archaic Numbers */ @@ -581,7 +588,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* Grantha */ - /* 11300 */ VMAbv, VMAbv, VMAbv, VMPst, O, B, B, B, B, B, B, B, B, O, O, B, + /* 11300 */ VMAbv, VMAbv, VMAbv, VMAbv, O, B, B, B, B, B, B, B, B, O, O, B, /* 11310 */ B, O, O, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11320 */ B, B, B, B, B, B, B, B, B, O, B, B, B, B, B, B, /* 11330 */ B, O, B, B, O, B, B, B, B, B, O, CMBlw, CMBlw, B, VPst, VPst, @@ -600,8 +607,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11420 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11430 */ B, B, B, B, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, /* 11440 */ VPst, VPst, H, VMAbv, VMAbv, VMPst, CMBlw, B, O, O, O, O, O, O, O, O, - /* 11450 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, FM, O, - /* 11460 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, + /* 11450 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, FMAbv, B, + /* 11460 */ CS, CS, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* 11470 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* Tirhuta */ @@ -610,7 +617,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11490 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 114A0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 114B0 */ VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VBlw, VBlw, VPre, VAbv, VPst, VPst, VPst, VPst, VMAbv, - /* 114C0 */ VMAbv, VMPst, H, CMBlw, B, O, O, O, O, O, O, O, O, O, O, O, + /* 114C0 */ VMAbv, VMAbv, H, CMBlw, B, O, O, O, O, O, O, O, O, O, O, O, /* 114D0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, #define use_offset_0x11580u 4720 @@ -643,7 +650,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11680 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11690 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 116A0 */ B, B, B, B, B, B, B, B, B, B, B, VMAbv, VMPst, VAbv, VPre, VPst, - /* 116B0 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, CMBlw, O, O, O, O, O, O, O, O, + /* 116B0 */ VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, H, CMBlw, B, O, O, O, O, O, O, O, /* 116C0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, /* 116D0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* 116E0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, @@ -666,15 +673,36 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11820 */ B, B, B, B, B, B, B, B, B, B, B, B, VPst, VPre, VPst, VBlw, /* 11830 */ VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VMAbv, VMPst, H, CMBlw, O, O, O, O, O, -#define use_offset_0x11a00u 5232 +#define use_offset_0x11900u 5232 + + + /* Dives Akuru */ + + /* 11900 */ B, B, B, B, B, B, B, O, O, B, O, O, B, B, B, B, + /* 11910 */ B, B, B, B, O, B, B, O, B, B, B, B, B, B, B, B, + /* 11920 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 11930 */ VPst, VPst, VPst, VPst, VPst, VPre, O, VPre, VPst, O, O, VMAbv, VMAbv, VPst, H, R, + /* 11940 */ MPst, R, MBlw, CMBlw, O, O, O, O, O, O, O, O, O, O, O, O, + /* 11950 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, +#define use_offset_0x119a0u 5328 + + + /* Nandinagari */ + + /* 119A0 */ B, B, B, B, B, B, B, B, O, O, B, B, B, B, B, B, + /* 119B0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 119C0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, + /* 119D0 */ B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, O, O, VAbv, VAbv, VPst, VPst, VMPst, VMPst, + /* 119E0 */ H, B, O, O, VPre, O, O, O, O, O, O, O, O, O, O, O, + /* 119F0 */ O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, O, /* Zanabazar Square */ /* 11A00 */ B, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VAbv, VAbv, VAbv, VBlw, B, B, B, B, B, /* 11A10 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11A20 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11A30 */ B, B, B, FM, VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst, R, MBlw, MBlw, MBlw, MBlw, GB, + /* 11A30 */ B, B, B, FMBlw, VBlw, VMAbv, VMAbv, VMAbv, VMAbv, VMPst, R, MBlw, MBlw, MBlw, MBlw, GB, /* 11A40 */ O, O, O, O, O, GB, O, H, O, O, O, O, O, O, O, O, /* Soyombo */ @@ -682,10 +710,10 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11A50 */ B, VAbv, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VBlw, VBlw, VBlw, B, B, B, B, /* 11A60 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11A70 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, - /* 11A80 */ B, B, B, B, O, O, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, + /* 11A80 */ B, B, B, B, R, R, R, R, R, R, FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, /* 11A90 */ FBlw, FBlw, FBlw, FBlw, FBlw, FBlw, VMAbv, VMPst, CMAbv, H, O, O, O, B, O, O, -#define use_offset_0x11c00u 5392 +#define use_offset_0x11c00u 5584 /* Bhaiksuki */ @@ -706,7 +734,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11CA0 */ SUB, SUB, SUB, SUB, SUB, SUB, SUB, SUB, O, SUB, SUB, SUB, SUB, SUB, SUB, SUB, /* 11CB0 */ VBlw, VPre, VBlw, VAbv, VPst, VMAbv, VMAbv, O, -#define use_offset_0x11d00u 5576 +#define use_offset_0x11d00u 5768 /* Masaram Gondi */ @@ -726,7 +754,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11D90 */ VAbv, VAbv, O, VPst, VPst, VMAbv, VMPst, H, O, O, O, O, O, O, O, O, /* 11DA0 */ B, B, B, B, B, B, B, B, B, B, O, O, O, O, O, O, -#define use_offset_0x11ee0u 5752 +#define use_offset_0x11ee0u 5944 /* Makasar */ @@ -734,7 +762,7 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = { /* 11EE0 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, /* 11EF0 */ B, B, GB, VAbv, VBlw, VPre, VPst, O, -}; /* Table items: 5776; occupancy: 74% */ +}; /* Table items: 5968; occupancy: 74% */ USE_TABLE_ELEMENT_TYPE hb_use_get_category (hb_codepoint_t u) @@ -785,7 +813,8 @@ hb_use_get_category (hb_codepoint_t u) if (hb_in_range (u, 0x11400u, 0x114DFu)) return use_table[u - 0x11400u + use_offset_0x11400u]; if (hb_in_range (u, 0x11580u, 0x1173Fu)) return use_table[u - 0x11580u + use_offset_0x11580u]; if (hb_in_range (u, 0x11800u, 0x1183Fu)) return use_table[u - 0x11800u + use_offset_0x11800u]; - if (hb_in_range (u, 0x11A00u, 0x11A9Fu)) return use_table[u - 0x11A00u + use_offset_0x11a00u]; + if (hb_in_range (u, 0x11900u, 0x1195Fu)) return use_table[u - 0x11900u + use_offset_0x11900u]; + if (hb_in_range (u, 0x119A0u, 0x11A9Fu)) return use_table[u - 0x119A0u + use_offset_0x119a0u]; if (hb_in_range (u, 0x11C00u, 0x11CB7u)) return use_table[u - 0x11C00u + use_offset_0x11c00u]; if (hb_in_range (u, 0x11D00u, 0x11DAFu)) return use_table[u - 0x11D00u + use_offset_0x11d00u]; if (hb_in_range (u, 0x11EE0u, 0x11EF7u)) return use_table[u - 0x11EE0u + use_offset_0x11ee0u]; @@ -800,7 +829,6 @@ hb_use_get_category (hb_codepoint_t u) #undef B #undef CGJ #undef CS -#undef FM #undef GB #undef H #undef HN @@ -812,28 +840,34 @@ hb_use_get_category (hb_codepoint_t u) #undef Rsv #undef S #undef SUB +#undef Sk #undef VS #undef WJ #undef ZWJ #undef ZWNJ -#undef CMBlw #undef CMAbv +#undef CMBlw +#undef FAbv #undef FBlw #undef FPst -#undef FAbv -#undef MPre +#undef FMAbv +#undef FMBlw +#undef FMPst +#undef MAbv #undef MBlw #undef MPst -#undef MAbv -#undef SMBlw +#undef MPre #undef SMAbv -#undef VPre +#undef SMBlw +#undef VAbv #undef VBlw #undef VPst -#undef VAbv -#undef VMPre +#undef VPre +#undef VMAbv #undef VMBlw #undef VMPst -#undef VMAbv +#undef VMPre + +#endif /* == End of generated table == */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.cc index 25b135ab58c..b5cf48ac227 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.cc @@ -26,12 +26,17 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex-use.hh" #include "hb-ot-shape-complex-arabic.hh" +#include "hb-ot-shape-complex-arabic-joining-list.hh" #include "hb-ot-shape-complex-vowel-constraints.hh" /* buffer var allocations */ -#define use_category() complex_var_u8_0() +#define use_category() complex_var_u8_1() /* @@ -40,7 +45,7 @@ */ static const hb_tag_t -basic_features[] = +use_basic_features[] = { /* * Basic features. @@ -55,28 +60,23 @@ basic_features[] = HB_TAG('c','j','c','t'), }; static const hb_tag_t -arabic_features[] = +use_topographical_features[] = { HB_TAG('i','s','o','l'), HB_TAG('i','n','i','t'), HB_TAG('m','e','d','i'), HB_TAG('f','i','n','a'), - /* The spec doesn't specify these but we apply anyway, since our Arabic shaper - * does. These are only used in Syriac spec. */ - HB_TAG('m','e','d','2'), - HB_TAG('f','i','n','2'), - HB_TAG('f','i','n','3'), }; -/* Same order as arabic_features. Don't need Syriac stuff.*/ +/* Same order as use_topographical_features. */ enum joining_form_t { - ISOL, - INIT, - MEDI, - FINA, - _NONE + USE_ISOL, + USE_INIT, + USE_MEDI, + USE_FINA, + _USE_NONE }; static const hb_tag_t -other_features[] = +use_other_features[] = { /* * Other features. @@ -89,42 +89,23 @@ other_features[] = HB_TAG('p','r','e','s'), HB_TAG('p','s','t','s'), }; -static const hb_tag_t -positioning_features[] = -{ - /* - * Positioning features. - * We don't care about the types. - */ - HB_TAG('d','i','s','t'), - HB_TAG('a','b','v','m'), - HB_TAG('b','l','w','m'), -}; static void -setup_syllables (const hb_ot_shape_plan_t *plan, +setup_syllables_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); +static void +record_rphf_use (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); static void -clear_substitution_flags (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -record_rphf (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); +record_pref_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer); static void -record_pref (const hb_ot_shape_plan_t *plan, +reorder_use (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer); -static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); -static void -clear_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer); static void collect_features_use (hb_ot_shape_planner_t *plan) @@ -132,7 +113,7 @@ collect_features_use (hb_ot_shape_planner_t *plan) hb_ot_map_builder_t *map = &plan->map; /* Do this before any lookups have been applied. */ - map->add_gsub_pause (setup_syllables); + map->add_gsub_pause (setup_syllables_use); /* "Default glyph pre-processing group" */ map->enable_feature (HB_TAG('l','o','c','l')); @@ -141,32 +122,28 @@ collect_features_use (hb_ot_shape_planner_t *plan) map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ); /* "Reordering group" */ - map->add_gsub_pause (clear_substitution_flags); + map->add_gsub_pause (_hb_clear_substitution_flags); map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ); - map->add_gsub_pause (record_rphf); - map->add_gsub_pause (clear_substitution_flags); + map->add_gsub_pause (record_rphf_use); + map->add_gsub_pause (_hb_clear_substitution_flags); map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ); - map->add_gsub_pause (record_pref); + map->add_gsub_pause (record_pref_use); /* "Orthographic unit shaping group" */ - for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) - map->enable_feature (basic_features[i], F_MANUAL_ZWJ); + for (unsigned int i = 0; i < ARRAY_LENGTH (use_basic_features); i++) + map->enable_feature (use_basic_features[i], F_MANUAL_ZWJ); - map->add_gsub_pause (reorder); - map->add_gsub_pause (clear_syllables); + map->add_gsub_pause (reorder_use); + map->add_gsub_pause (_hb_clear_syllables); /* "Topographical features" */ - for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++) - map->add_feature (arabic_features[i]); + for (unsigned int i = 0; i < ARRAY_LENGTH (use_topographical_features); i++) + map->add_feature (use_topographical_features[i]); map->add_gsub_pause (nullptr); /* "Standard typographic presentation" */ - for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) - map->enable_feature (other_features[i], F_MANUAL_ZWJ); - - /* "Positional feature application" */ - for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++) - map->enable_feature (positioning_features[i]); + for (unsigned int i = 0; i < ARRAY_LENGTH (use_other_features); i++) + map->enable_feature (use_other_features[i], F_MANUAL_ZWJ); } struct use_shape_plan_t @@ -176,40 +153,6 @@ struct use_shape_plan_t arabic_shape_plan_t *arabic_plan; }; -static bool -has_arabic_joining (hb_script_t script) -{ - /* List of scripts that have data in arabic-table. */ - switch ((int) script) - { - /* Unicode-1.1 additions */ - case HB_SCRIPT_ARABIC: - - /* Unicode-3.0 additions */ - case HB_SCRIPT_MONGOLIAN: - case HB_SCRIPT_SYRIAC: - - /* Unicode-5.0 additions */ - case HB_SCRIPT_NKO: - case HB_SCRIPT_PHAGS_PA: - - /* Unicode-6.0 additions */ - case HB_SCRIPT_MANDAIC: - - /* Unicode-7.0 additions */ - case HB_SCRIPT_MANICHAEAN: - case HB_SCRIPT_PSALTER_PAHLAVI: - - /* Unicode-9.0 additions */ - case HB_SCRIPT_ADLAM: - - return true; - - default: - return false; - } -} - static void * data_create_use (const hb_ot_shape_plan_t *plan) { @@ -243,15 +186,16 @@ data_destroy_use (void *data) free (data); } -enum syllable_type_t { - independent_cluster, - virama_terminated_cluster, - standard_cluster, - number_joiner_terminated_cluster, - numeral_cluster, - symbol_cluster, - broken_cluster, - non_cluster, +enum use_syllable_type_t { + use_independent_cluster, + use_virama_terminated_cluster, + use_sakot_terminated_cluster, + use_standard_cluster, + use_number_joiner_terminated_cluster, + use_numeral_cluster, + use_symbol_cluster, + use_broken_cluster, + use_non_cluster, }; #include "hb-ot-shape-complex-use-machine.hh" @@ -294,7 +238,7 @@ setup_rphf_mask (const hb_ot_shape_plan_t *plan, foreach_syllable (buffer, start, end) { - unsigned int limit = info[start].use_category() == USE_R ? 1 : MIN (3u, end - start); + unsigned int limit = info[start].use_category() == USE_R ? 1 : hb_min (3u, end - start); for (unsigned int i = start; i < start + limit; i++) info[i].mask |= mask; } @@ -308,11 +252,11 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, if (use_plan->arabic_plan) return; - static_assert ((INIT < 4 && ISOL < 4 && MEDI < 4 && FINA < 4), ""); + static_assert ((USE_INIT < 4 && USE_ISOL < 4 && USE_MEDI < 4 && USE_FINA < 4), ""); hb_mask_t masks[4], all_masks = 0; for (unsigned int i = 0; i < 4; i++) { - masks[i] = plan->map.get_1_mask (arabic_features[i]); + masks[i] = plan->map.get_1_mask (use_topographical_features[i]); if (masks[i] == plan->map.get_global_mask ()) masks[i] = 0; all_masks |= masks[i]; @@ -322,38 +266,39 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, hb_mask_t other_masks = ~all_masks; unsigned int last_start = 0; - joining_form_t last_form = _NONE; + joining_form_t last_form = _USE_NONE; hb_glyph_info_t *info = buffer->info; foreach_syllable (buffer, start, end) { - syllable_type_t syllable_type = (syllable_type_t) (info[start].syllable() & 0x0F); + use_syllable_type_t syllable_type = (use_syllable_type_t) (info[start].syllable() & 0x0F); switch (syllable_type) { - case independent_cluster: - case symbol_cluster: - case non_cluster: + case use_independent_cluster: + case use_symbol_cluster: + case use_non_cluster: /* These don't join. Nothing to do. */ - last_form = _NONE; + last_form = _USE_NONE; break; - case virama_terminated_cluster: - case standard_cluster: - case number_joiner_terminated_cluster: - case numeral_cluster: - case broken_cluster: + case use_virama_terminated_cluster: + case use_sakot_terminated_cluster: + case use_standard_cluster: + case use_number_joiner_terminated_cluster: + case use_numeral_cluster: + case use_broken_cluster: - bool join = last_form == FINA || last_form == ISOL; + bool join = last_form == USE_FINA || last_form == USE_ISOL; if (join) { /* Fixup previous syllable's form. */ - last_form = last_form == FINA ? MEDI : INIT; + last_form = last_form == USE_FINA ? USE_MEDI : USE_INIT; for (unsigned int i = last_start; i < start; i++) info[i].mask = (info[i].mask & other_masks) | masks[last_form]; } /* Form for this syllable. */ - last_form = join ? FINA : ISOL; + last_form = join ? USE_FINA : USE_ISOL; for (unsigned int i = start; i < end; i++) info[i].mask = (info[i].mask & other_masks) | masks[last_form]; @@ -365,11 +310,11 @@ setup_topographical_masks (const hb_ot_shape_plan_t *plan, } static void -setup_syllables (const hb_ot_shape_plan_t *plan, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +setup_syllables_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { - find_syllables (buffer); + find_syllables_use (buffer); foreach_syllable (buffer, start, end) buffer->unsafe_to_break (start, end); setup_rphf_mask (plan, buffer); @@ -377,20 +322,9 @@ setup_syllables (const hb_ot_shape_plan_t *plan, } static void -clear_substitution_flags (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - _hb_glyph_info_clear_substituted (&info[i]); -} - -static void -record_rphf (const hb_ot_shape_plan_t *plan, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +record_rphf_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { const use_shape_plan_t *use_plan = (const use_shape_plan_t *) plan->data; @@ -411,9 +345,9 @@ record_rphf (const hb_ot_shape_plan_t *plan, } static void -record_pref (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) +record_pref_use (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font HB_UNUSED, + hb_buffer_t *buffer) { hb_glyph_info_t *info = buffer->info; @@ -430,21 +364,22 @@ record_pref (const hb_ot_shape_plan_t *plan HB_UNUSED, } static inline bool -is_halant (const hb_glyph_info_t &info) +is_halant_use (const hb_glyph_info_t &info) { return (info.use_category() == USE_H || info.use_category() == USE_HVM) && !_hb_glyph_info_ligated (&info); } static void -reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end) +reorder_syllable_use (hb_buffer_t *buffer, unsigned int start, unsigned int end) { - syllable_type_t syllable_type = (syllable_type_t) (buffer->info[start].syllable() & 0x0F); + use_syllable_type_t syllable_type = (use_syllable_type_t) (buffer->info[start].syllable() & 0x0F); /* Only a few syllable types need reordering. */ if (unlikely (!(FLAG_UNSAFE (syllable_type) & - (FLAG (virama_terminated_cluster) | - FLAG (standard_cluster) | - FLAG (broken_cluster) | + (FLAG (use_virama_terminated_cluster) | + FLAG (use_sakot_terminated_cluster) | + FLAG (use_standard_cluster) | + FLAG (use_broken_cluster) | 0)))) return; @@ -475,7 +410,7 @@ reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end) for (unsigned int i = start + 1; i < end; i++) { bool is_post_base_glyph = (FLAG64_UNSAFE (info[i].use_category()) & POST_BASE_FLAGS64) || - is_halant (info[i]); + is_halant_use (info[i]); if (is_post_base_glyph || i == end - 1) { /* If we hit a post-base glyph, move before it; otherwise move to the @@ -499,7 +434,7 @@ reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end) for (unsigned int i = start; i < end; i++) { uint32_t flag = FLAG_UNSAFE (info[i].use_category()); - if (is_halant (info[i])) + if (is_halant_use (info[i])) { /* If we hit a halant, move after it; otherwise move to the beginning, and * shift things in between forward. */ @@ -519,16 +454,20 @@ reorder_syllable (hb_buffer_t *buffer, unsigned int start, unsigned int end) } static inline void -insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font, - hb_buffer_t *buffer) +insert_dotted_circles_use (const hb_ot_shape_plan_t *plan HB_UNUSED, + hb_font_t *font, + hb_buffer_t *buffer) { - /* Note: This loop is extra overhead, but should not be measurable. */ + if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) + return; + + /* Note: This loop is extra overhead, but should not be measurable. + * TODO Use a buffer scratch flag to remove the loop. */ bool has_broken_syllables = false; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) - if ((info[i].syllable() & 0x0F) == broken_cluster) + if ((info[i].syllable() & 0x0F) == use_broken_cluster) { has_broken_syllables = true; break; @@ -548,8 +487,8 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, while (buffer->idx < buffer->len && buffer->successful) { unsigned int syllable = buffer->cur().syllable(); - syllable_type_t syllable_type = (syllable_type_t) (syllable & 0x0F); - if (unlikely (last_syllable != syllable && syllable_type == broken_cluster)) + use_syllable_type_t syllable_type = (use_syllable_type_t) (syllable & 0x0F); + if (unlikely (last_syllable != syllable && syllable_type == use_broken_cluster)) { last_syllable = syllable; @@ -557,7 +496,6 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, ginfo.cluster = buffer->cur().cluster; ginfo.mask = buffer->cur().mask; ginfo.syllable() = buffer->cur().syllable(); - /* TODO Set glyph_props? */ /* Insert dottedcircle after possible Repha. */ while (buffer->idx < buffer->len && buffer->successful && @@ -574,29 +512,18 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED, } static void -reorder (const hb_ot_shape_plan_t *plan, - hb_font_t *font, - hb_buffer_t *buffer) +reorder_use (const hb_ot_shape_plan_t *plan, + hb_font_t *font, + hb_buffer_t *buffer) { - insert_dotted_circles (plan, font, buffer); + insert_dotted_circles_use (plan, font, buffer); foreach_syllable (buffer, start, end) - reorder_syllable (buffer, start, end); + reorder_syllable_use (buffer, start, end); HB_BUFFER_DEALLOCATE_VAR (buffer, use_category); } -static void -clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, - hb_font_t *font HB_UNUSED, - hb_buffer_t *buffer) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - for (unsigned int i = 0; i < count; i++) - info[i].syllable() = 0; -} - static void preprocess_text_use (const hb_ot_shape_plan_t *plan, @@ -637,3 +564,6 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use = HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, false, /* fallback_position */ }; + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.hh index d7edef40ff2..6a42d58c5a8 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-use.hh @@ -68,6 +68,12 @@ enum use_category_t { USE_VS = 21, /* VARIATION_SELECTOR */ // USE_V = 36, /* VOWEL */ // USE_VM = 40, /* VOWEL_MOD */ + USE_CS = 43, /* CONS_WITH_STACKER */ + + /* https://github.com/harfbuzz/harfbuzz/issues/1102 */ + USE_HVM = 44, /* HALANT_OR_VOWEL_MODIFIER */ + + USE_Sk = 48, /* SAKOT */ USE_FAbv = 24, /* CONS_FINAL_ABOVE */ USE_FBlw = 25, /* CONS_FINAL_BELOW */ @@ -88,10 +94,9 @@ enum use_category_t { USE_VMPre = 23, /* VOWEL_MOD_PRE */ USE_SMAbv = 41, /* SYM_MOD_ABOVE */ USE_SMBlw = 42, /* SYM_MOD_BELOW */ - USE_CS = 43, /* CONS_WITH_STACKER */ - - /* https://github.com/harfbuzz/harfbuzz/issues/1102 */ - USE_HVM = 44, /* HALANT_OR_VOWEL_MODIFIER */ + USE_FMAbv = 45, /* CONS_FINAL_MOD UIPC = Top */ + USE_FMBlw = 46, /* CONS_FINAL_MOD UIPC = Bottom */ + USE_FMPst = 47, /* CONS_FINAL_MOD UIPC = Not_Applicable */ }; HB_INTERNAL USE_TABLE_ELEMENT_TYPE diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-vowel-constraints.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-vowel-constraints.cc index 366751efee2..adfaa301049 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-vowel-constraints.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex-vowel-constraints.cc @@ -2,17 +2,22 @@ /* * The following functions are generated by running: * - * ./gen-vowel-constraints.py use Scripts.txt + * ./gen-vowel-constraints.py ms-use/IndicShapingInvalidCluster.txt Scripts.txt * * on files with these headers: * - * # Copied from https://docs.microsoft.com/en-us/typography/script-development/use - * # On October 23, 2018; with documentd dated 02/07/2018. + * # IndicShapingInvalidCluster.txt + * # Date: 2015-03-12, 21:17:00 GMT [AG] + * # Date: 2019-11-08, 23:22:00 GMT [AG] * - * # Scripts-11.0.0.txt - * # Date: 2018-02-21, 05:34:31 GMT + * # Scripts-13.0.0.txt + * # Date: 2020-01-22, 00:07:43 GMT */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-complex-vowel-constraints.hh" static void @@ -34,6 +39,12 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED, hb_buffer_t *buffer, hb_font_t *font HB_UNUSED) { +#ifdef HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS + return; +#endif + if (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE) + return; + /* UGLY UGLY UGLY business of adding dotted-circle in the middle of * vowel-sequences that look like another vowel. Data for each script * collected from the USE script development spec. @@ -87,8 +98,7 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED, 0x0907u == buffer->cur (2).codepoint) { buffer->next_glyph (); - buffer->next_glyph (); - _output_dotted_circle (buffer); + matched = true; } break; } @@ -201,6 +211,21 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED, processed = true; break; + case HB_SCRIPT_TAMIL: + for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) + { + bool matched = false; + if (0x0B85u == buffer->cur ().codepoint && + 0x0BC2u == buffer->cur (1).codepoint) + { + matched = true; + } + buffer->next_glyph (); + if (matched) _output_with_dotted_circle (buffer); + } + processed = true; + break; + case HB_SCRIPT_TELUGU: for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;) { @@ -434,4 +459,6 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED, } } + +#endif /* == End of generated functions == */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex.hh index 2756ae1aeeb..59165c46c70 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-complex.hh @@ -50,8 +50,9 @@ enum hb_ot_shape_zero_width_marks_type_t { /* Master OT shaper list */ #define HB_COMPLEX_SHAPERS_IMPLEMENT_SHAPERS \ - HB_COMPLEX_SHAPER_IMPLEMENT (default) /* should be first */ \ HB_COMPLEX_SHAPER_IMPLEMENT (arabic) \ + HB_COMPLEX_SHAPER_IMPLEMENT (default) \ + HB_COMPLEX_SHAPER_IMPLEMENT (dumber) \ HB_COMPLEX_SHAPER_IMPLEMENT (hangul) \ HB_COMPLEX_SHAPER_IMPLEMENT (hebrew) \ HB_COMPLEX_SHAPER_IMPLEMENT (indic) \ @@ -60,7 +61,7 @@ enum hb_ot_shape_zero_width_marks_type_t { HB_COMPLEX_SHAPER_IMPLEMENT (myanmar_zawgyi) \ HB_COMPLEX_SHAPER_IMPLEMENT (thai) \ HB_COMPLEX_SHAPER_IMPLEMENT (use) \ - /* ^--- Add new shapers here */ + /* ^--- Add new shapers here; keep sorted. */ struct hb_ot_complex_shaper_t @@ -377,6 +378,13 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner) case HB_SCRIPT_MAKASAR: //case HB_SCRIPT_SOGDIAN: + /* Unicode-12.0 additions */ + case HB_SCRIPT_NANDINAGARI: + + /* Unicode-13.0 additions */ + case HB_SCRIPT_CHORASMIAN: + case HB_SCRIPT_DIVES_AKURU: + /* If the designer designed the font for the 'DFLT' script, * (or we ended up arbitrarily pick 'latn'), use the default shaper. * Otherwise, use the specific shaper. diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc index d29bc9b9ef5..b6b6f0b1535 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-fallback.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-fallback.hh" #include "hb-kern.hh" @@ -166,6 +170,10 @@ _hb_ot_shape_fallback_mark_position_recategorize_marks (const hb_ot_shape_plan_t hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) { +#ifdef HB_NO_OT_SHAPE_FALLBACK + return; +#endif + unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 0; i < count; i++) @@ -414,12 +422,12 @@ position_cluster (const hb_ot_shape_plan_t *plan, /* Find the base glyph */ hb_glyph_info_t *info = buffer->info; for (unsigned int i = start; i < end; i++) - if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i]))) + if (!_hb_glyph_info_is_unicode_mark (&info[i])) { /* Find mark glyphs */ unsigned int j; for (j = i + 1; j < end; j++) - if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[j]))) + if (!_hb_glyph_info_is_unicode_mark (&info[j])) break; position_around_base (plan, font, buffer, i, j, adjust_offsets_when_zeroing); @@ -434,13 +442,17 @@ _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer, bool adjust_offsets_when_zeroing) { +#ifdef HB_NO_OT_SHAPE_FALLBACK + return; +#endif + _hb_buffer_assert_gsubgpos_vars (buffer); unsigned int start = 0; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; for (unsigned int i = 1; i < count; i++) - if (likely (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&info[i])))) { + if (likely (!_hb_glyph_info_is_unicode_mark (&info[i]))) { position_cluster (plan, font, buffer, start, i, adjust_offsets_when_zeroing); start = i; } @@ -448,6 +460,7 @@ _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, } +#ifndef HB_DISABLE_DEPRECATED struct hb_ot_shape_fallback_kern_driver_t { hb_ot_shape_fallback_kern_driver_t (hb_font_t *font_, @@ -466,6 +479,7 @@ struct hb_ot_shape_fallback_kern_driver_t hb_font_t *font; hb_direction_t direction; }; +#endif /* Performs font-assisted kerning. */ void @@ -473,6 +487,11 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, hb_font_t *font, hb_buffer_t *buffer) { +#ifdef HB_NO_OT_SHAPE_FALLBACK + return; +#endif + +#ifndef HB_DISABLE_DEPRECATED if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction) ? !font->has_glyph_h_kerning_func () : !font->has_glyph_v_kerning_func ()) @@ -489,6 +508,7 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, if (reverse) buffer->reverse (); +#endif } @@ -571,3 +591,6 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED, } } } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc index ed73abb1530..aa88b2681bc 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape-normalize.cc @@ -24,6 +24,10 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + #include "hb-ot-shape-normalize.hh" #include "hb-ot-shape-complex.hh" #include "hb-ot-shape.hh" @@ -330,7 +334,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, { unsigned int end; for (end = buffer->idx + 1; end < count; end++) - if (unlikely (HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end])))) + if (unlikely (_hb_glyph_info_is_unicode_mark (&buffer->info[end]))) break; if (end < count) @@ -356,7 +360,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, /* Find all the marks now. */ for (end = buffer->idx + 1; end < count; end++) - if (!HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->info[end]))) + if (!_hb_glyph_info_is_unicode_mark(&buffer->info[end])) break; /* idx to end is one non-simple cluster. */ @@ -431,7 +435,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, * This is both an optimization to avoid trying to compose every two neighboring * glyphs in most scripts AND a desired feature for Hangul. Apparently Hangul * fonts are not designed to mix-and-match pre-composed syllables and Jamo. */ - HB_UNICODE_GENERAL_CATEGORY_IS_MARK (_hb_glyph_info_get_general_category (&buffer->cur()))) + _hb_glyph_info_is_unicode_mark(&buffer->cur())) { if (/* If there's anything between the starter and this char, they should have CCC * smaller than this character's. */ @@ -469,3 +473,6 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, buffer->swap_buffers (); } } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc index e9c8f882162..154725598ba 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.cc @@ -26,6 +26,14 @@ * Google Author(s): Behdad Esfahbod */ +#include "hb.hh" + +#ifndef HB_NO_OT_SHAPE + +#ifdef HB_NO_OT_LAYOUT +#error "Cannot compile 'ot' shaper with HB_NO_OT_LAYOUT." +#endif + #include "hb-shaper-impl.hh" #include "hb-ot-shape.hh" @@ -40,6 +48,16 @@ #include "hb-aat-layout.hh" +#ifndef HB_NO_AAT_SHAPE +static inline bool +_hb_apply_morx (hb_face_t *face, const hb_segment_properties_t *props) +{ + /* https://github.com/harfbuzz/harfbuzz/issues/2124 */ + return hb_aat_layout_has_substitution (face) && + (HB_DIRECTION_IS_HORIZONTAL (props->direction) || !hb_ot_layout_has_substitution (face)); +} +#endif + /** * SECTION:hb-ot-shape * @title: hb-ot-shape @@ -55,36 +73,24 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, const hb_feature_t *user_features, unsigned int num_user_features); -static bool -_hb_apply_morx (hb_face_t *face) -{ - if (hb_options ().aat && - hb_aat_layout_has_substitution (face)) - return true; - - /* Ignore empty GSUB tables. */ - return (!hb_ot_layout_has_substitution (face) || - !hb_ot_layout_table_get_script_tags (face, - HB_OT_TAG_GSUB, - 0, nullptr, nullptr)) && - hb_aat_layout_has_substitution (face); -} - hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *face, const hb_segment_properties_t *props) : face (face), props (*props), map (face, props), - aat_map (face, props), - apply_morx (_hb_apply_morx (face)) + aat_map (face, props) +#ifndef HB_NO_AAT_SHAPE + , apply_morx (_hb_apply_morx (face, props)) +#endif { shaper = hb_ot_shape_complex_categorize (this); script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE; script_fallback_mark_positioning = shaper->fallback_position; - if (apply_morx) - shaper = &_hb_ot_complex_shaper_default; + /* https://github.com/harfbuzz/harfbuzz/issues/1528 */ + if (apply_morx && shaper != &_hb_ot_complex_shaper_default) + shaper = &_hb_ot_complex_shaper_dumber; } void @@ -94,21 +100,32 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, plan.props = props; plan.shaper = shaper; map.compile (plan.map, key); +#ifndef HB_NO_AAT_SHAPE if (apply_morx) aat_map.compile (plan.aat_map); +#endif +#ifndef HB_NO_OT_SHAPE_FRACTIONS plan.frac_mask = plan.map.get_1_mask (HB_TAG ('f','r','a','c')); plan.numr_mask = plan.map.get_1_mask (HB_TAG ('n','u','m','r')); plan.dnom_mask = plan.map.get_1_mask (HB_TAG ('d','n','o','m')); plan.has_frac = plan.frac_mask || (plan.numr_mask && plan.dnom_mask); +#endif + plan.rtlm_mask = plan.map.get_1_mask (HB_TAG ('r','t','l','m')); + plan.has_vert = !!plan.map.get_1_mask (HB_TAG ('v','e','r','t')); + hb_tag_t kern_tag = HB_DIRECTION_IS_HORIZONTAL (props.direction) ? HB_TAG ('k','e','r','n') : HB_TAG ('v','k','r','n'); +#ifndef HB_NO_OT_KERN plan.kern_mask = plan.map.get_mask (kern_tag); - plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k')); - plan.requested_kerning = !!plan.kern_mask; +#endif +#ifndef HB_NO_AAT_SHAPE + plan.trak_mask = plan.map.get_mask (HB_TAG ('t','r','a','k')); plan.requested_tracking = !!plan.trak_mask; +#endif + bool has_gpos_kern = plan.map.get_feature_index (1, kern_tag) != HB_OT_LAYOUT_NO_FEATURE_INDEX; bool disable_gpos = plan.shaper->gpos_tag && plan.shaper->gpos_tag != plan.map.chosen_script[1]; @@ -124,42 +141,61 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan, * Decide who does substitutions. GSUB, morx, or fallback. */ +#ifndef HB_NO_AAT_SHAPE plan.apply_morx = apply_morx; +#endif /* * Decide who does positioning. GPOS, kerx, kern, or fallback. */ - if (hb_options ().aat && hb_aat_layout_has_positioning (face)) + if (0) + ; +#ifndef HB_NO_AAT_SHAPE + else if (hb_aat_layout_has_positioning (face)) plan.apply_kerx = true; +#endif else if (!apply_morx && !disable_gpos && hb_ot_layout_has_positioning (face)) plan.apply_gpos = true; - else if (hb_aat_layout_has_positioning (face)) - plan.apply_kerx = true; - if (!plan.apply_kerx && !has_gpos_kern) + if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos)) { /* Apparently Apple applies kerx if GPOS kern was not applied. */ +#ifndef HB_NO_AAT_SHAPE if (hb_aat_layout_has_positioning (face)) plan.apply_kerx = true; - else if (hb_ot_layout_has_kerning (face)) + else +#endif +#ifndef HB_NO_OT_KERN + if (hb_ot_layout_has_kerning (face)) plan.apply_kern = true; +#endif } plan.zero_marks = script_zero_marks && !plan.apply_kerx && - (!plan.apply_kern || !hb_ot_layout_has_machine_kerning (face)); + (!plan.apply_kern +#ifndef HB_NO_OT_KERN + || !hb_ot_layout_has_machine_kerning (face) +#endif + ); plan.has_gpos_mark = !!plan.map.get_1_mask (HB_TAG ('m','a','r','k')); plan.adjust_mark_positioning_when_zeroing = !plan.apply_gpos && !plan.apply_kerx && - (!plan.apply_kern || !hb_ot_layout_has_cross_kerning (face)); + (!plan.apply_kern +#ifndef HB_NO_OT_KERN + || !hb_ot_layout_has_cross_kerning (face) +#endif + ); plan.fallback_mark_positioning = plan.adjust_mark_positioning_when_zeroing && script_fallback_mark_positioning; +#ifndef HB_NO_AAT_SHAPE /* Currently we always apply trak. */ plan.apply_trak = plan.requested_tracking && hb_aat_layout_has_tracking (face); +#endif } bool @@ -167,7 +203,9 @@ hb_ot_shape_plan_t::init0 (hb_face_t *face, const hb_shape_plan_key_t *key) { map.init (); +#ifndef HB_NO_AAT_SHAPE aat_map.init (); +#endif hb_ot_shape_planner_t planner (face, &key->props); @@ -182,7 +220,13 @@ hb_ot_shape_plan_t::init0 (hb_face_t *face, { data = shaper->data_create (this); if (unlikely (!data)) + { + map.fini (); +#ifndef HB_NO_AAT_SHAPE + aat_map.fini (); +#endif return false; + } } return true; @@ -195,16 +239,20 @@ hb_ot_shape_plan_t::fini () shaper->data_destroy (const_cast (data)); map.fini (); +#ifndef HB_NO_AAT_SHAPE aat_map.fini (); +#endif } void hb_ot_shape_plan_t::substitute (hb_font_t *font, hb_buffer_t *buffer) const { +#ifndef HB_NO_AAT_SHAPE if (unlikely (apply_morx)) hb_aat_layout_substitute (this, font, buffer); else +#endif map.substitute (this, font, buffer); } @@ -214,21 +262,29 @@ hb_ot_shape_plan_t::position (hb_font_t *font, { if (this->apply_gpos) map.position (this, font, buffer); +#ifndef HB_NO_AAT_SHAPE else if (this->apply_kerx) hb_aat_layout_position (this, font, buffer); +#endif +#ifndef HB_NO_OT_KERN else if (this->apply_kern) hb_ot_layout_kern (this, font, buffer); +#endif else _hb_ot_shape_fallback_kern (this, font, buffer); +#ifndef HB_NO_AAT_SHAPE if (this->apply_trak) hb_aat_layout_track (this, font, buffer); +#endif } static const hb_ot_map_feature_t common_features[] = { + {HB_TAG('a','b','v','m'), F_GLOBAL}, + {HB_TAG('b','l','w','m'), F_GLOBAL}, {HB_TAG('c','c','m','p'), F_GLOBAL}, {HB_TAG('l','o','c','l'), F_GLOBAL}, {HB_TAG('m','a','r','k'), F_GLOBAL_MANUAL_JOINERS}, @@ -243,6 +299,7 @@ horizontal_features[] = {HB_TAG('c','a','l','t'), F_GLOBAL}, {HB_TAG('c','l','i','g'), F_GLOBAL}, {HB_TAG('c','u','r','s'), F_GLOBAL}, + {HB_TAG('d','i','s','t'), F_GLOBAL}, {HB_TAG('k','e','r','n'), F_GLOBAL_HAS_FALLBACK}, {HB_TAG('l','i','g','a'), F_GLOBAL}, {HB_TAG('r','c','l','t'), F_GLOBAL}, @@ -274,18 +331,22 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, break; } +#ifndef HB_NO_OT_SHAPE_FRACTIONS /* Automatic fractions. */ map->add_feature (HB_TAG ('f','r','a','c')); map->add_feature (HB_TAG ('n','u','m','r')); map->add_feature (HB_TAG ('d','n','o','m')); +#endif /* Random! */ map->enable_feature (HB_TAG ('r','a','n','d'), F_RANDOM, HB_OT_MAP_MAX_VALUE); +#ifndef HB_NO_AAT_SHAPE /* Tracking. We enable dummy feature here just to allow disabling * AAT 'trak' table using features. * https://github.com/harfbuzz/harfbuzz/issues/1303 */ map->enable_feature (HB_TAG ('t','r','a','k'), F_HAS_FALLBACK); +#endif map->enable_feature (HB_TAG ('H','A','R','F')); @@ -318,6 +379,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, feature->value); } +#ifndef HB_NO_AAT_SHAPE if (planner->apply_morx) { hb_aat_map_builder_t *aat_map = &planner->aat_map; @@ -327,6 +389,7 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner, aat_map->add_feature (feature->tag, feature->value); } } +#endif if (planner->shaper->override_features) planner->shaper->override_features (planner); @@ -417,6 +480,7 @@ hb_set_unicode_props (hb_buffer_t *buffer) { _hb_glyph_info_set_continuation (&info[i]); } +#ifndef HB_NO_EMOJI_SEQUENCES else if (unlikely (_hb_glyph_info_is_zwj (&info[i]))) { _hb_glyph_info_set_continuation (&info[i]); @@ -428,6 +492,7 @@ hb_set_unicode_props (hb_buffer_t *buffer) _hb_glyph_info_set_continuation (&info[i]); } } +#endif /* Or part of the Other_Grapheme_Extend that is not marks. * As of Unicode 11 that is just: * @@ -448,6 +513,9 @@ hb_set_unicode_props (hb_buffer_t *buffer) static void hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) { + if (unlikely (buffer->flags & HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE)) + return; + if (!(buffer->flags & HB_BUFFER_FLAG_BOT) || buffer->context_len[0] || !_hb_glyph_info_is_unicode_mark (&buffer->info[0])) @@ -524,30 +592,95 @@ hb_ensure_native_direction (hb_buffer_t *buffer) * Substitute */ -static inline void -hb_ot_mirror_chars (const hb_ot_shape_context_t *c) +static hb_codepoint_t +hb_vert_char_for (hb_codepoint_t u) { - if (HB_DIRECTION_IS_FORWARD (c->target_direction)) - return; + switch (u >> 8) + { + case 0x20: switch (u) { + case 0x2013u: return 0xfe32u; // EN DASH + case 0x2014u: return 0xfe31u; // EM DASH + case 0x2025u: return 0xfe30u; // TWO DOT LEADER + case 0x2026u: return 0xfe19u; // HORIZONTAL ELLIPSIS + } break; + case 0x30: switch (u) { + case 0x3001u: return 0xfe11u; // IDEOGRAPHIC COMMA + case 0x3002u: return 0xfe12u; // IDEOGRAPHIC FULL STOP + case 0x3008u: return 0xfe3fu; // LEFT ANGLE BRACKET + case 0x3009u: return 0xfe40u; // RIGHT ANGLE BRACKET + case 0x300au: return 0xfe3du; // LEFT DOUBLE ANGLE BRACKET + case 0x300bu: return 0xfe3eu; // RIGHT DOUBLE ANGLE BRACKET + case 0x300cu: return 0xfe41u; // LEFT CORNER BRACKET + case 0x300du: return 0xfe42u; // RIGHT CORNER BRACKET + case 0x300eu: return 0xfe43u; // LEFT WHITE CORNER BRACKET + case 0x300fu: return 0xfe44u; // RIGHT WHITE CORNER BRACKET + case 0x3010u: return 0xfe3bu; // LEFT BLACK LENTICULAR BRACKET + case 0x3011u: return 0xfe3cu; // RIGHT BLACK LENTICULAR BRACKET + case 0x3014u: return 0xfe39u; // LEFT TORTOISE SHELL BRACKET + case 0x3015u: return 0xfe3au; // RIGHT TORTOISE SHELL BRACKET + case 0x3016u: return 0xfe17u; // LEFT WHITE LENTICULAR BRACKET + case 0x3017u: return 0xfe18u; // RIGHT WHITE LENTICULAR BRACKET + } break; + case 0xfe: switch (u) { + case 0xfe4fu: return 0xfe34u; // WAVY LOW LINE + } break; + case 0xff: switch (u) { + case 0xff01u: return 0xfe15u; // FULLWIDTH EXCLAMATION MARK + case 0xff08u: return 0xfe35u; // FULLWIDTH LEFT PARENTHESIS + case 0xff09u: return 0xfe36u; // FULLWIDTH RIGHT PARENTHESIS + case 0xff0cu: return 0xfe10u; // FULLWIDTH COMMA + case 0xff1au: return 0xfe13u; // FULLWIDTH COLON + case 0xff1bu: return 0xfe14u; // FULLWIDTH SEMICOLON + case 0xff1fu: return 0xfe16u; // FULLWIDTH QUESTION MARK + case 0xff3bu: return 0xfe47u; // FULLWIDTH LEFT SQUARE BRACKET + case 0xff3du: return 0xfe48u; // FULLWIDTH RIGHT SQUARE BRACKET + case 0xff3fu: return 0xfe33u; // FULLWIDTH LOW LINE + case 0xff5bu: return 0xfe37u; // FULLWIDTH LEFT CURLY BRACKET + case 0xff5du: return 0xfe38u; // FULLWIDTH RIGHT CURLY BRACKET + } break; + } - hb_buffer_t *buffer = c->buffer; - hb_unicode_funcs_t *unicode = buffer->unicode; - hb_mask_t rtlm_mask = c->plan->rtlm_mask; + return u; +} +static inline void +hb_ot_rotate_chars (const hb_ot_shape_context_t *c) +{ + hb_buffer_t *buffer = c->buffer; unsigned int count = buffer->len; hb_glyph_info_t *info = buffer->info; - for (unsigned int i = 0; i < count; i++) { - hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint); - if (likely (codepoint == info[i].codepoint || !c->font->has_glyph (codepoint))) - info[i].mask |= rtlm_mask; - else - info[i].codepoint = codepoint; + + if (HB_DIRECTION_IS_BACKWARD (c->target_direction)) + { + hb_unicode_funcs_t *unicode = buffer->unicode; + hb_mask_t rtlm_mask = c->plan->rtlm_mask; + + for (unsigned int i = 0; i < count; i++) { + hb_codepoint_t codepoint = unicode->mirroring (info[i].codepoint); + if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint))) + info[i].codepoint = codepoint; + else + info[i].mask |= rtlm_mask; + } + } + + if (HB_DIRECTION_IS_VERTICAL (c->target_direction) && !c->plan->has_vert) + { + for (unsigned int i = 0; i < count; i++) { + hb_codepoint_t codepoint = hb_vert_char_for (info[i].codepoint); + if (unlikely (codepoint != info[i].codepoint && c->font->has_glyph (codepoint))) + info[i].codepoint = codepoint; + } } } static inline void hb_ot_shape_setup_masks_fraction (const hb_ot_shape_context_t *c) { +#ifdef HB_NO_OT_SHAPE_FRACTIONS + return; +#endif + if (!(c->buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_NON_ASCII) || !c->plan->has_frac) return; @@ -619,7 +752,7 @@ hb_ot_shape_setup_masks (const hb_ot_shape_context_t *c) for (unsigned int i = 0; i < c->num_user_features; i++) { const hb_feature_t *feature = &c->user_features[i]; - if (!(feature->start == 0 && feature->end == (unsigned int)-1)) { + if (!(feature->start == HB_FEATURE_GLOBAL_START && feature->end == HB_FEATURE_GLOBAL_END)) { unsigned int shift; hb_mask_t mask = map->get_mask (feature->tag, &shift); buffer->set_masks (feature->value << shift, mask, feature->start, feature->end); @@ -714,7 +847,7 @@ hb_ot_substitute_default (const hb_ot_shape_context_t *c) { hb_buffer_t *buffer = c->buffer; - hb_ot_mirror_chars (c); + hb_ot_rotate_chars (c); HB_BUFFER_ALLOCATE_VAR (buffer, glyph_index); @@ -758,8 +891,10 @@ static inline void hb_ot_substitute_post (const hb_ot_shape_context_t *c) { hb_ot_hide_default_ignorables (c->buffer, c->font); +#ifndef HB_NO_AAT_SHAPE if (c->plan->apply_morx) hb_aat_layout_remove_deleted_glyphs (c->buffer); +#endif if (c->plan->shaper->postprocess_glyphs) c->plan->shaper->postprocess_glyphs (c->plan, c->buffer, c->font); @@ -893,8 +1028,10 @@ hb_ot_position_complex (const hb_ot_shape_context_t *c) /* Finish off. Has to follow a certain order. */ hb_ot_layout_position_finish_advances (c->font, c->buffer); hb_ot_zero_width_default_ignorables (c->buffer); +#ifndef HB_NO_AAT_SHAPE if (c->plan->apply_morx) hb_aat_layout_zero_width_deleted_glyphs (c->buffer); +#endif hb_ot_layout_position_finish_offsets (c->font, c->buffer); /* The nil glyph_h_origin() func returns 0, so no need to apply it. */ @@ -959,13 +1096,13 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c) c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR))) { - c->buffer->max_len = MAX (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR, - (unsigned) HB_BUFFER_MAX_LEN_MIN); + c->buffer->max_len = hb_max (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR, + (unsigned) HB_BUFFER_MAX_LEN_MIN); } if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR))) { - c->buffer->max_ops = MAX (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR, - (unsigned) HB_BUFFER_MAX_OPS_MIN); + c->buffer->max_ops = hb_max (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR, + (unsigned) HB_BUFFER_MAX_OPS_MIN); } /* Save the original direction, we use it later. */ @@ -1081,3 +1218,6 @@ hb_ot_shape_glyphs_closure (hb_font_t *font, hb_shape_plan_destroy (shape_plan); } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh index 5adc05827e6..7823126ee46 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-shape.hh @@ -37,9 +37,9 @@ struct hb_ot_shape_plan_key_t { unsigned int variations_index[2]; - void init (hb_face_t *face, - const int *coords, - unsigned int num_coords) + void init (hb_face_t *face, + const int *coords, + unsigned num_coords) { for (unsigned int table_index = 0; table_index < 2; table_index++) hb_ot_layout_table_find_feature_variations (face, @@ -65,14 +65,41 @@ struct hb_ot_shape_plan_t hb_ot_map_t map; hb_aat_map_t aat_map; const void *data; +#ifndef HB_NO_OT_SHAPE_FRACTIONS hb_mask_t frac_mask, numr_mask, dnom_mask; +#else + static constexpr hb_mask_t frac_mask = 0; + static constexpr hb_mask_t numr_mask = 0; + static constexpr hb_mask_t dnom_mask = 0; +#endif hb_mask_t rtlm_mask; +#ifndef HB_NO_OT_KERN hb_mask_t kern_mask; +#else + static constexpr hb_mask_t kern_mask = 0; +#endif +#ifndef HB_NO_AAT_SHAPE hb_mask_t trak_mask; +#else + static constexpr hb_mask_t trak_mask = 0; +#endif +#ifndef HB_NO_OT_KERN bool requested_kerning : 1; +#else + static constexpr bool requested_kerning = false; +#endif +#ifndef HB_NO_AAT_SHAPE bool requested_tracking : 1; +#else + static constexpr bool requested_tracking = false; +#endif +#ifndef HB_NO_OT_SHAPE_FRACTIONS bool has_frac : 1; +#else + static constexpr bool has_frac = false; +#endif + bool has_vert : 1; bool has_gpos_mark : 1; bool zero_marks : 1; bool fallback_glyph_classes : 1; @@ -80,10 +107,20 @@ struct hb_ot_shape_plan_t bool adjust_mark_positioning_when_zeroing : 1; bool apply_gpos : 1; - bool apply_kerx : 1; +#ifndef HB_NO_OT_KERN bool apply_kern : 1; +#else + static constexpr bool apply_kern = false; +#endif +#ifndef HB_NO_AAT_SHAPE + bool apply_kerx : 1; bool apply_morx : 1; bool apply_trak : 1; +#else + static constexpr bool apply_kerx = false; + static constexpr bool apply_morx = false; + static constexpr bool apply_trak = false; +#endif void collect_lookups (hb_tag_t table_tag, hb_set_t *lookups) const { @@ -113,7 +150,11 @@ struct hb_ot_shape_planner_t hb_segment_properties_t props; hb_ot_map_builder_t map; hb_aat_map_builder_t aat_map; +#ifndef HB_NO_AAT_SHAPE bool apply_morx : 1; +#else + static constexpr bool apply_morx = false; +#endif bool script_zero_marks : 1; bool script_fallback_mark_positioning : 1; const struct hb_ot_complex_shaper_t *shaper; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh index 63dbfce4551..ca97affc9a6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-stat-table.hh @@ -59,6 +59,11 @@ enum struct AxisValueFormat1 { + unsigned int get_axis_index () const { return axisIndex; } + float get_value () const { return value.to_float (); } + + hb_ot_name_id_t get_value_name_id () const { return valueNameID; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -75,13 +80,18 @@ struct AxisValueFormat1 NameID valueNameID; /* The name ID for entries in the 'name' table * that provide a display string for this * attribute value. */ - Fixed value; /* A numeric value for this attribute value. */ + HBFixed value; /* A numeric value for this attribute value. */ public: DEFINE_SIZE_STATIC (12); }; struct AxisValueFormat2 { + unsigned int get_axis_index () const { return axisIndex; } + float get_value () const { return nominalValue.to_float (); } + + hb_ot_name_id_t get_value_name_id () const { return valueNameID; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -98,10 +108,10 @@ struct AxisValueFormat2 NameID valueNameID; /* The name ID for entries in the 'name' table * that provide a display string for this * attribute value. */ - Fixed nominalValue; /* A numeric value for this attribute value. */ - Fixed rangeMinValue; /* The minimum value for a range associated + HBFixed nominalValue; /* A numeric value for this attribute value. */ + HBFixed rangeMinValue; /* The minimum value for a range associated * with the specified name ID. */ - Fixed rangeMaxValue; /* The maximum value for a range associated + HBFixed rangeMaxValue; /* The maximum value for a range associated * with the specified name ID. */ public: DEFINE_SIZE_STATIC (20); @@ -109,6 +119,11 @@ struct AxisValueFormat2 struct AxisValueFormat3 { + unsigned int get_axis_index () const { return axisIndex; } + float get_value () const { return value.to_float (); } + + hb_ot_name_id_t get_value_name_id () const { return valueNameID; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -125,8 +140,8 @@ struct AxisValueFormat3 NameID valueNameID; /* The name ID for entries in the 'name' table * that provide a display string for this * attribute value. */ - Fixed value; /* A numeric value for this attribute value. */ - Fixed linkedValue; /* The numeric value for a style-linked mapping + HBFixed value; /* A numeric value for this attribute value. */ + HBFixed linkedValue; /* The numeric value for a style-linked mapping * from this value. */ public: DEFINE_SIZE_STATIC (16); @@ -134,6 +149,9 @@ struct AxisValueFormat3 struct AxisValueRecord { + unsigned int get_axis_index () const { return axisIndex; } + float get_value () const { return value.to_float (); } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -144,13 +162,18 @@ struct AxisValueRecord HBUINT16 axisIndex; /* Zero-base index into the axis record array * identifying the axis to which this value * applies. Must be less than designAxisCount. */ - Fixed value; /* A numeric value for this attribute value. */ + HBFixed value; /* A numeric value for this attribute value. */ public: DEFINE_SIZE_STATIC (6); }; struct AxisValueFormat4 { + const AxisValueRecord &get_axis_record (unsigned int axis_index) const + { return axisValues.as_array (axisCount)[axis_index]; } + + hb_ot_name_id_t get_value_name_id () const { return valueNameID; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -175,19 +198,55 @@ struct AxisValueFormat4 struct AxisValue { + bool get_value (unsigned int axis_index) const + { + switch (u.format) + { + case 1: return u.format1.get_value (); + case 2: return u.format2.get_value (); + case 3: return u.format3.get_value (); + case 4: return u.format4.get_axis_record (axis_index).get_value (); + default:return 0; + } + } + + unsigned int get_axis_index () const + { + switch (u.format) + { + case 1: return u.format1.get_axis_index (); + case 2: return u.format2.get_axis_index (); + case 3: return u.format3.get_axis_index (); + /* case 4: Makes more sense for variable fonts which are handled by fvar in hb-style */ + default:return -1; + } + } + + hb_ot_name_id_t get_value_name_id () const + { + switch (u.format) + { + case 1: return u.format1.get_value_name_id (); + case 2: return u.format2.get_value_name_id (); + case 3: return u.format3.get_value_name_id (); + case 4: return u.format4.get_value_name_id (); + default:return HB_OT_NAME_ID_INVALID; + } + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - if (unlikely (c->check_struct (this))) + if (unlikely (!c->check_struct (this))) return_trace (false); switch (u.format) { - case 1: return_trace (likely (u.format1.sanitize (c))); - case 2: return_trace (likely (u.format2.sanitize (c))); - case 3: return_trace (likely (u.format3.sanitize (c))); - case 4: return_trace (likely (u.format4.sanitize (c))); - default: return_trace (true); + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 3: return_trace (u.format3.sanitize (c)); + case 4: return_trace (u.format4.sanitize (c)); + default:return_trace (true); } } @@ -206,6 +265,10 @@ struct AxisValue struct StatAxisRecord { + int cmp (hb_tag_t key) const { return tag.cmp (key); } + + hb_ot_name_id_t get_name_id () const { return nameID; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); @@ -227,21 +290,82 @@ struct STAT { static constexpr hb_tag_t tableTag = HB_OT_TAG_STAT; + bool has_data () const { return version.to_int (); } + + bool get_value (hb_tag_t tag, float *value) const + { + unsigned int axis_index; + if (!get_design_axes ().lfind (tag, &axis_index)) return false; + + hb_array_t> axis_values = get_axis_value_offsets (); + for (unsigned int i = 0; i < axis_values.length; i++) + { + const AxisValue& axis_value = this+axis_values[i]; + if (axis_value.get_axis_index () == axis_index) + { + if (value) + *value = axis_value.get_value (axis_index); + return true; + } + } + return false; + } + + unsigned get_design_axis_count () const { return designAxisCount; } + + hb_ot_name_id_t get_axis_record_name_id (unsigned axis_record_index) const + { + if (unlikely (axis_record_index >= designAxisCount)) return HB_OT_NAME_ID_INVALID; + const StatAxisRecord &axis_record = get_design_axes ()[axis_record_index]; + return axis_record.get_name_id (); + } + + unsigned get_axis_value_count () const { return axisValueCount; } + + hb_ot_name_id_t get_axis_value_name_id (unsigned axis_value_index) const + { + if (unlikely (axis_value_index >= axisValueCount)) return HB_OT_NAME_ID_INVALID; + const AxisValue &axis_value = (this + get_axis_value_offsets ()[axis_value_index]); + return axis_value.get_value_name_id (); + } + + void collect_name_ids (hb_set_t *nameids_to_retain) const + { + if (!has_data ()) return; + + + get_design_axes () + | hb_map (&StatAxisRecord::get_name_id) + | hb_sink (nameids_to_retain) + ; + + + get_axis_value_offsets () + | hb_map (hb_add (&(this + offsetToAxisValueOffsets))) + | hb_map (&AxisValue::get_value_name_id) + | hb_sink (nameids_to_retain) + ; + } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (likely (c->check_struct (this) && - majorVersion == 1 && - minorVersion > 0 && + version.major == 1 && + version.minor > 0 && designAxesOffset.sanitize (c, this, designAxisCount) && offsetToAxisValueOffsets.sanitize (c, this, axisValueCount, &(this+offsetToAxisValueOffsets)))); } protected: - HBUINT16 majorVersion; /* Major version number of the style attributes - * table — set to 1. */ - HBUINT16 minorVersion; /* Minor version number of the style attributes - * table — set to 2. */ + hb_array_t const get_design_axes () const + { return (this+designAxesOffset).as_array (designAxisCount); } + + hb_array_t> const get_axis_value_offsets () const + { return (this+offsetToAxisValueOffsets).as_array (axisValueCount); } + + + protected: + FixedVersion<>version; /* Version of the stat table + * initially set to 0x00010002u */ HBUINT16 designAxisSize; /* The size in bytes of each axis record. */ HBUINT16 designAxisCount;/* The number of design axis records. In a * font with an 'fvar' table, this value must be @@ -249,7 +373,7 @@ struct STAT * in the 'fvar' table. In all fonts, must * be greater than zero if axisValueCount * is greater than zero. */ - LNNOffsetTo > + LNNOffsetTo> designAxesOffset; /* Offset in bytes from the beginning of * the STAT table to the start of the design @@ -257,7 +381,7 @@ struct STAT * set to zero; if designAxisCount is greater * than zero, must be greater than zero. */ HBUINT16 axisValueCount; /* The number of axis value tables. */ - LNNOffsetTo > > + LNNOffsetTo>> offsetToAxisValueOffsets; /* Offset in bytes from the beginning of * the STAT table to the start of the design diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh index 93333bb3ff0..9109b487b91 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag-table.hh @@ -6,1055 +6,1058 @@ * * on files with these headers: * - * - * File-Date: 2018-08-08 + * + * File-Date: 2020-05-12 */ #ifndef HB_OT_TAG_TABLE_HH #define HB_OT_TAG_TABLE_HH static const LangTag ot_languages[] = { - {"aa", {HB_TAG('A','F','R',' ')}}, /* Afar */ - {"aae", {HB_TAG('S','Q','I',' ')}}, /* Arbëreshë Albanian -> Albanian */ - {"aao", {HB_TAG('A','R','A',' ')}}, /* Algerian Saharan Arabic -> Arabic */ - {"aat", {HB_TAG('S','Q','I',' ')}}, /* Arvanitika Albanian -> Albanian */ - {"ab", {HB_TAG('A','B','K',' ')}}, /* Abkhazian */ - {"abh", {HB_TAG('A','R','A',' ')}}, /* Tajiki Arabic -> Arabic */ - {"abq", {HB_TAG('A','B','A',' ')}}, /* Abaza */ - {"abv", {HB_TAG('A','R','A',' ')}}, /* Baharna Arabic -> Arabic */ - {"acf", {HB_TAG('F','A','N',' ')}}, /* Saint Lucian Creole French -> French Antillean */ - {"ach", {HB_TAG('A','C','H',' ')}}, /* Acoli -> Acholi */ - {"acm", {HB_TAG('A','R','A',' ')}}, /* Mesopotamian Arabic -> Arabic */ - {"acq", {HB_TAG('A','R','A',' ')}}, /* Ta'izzi-Adeni Arabic -> Arabic */ - {"acr", {HB_TAG('A','C','R',' ')}}, /* Achi */ - {"acw", {HB_TAG('A','R','A',' ')}}, /* Hijazi Arabic -> Arabic */ - {"acx", {HB_TAG('A','R','A',' ')}}, /* Omani Arabic -> Arabic */ - {"acy", {HB_TAG('A','R','A',' ')}}, /* Cypriot Arabic -> Arabic */ - {"ada", {HB_TAG('D','N','G',' ')}}, /* Adangme -> Dangme */ - {"adf", {HB_TAG('A','R','A',' ')}}, /* Dhofari Arabic -> Arabic */ - {"adp", {HB_TAG('D','Z','N',' ')}}, /* Adap (retired code) -> Dzongkha */ - {"ady", {HB_TAG('A','D','Y',' ')}}, /* Adyghe */ - {"aeb", {HB_TAG('A','R','A',' ')}}, /* Tunisian Arabic -> Arabic */ - {"aec", {HB_TAG('A','R','A',' ')}}, /* Saidi Arabic -> Arabic */ - {"af", {HB_TAG('A','F','K',' ')}}, /* Afrikaans */ - {"afb", {HB_TAG('A','R','A',' ')}}, /* Gulf Arabic -> Arabic */ - {"ahg", {HB_TAG('A','G','W',' ')}}, /* Qimant -> Agaw */ - {"aht", {HB_TAG('A','T','H',' ')}}, /* Ahtena -> Athapaskan */ - {"aii", {HB_TAG('S','W','A',' '), /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ - HB_TAG('S','Y','R',' ')}}, /* Assyrian Neo-Aramaic -> Syriac */ - {"aio", {HB_TAG('A','I','O',' ')}}, /* Aiton */ - {"aiw", {HB_TAG('A','R','I',' ')}}, /* Aari */ - {"ajp", {HB_TAG('A','R','A',' ')}}, /* South Levantine Arabic -> Arabic */ - {"ak", {HB_TAG('A','K','A',' '), /* Akan [macrolanguage] */ - HB_TAG('T','W','I',' ')}}, /* Akan [macrolanguage] -> Twi */ - {"aln", {HB_TAG('S','Q','I',' ')}}, /* Gheg Albanian -> Albanian */ - {"als", {HB_TAG('S','Q','I',' ')}}, /* Tosk Albanian -> Albanian */ - {"alt", {HB_TAG('A','L','T',' ')}}, /* Southern Altai -> Altai */ - {"am", {HB_TAG('A','M','H',' ')}}, /* Amharic */ - {"amf", {HB_TAG('H','B','N',' ')}}, /* Hamer-Banna -> Hammer-Banna */ - {"amw", {HB_TAG('S','Y','R',' ')}}, /* Western Neo-Aramaic -> Syriac */ - {"an", {HB_TAG('A','R','G',' ')}}, /* Aragonese */ - {"ang", {HB_TAG('A','N','G',' ')}}, /* Old English (ca. 450-1100) -> Anglo-Saxon */ - {"apc", {HB_TAG('A','R','A',' ')}}, /* North Levantine Arabic -> Arabic */ - {"apd", {HB_TAG('A','R','A',' ')}}, /* Sudanese Arabic -> Arabic */ - {"apj", {HB_TAG('A','T','H',' ')}}, /* Jicarilla Apache -> Athapaskan */ - {"apk", {HB_TAG('A','T','H',' ')}}, /* Kiowa Apache -> Athapaskan */ - {"apl", {HB_TAG('A','T','H',' ')}}, /* Lipan Apache -> Athapaskan */ - {"apm", {HB_TAG('A','T','H',' ')}}, /* Mescalero-Chiricahua Apache -> Athapaskan */ - {"apw", {HB_TAG('A','T','H',' ')}}, /* Western Apache -> Athapaskan */ - {"ar", {HB_TAG('A','R','A',' ')}}, /* Arabic [macrolanguage] */ - {"arb", {HB_TAG('A','R','A',' ')}}, /* Standard Arabic -> Arabic */ - {"arn", {HB_TAG('M','A','P',' ')}}, /* Mapudungun */ - {"arq", {HB_TAG('A','R','A',' ')}}, /* Algerian Arabic -> Arabic */ - {"ars", {HB_TAG('A','R','A',' ')}}, /* Najdi Arabic -> Arabic */ - {"ary", {HB_TAG('M','O','R',' ')}}, /* Moroccan Arabic -> Moroccan */ - {"arz", {HB_TAG('A','R','A',' ')}}, /* Egyptian Arabic -> Arabic */ - {"as", {HB_TAG('A','S','M',' ')}}, /* Assamese */ - {"ast", {HB_TAG('A','S','T',' ')}}, /* Asturian */ - {"ath", {HB_TAG('A','T','H',' ')}}, /* Athapascan [family] -> Athapaskan */ - {"atj", {HB_TAG('R','C','R',' ')}}, /* Atikamekw -> R-Cree */ - {"atv", {HB_TAG('A','L','T',' ')}}, /* Northern Altai -> Altai */ - {"auz", {HB_TAG('A','R','A',' ')}}, /* Uzbeki Arabic -> Arabic */ - {"av", {HB_TAG('A','V','R',' ')}}, /* Avaric -> Avar */ - {"avl", {HB_TAG('A','R','A',' ')}}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ - {"awa", {HB_TAG('A','W','A',' ')}}, /* Awadhi */ - {"ay", {HB_TAG('A','Y','M',' ')}}, /* Aymara [macrolanguage] */ - {"ayc", {HB_TAG('A','Y','M',' ')}}, /* Southern Aymara -> Aymara */ - {"ayh", {HB_TAG('A','R','A',' ')}}, /* Hadrami Arabic -> Arabic */ - {"ayl", {HB_TAG('A','R','A',' ')}}, /* Libyan Arabic -> Arabic */ - {"ayn", {HB_TAG('A','R','A',' ')}}, /* Sanaani Arabic -> Arabic */ - {"ayp", {HB_TAG('A','R','A',' ')}}, /* North Mesopotamian Arabic -> Arabic */ - {"ayr", {HB_TAG('A','Y','M',' ')}}, /* Central Aymara -> Aymara */ - {"az", {HB_TAG('A','Z','E',' ')}}, /* Azerbaijani [macrolanguage] */ - {"azb", {HB_TAG('A','Z','B',' ')}}, /* South Azerbaijani -> Torki */ - {"azj", {HB_TAG('A','Z','E',' ')}}, /* North Azerbaijani -> Azerbaijani */ - {"ba", {HB_TAG('B','S','H',' ')}}, /* Bashkir */ - {"bad", {HB_TAG('B','A','D','0')}}, /* Banda [family] */ - {"bai", {HB_TAG('B','M','L',' ')}}, /* Bamileke [family] */ - {"bal", {HB_TAG('B','L','I',' ')}}, /* Baluchi [macrolanguage] */ - {"ban", {HB_TAG('B','A','N',' ')}}, /* Balinese */ - {"bar", {HB_TAG('B','A','R',' ')}}, /* Bavarian */ - {"bbc", {HB_TAG('B','B','C',' ')}}, /* Batak Toba */ - {"bbz", {HB_TAG('A','R','A',' ')}}, /* Babalia Creole Arabic -> Arabic */ - {"bcc", {HB_TAG('B','L','I',' ')}}, /* Southern Balochi -> Baluchi */ - {"bci", {HB_TAG('B','A','U',' ')}}, /* Baoulé -> Baulé */ - {"bcl", {HB_TAG('B','I','K',' ')}}, /* Central Bikol -> Bikol */ - {"bcq", {HB_TAG('B','C','H',' ')}}, /* Bench */ - {"bcr", {HB_TAG('A','T','H',' ')}}, /* Babine -> Athapaskan */ - {"bdy", {HB_TAG('B','D','Y',' ')}}, /* Bandjalang */ - {"be", {HB_TAG('B','E','L',' ')}}, /* Belarusian -> Belarussian */ - {"bea", {HB_TAG('A','T','H',' ')}}, /* Beaver -> Athapaskan */ - {"beb", {HB_TAG('B','T','I',' ')}}, /* Bebele -> Beti */ - {"bem", {HB_TAG('B','E','M',' ')}}, /* Bemba (Zambia) */ - {"ber", {HB_TAG('B','B','R',' ')}}, /* Berber [family] */ - {"bfq", {HB_TAG('B','A','D',' ')}}, /* Badaga */ - {"bft", {HB_TAG('B','L','T',' ')}}, /* Balti */ - {"bfu", {HB_TAG('L','A','H',' ')}}, /* Gahri -> Lahuli */ - {"bfy", {HB_TAG('B','A','G',' ')}}, /* Bagheli -> Baghelkhandi */ - {"bg", {HB_TAG('B','G','R',' ')}}, /* Bulgarian */ - {"bgc", {HB_TAG('B','G','C',' ')}}, /* Haryanvi */ - {"bgn", {HB_TAG('B','L','I',' ')}}, /* Western Balochi -> Baluchi */ - {"bgp", {HB_TAG('B','L','I',' ')}}, /* Eastern Balochi -> Baluchi */ - {"bgq", {HB_TAG('B','G','Q',' ')}}, /* Bagri */ - {"bgr", {HB_TAG('Q','I','N',' ')}}, /* Bawm Chin -> Chin */ - {"bhb", {HB_TAG('B','H','I',' ')}}, /* Bhili */ - {"bhi", {HB_TAG('B','H','I',' ')}}, /* Bhilali -> Bhili */ - {"bhk", {HB_TAG('B','I','K',' ')}}, /* Albay Bicolano (retired code) -> Bikol */ - {"bho", {HB_TAG('B','H','O',' ')}}, /* Bhojpuri */ - {"bhr", {HB_TAG('M','L','G',' ')}}, /* Bara Malagasy -> Malagasy */ - {"bi", {HB_TAG('B','I','S',' ')}}, /* Bislama */ - {"bik", {HB_TAG('B','I','K',' ')}}, /* Bikol [macrolanguage] */ - {"bin", {HB_TAG('E','D','O',' ')}}, /* Edo */ - {"bjj", {HB_TAG('B','J','J',' ')}}, /* Kanauji */ - {"bjn", {HB_TAG('M','L','Y',' ')}}, /* Banjar -> Malay */ - {"bjq", {HB_TAG('M','L','G',' ')}}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ - {"bjt", {HB_TAG('B','L','N',' ')}}, /* Balanta-Ganja -> Balante */ - {"bla", {HB_TAG('B','K','F',' ')}}, /* Siksika -> Blackfoot */ - {"ble", {HB_TAG('B','L','N',' ')}}, /* Balanta-Kentohe -> Balante */ - {"blk", {HB_TAG('B','L','K',' ')}}, /* Pa'o Karen */ - {"bln", {HB_TAG('B','I','K',' ')}}, /* Southern Catanduanes Bikol -> Bikol */ - {"bm", {HB_TAG('B','M','B',' ')}}, /* Bambara (Bamanankan) */ - {"bmm", {HB_TAG('M','L','G',' ')}}, /* Northern Betsimisaraka Malagasy -> Malagasy */ - {"bn", {HB_TAG('B','E','N',' ')}}, /* Bengali */ - {"bo", {HB_TAG('T','I','B',' ')}}, /* Tibetan */ - {"bpy", {HB_TAG('B','P','Y',' ')}}, /* Bishnupriya -> Bishnupriya Manipuri */ - {"bqi", {HB_TAG('L','R','C',' ')}}, /* Bakhtiari -> Luri */ - {"br", {HB_TAG('B','R','E',' ')}}, /* Breton */ - {"bra", {HB_TAG('B','R','I',' ')}}, /* Braj -> Braj Bhasha */ - {"brh", {HB_TAG('B','R','H',' ')}}, /* Brahui */ - {"brx", {HB_TAG('B','R','X',' ')}}, /* Bodo (India) */ - {"bs", {HB_TAG('B','O','S',' ')}}, /* Bosnian */ - {"bsk", {HB_TAG('B','S','K',' ')}}, /* Burushaski */ - {"btb", {HB_TAG('B','T','I',' ')}}, /* Beti (Cameroon) (retired code) */ - {"btj", {HB_TAG('M','L','Y',' ')}}, /* Bacanese Malay -> Malay */ - {"bto", {HB_TAG('B','I','K',' ')}}, /* Rinconada Bikol -> Bikol */ - {"bts", {HB_TAG('B','T','S',' ')}}, /* Batak Simalungun */ - {"bug", {HB_TAG('B','U','G',' ')}}, /* Buginese -> Bugis */ - {"bum", {HB_TAG('B','T','I',' ')}}, /* Bulu (Cameroon) -> Beti */ - {"bve", {HB_TAG('M','L','Y',' ')}}, /* Berau Malay -> Malay */ - {"bvu", {HB_TAG('M','L','Y',' ')}}, /* Bukit Malay -> Malay */ - {"bxk", {HB_TAG('L','U','H',' ')}}, /* Bukusu -> Luyia */ - {"bxp", {HB_TAG('B','T','I',' ')}}, /* Bebil -> Beti */ - {"bxr", {HB_TAG('R','B','U',' ')}}, /* Russia Buriat -> Russian Buriat */ - {"byn", {HB_TAG('B','I','L',' ')}}, /* Bilin -> Bilen */ - {"byv", {HB_TAG('B','Y','V',' ')}}, /* Medumba */ - {"bzc", {HB_TAG('M','L','G',' ')}}, /* Southern Betsimisaraka Malagasy -> Malagasy */ - {"ca", {HB_TAG('C','A','T',' ')}}, /* Catalan */ - {"caf", {HB_TAG('C','R','R',' '), /* Southern Carrier -> Carrier */ - HB_TAG('A','T','H',' ')}}, /* Southern Carrier -> Athapaskan */ - {"cak", {HB_TAG('C','A','K',' ')}}, /* Kaqchikel */ - {"cbk", {HB_TAG('C','B','K',' ')}}, /* Chavacano -> Zamboanga Chavacano */ - {"cbl", {HB_TAG('Q','I','N',' ')}}, /* Bualkhaw Chin -> Chin */ - {"cco", {HB_TAG('C','C','H','N')}}, /* Comaltepec Chinantec -> Chinantec */ - {"ccq", {HB_TAG('A','R','K',' ')}}, /* Chaungtha (retired code) -> Rakhine */ - {"cdo", {HB_TAG('Z','H','S',' ')}}, /* Min Dong Chinese -> Chinese Simplified */ - {"ce", {HB_TAG('C','H','E',' ')}}, /* Chechen */ - {"ceb", {HB_TAG('C','E','B',' ')}}, /* Cebuano */ - {"cfm", {HB_TAG('H','A','L',' ')}}, /* Halam (Falam Chin) */ - {"cgg", {HB_TAG('C','G','G',' ')}}, /* Chiga */ - {"ch", {HB_TAG('C','H','A',' ')}}, /* Chamorro */ - {"chj", {HB_TAG('C','C','H','N')}}, /* Ojitlán Chinantec -> Chinantec */ - {"chk", {HB_TAG('C','H','K','0')}}, /* Chuukese */ - {"cho", {HB_TAG('C','H','O',' ')}}, /* Choctaw */ - {"chp", {HB_TAG('C','H','P',' '), /* Chipewyan */ - HB_TAG('S','A','Y',' '), /* Chipewyan -> Sayisi */ - HB_TAG('A','T','H',' ')}}, /* Chipewyan -> Athapaskan */ - {"chq", {HB_TAG('C','C','H','N')}}, /* Quiotepec Chinantec -> Chinantec */ - {"chr", {HB_TAG('C','H','R',' ')}}, /* Cherokee */ - {"chy", {HB_TAG('C','H','Y',' ')}}, /* Cheyenne */ - {"chz", {HB_TAG('C','C','H','N')}}, /* Ozumacín Chinantec -> Chinantec */ - {"ciw", {HB_TAG('O','J','B',' ')}}, /* Chippewa -> Ojibway */ - {"cja", {HB_TAG('C','J','A',' ')}}, /* Western Cham */ - {"cjm", {HB_TAG('C','J','M',' ')}}, /* Eastern Cham */ - {"cjy", {HB_TAG('Z','H','S',' ')}}, /* Jinyu Chinese -> Chinese Simplified */ - {"cka", {HB_TAG('Q','I','N',' ')}}, /* Khumi Awa Chin (retired code) -> Chin */ - {"ckb", {HB_TAG('K','U','R',' ')}}, /* Central Kurdish -> Kurdish */ - {"ckt", {HB_TAG('C','H','K',' ')}}, /* Chukot -> Chukchi */ - {"clc", {HB_TAG('A','T','H',' ')}}, /* Chilcotin -> Athapaskan */ - {"cld", {HB_TAG('S','Y','R',' ')}}, /* Chaldean Neo-Aramaic -> Syriac */ - {"cle", {HB_TAG('C','C','H','N')}}, /* Lealao Chinantec -> Chinantec */ - {"cmn", {HB_TAG('Z','H','S',' ')}}, /* Mandarin Chinese -> Chinese Simplified */ - {"cmr", {HB_TAG('Q','I','N',' ')}}, /* Mro-Khimi Chin -> Chin */ - {"cnb", {HB_TAG('Q','I','N',' ')}}, /* Chinbon Chin -> Chin */ - {"cnh", {HB_TAG('Q','I','N',' ')}}, /* Hakha Chin -> Chin */ - {"cnk", {HB_TAG('Q','I','N',' ')}}, /* Khumi Chin -> Chin */ - {"cnl", {HB_TAG('C','C','H','N')}}, /* Lalana Chinantec -> Chinantec */ - {"cnt", {HB_TAG('C','C','H','N')}}, /* Tepetotutla Chinantec -> Chinantec */ - {"cnw", {HB_TAG('Q','I','N',' ')}}, /* Ngawn Chin -> Chin */ - {"co", {HB_TAG('C','O','S',' ')}}, /* Corsican */ - {"coa", {HB_TAG('M','L','Y',' ')}}, /* Cocos Islands Malay -> Malay */ - {"cop", {HB_TAG('C','O','P',' ')}}, /* Coptic */ - {"coq", {HB_TAG('A','T','H',' ')}}, /* Coquille -> Athapaskan */ - {"cpa", {HB_TAG('C','C','H','N')}}, /* Palantla Chinantec -> Chinantec */ - {"cpe", {HB_TAG('C','P','P',' ')}}, /* English-based creoles and pidgins [family] -> Creoles */ - {"cpf", {HB_TAG('C','P','P',' ')}}, /* French-based creoles and pidgins [family] -> Creoles */ - {"cpp", {HB_TAG('C','P','P',' ')}}, /* Portuguese-based creoles and pidgins [family] -> Creoles */ - {"cpx", {HB_TAG('Z','H','S',' ')}}, /* Pu-Xian Chinese -> Chinese Simplified */ - {"cqd", {HB_TAG('H','M','N',' ')}}, /* Chuanqiandian Cluster Miao -> Hmong */ - {"cqu", {HB_TAG('Q','U','H',' ')}}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ - {"cr", {HB_TAG('C','R','E',' '), /* Cree [macrolanguage] */ - HB_TAG('Y','C','R',' ')}}, /* Cree [macrolanguage] -> Y-Cree */ - {"crh", {HB_TAG('C','R','T',' ')}}, /* Crimean Tatar */ - {"crj", {HB_TAG('E','C','R',' ')}}, /* Southern East Cree -> Eastern Cree */ - {"crk", {HB_TAG('W','C','R',' ')}}, /* Plains Cree -> West-Cree */ - {"crl", {HB_TAG('E','C','R',' ')}}, /* Northern East Cree -> Eastern Cree */ - {"crm", {HB_TAG('M','C','R',' '), /* Moose Cree */ - HB_TAG('L','C','R',' ')}}, /* Moose Cree -> L-Cree */ - {"crp", {HB_TAG('C','P','P',' ')}}, /* Creoles and pidgins [family] -> Creoles */ - {"crx", {HB_TAG('C','R','R',' '), /* Carrier */ - HB_TAG('A','T','H',' ')}}, /* Carrier -> Athapaskan */ - {"cs", {HB_TAG('C','S','Y',' ')}}, /* Czech */ - {"csa", {HB_TAG('C','C','H','N')}}, /* Chiltepec Chinantec -> Chinantec */ - {"csb", {HB_TAG('C','S','B',' ')}}, /* Kashubian */ - {"csh", {HB_TAG('Q','I','N',' ')}}, /* Asho Chin -> Chin */ - {"cso", {HB_TAG('C','C','H','N')}}, /* Sochiapam Chinantec -> Chinantec */ - {"csw", {HB_TAG('N','C','R',' '), /* Swampy Cree -> N-Cree */ - HB_TAG('N','H','C',' ')}}, /* Swampy Cree -> Norway House Cree */ - {"csy", {HB_TAG('Q','I','N',' ')}}, /* Siyin Chin -> Chin */ - {"ctc", {HB_TAG('A','T','H',' ')}}, /* Chetco -> Athapaskan */ - {"ctd", {HB_TAG('Q','I','N',' ')}}, /* Tedim Chin -> Chin */ - {"cte", {HB_TAG('C','C','H','N')}}, /* Tepinapa Chinantec -> Chinantec */ - {"ctg", {HB_TAG('C','T','G',' ')}}, /* Chittagonian */ - {"ctl", {HB_TAG('C','C','H','N')}}, /* Tlacoatzintepec Chinantec -> Chinantec */ - {"cts", {HB_TAG('B','I','K',' ')}}, /* Northern Catanduanes Bikol -> Bikol */ - {"cu", {HB_TAG('C','S','L',' ')}}, /* Church Slavonic */ - {"cuc", {HB_TAG('C','C','H','N')}}, /* Usila Chinantec -> Chinantec */ - {"cuk", {HB_TAG('C','U','K',' ')}}, /* San Blas Kuna */ - {"cv", {HB_TAG('C','H','U',' ')}}, /* Chuvash */ - {"cvn", {HB_TAG('C','C','H','N')}}, /* Valle Nacional Chinantec -> Chinantec */ - {"cwd", {HB_TAG('D','C','R',' '), /* Woods Cree */ - HB_TAG('T','C','R',' ')}}, /* Woods Cree -> TH-Cree */ - {"cy", {HB_TAG('W','E','L',' ')}}, /* Welsh */ - {"czh", {HB_TAG('Z','H','S',' ')}}, /* Huizhou Chinese -> Chinese Simplified */ - {"czo", {HB_TAG('Z','H','S',' ')}}, /* Min Zhong Chinese -> Chinese Simplified */ - {"czt", {HB_TAG('Q','I','N',' ')}}, /* Zotung Chin -> Chin */ - {"da", {HB_TAG('D','A','N',' ')}}, /* Danish */ - {"dao", {HB_TAG('Q','I','N',' ')}}, /* Daai Chin -> Chin */ - {"dap", {HB_TAG('N','I','S',' ')}}, /* Nisi (India) (retired code) */ - {"dar", {HB_TAG('D','A','R',' ')}}, /* Dargwa */ - {"dax", {HB_TAG('D','A','X',' ')}}, /* Dayi */ - {"de", {HB_TAG('D','E','U',' ')}}, /* German */ - {"den", {HB_TAG('S','L','A',' '), /* Slave (Athapascan) [macrolanguage] -> Slavey */ - HB_TAG('A','T','H',' ')}}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ - {"dgo", {HB_TAG('D','G','O',' ')}}, /* Dogri */ - {"dgr", {HB_TAG('A','T','H',' ')}}, /* Dogrib -> Athapaskan */ - {"dhd", {HB_TAG('M','A','W',' ')}}, /* Dhundari -> Marwari */ - {"dhg", {HB_TAG('D','H','G',' ')}}, /* Dhangu */ - {"dib", {HB_TAG('D','N','K',' ')}}, /* South Central Dinka -> Dinka */ - {"dik", {HB_TAG('D','N','K',' ')}}, /* Southwestern Dinka -> Dinka */ - {"din", {HB_TAG('D','N','K',' ')}}, /* Dinka [macrolanguage] */ - {"dip", {HB_TAG('D','N','K',' ')}}, /* Northeastern Dinka -> Dinka */ - {"diq", {HB_TAG('D','I','Q',' ')}}, /* Dimli */ - {"diw", {HB_TAG('D','N','K',' ')}}, /* Northwestern Dinka -> Dinka */ - {"dje", {HB_TAG('D','J','R',' ')}}, /* Zarma */ - {"djr", {HB_TAG('D','J','R','0')}}, /* Djambarrpuyngu */ - {"dks", {HB_TAG('D','N','K',' ')}}, /* Southeastern Dinka -> Dinka */ - {"dng", {HB_TAG('D','U','N',' ')}}, /* Dungan */ - {"dnj", {HB_TAG('D','N','J',' ')}}, /* Dan */ - {"doi", {HB_TAG('D','G','R',' ')}}, /* Dogri [macrolanguage] */ - {"drh", {HB_TAG('M','N','G',' ')}}, /* Darkhat (retired code) -> Mongolian */ - {"drw", {HB_TAG('D','R','I',' ')}}, /* Darwazi (retired code) -> Dari */ - {"dsb", {HB_TAG('L','S','B',' ')}}, /* Lower Sorbian */ - {"dty", {HB_TAG('N','E','P',' ')}}, /* Dotyali -> Nepali */ - {"duj", {HB_TAG('D','U','J',' ')}}, /* Dhuwal (retired code) */ - {"dup", {HB_TAG('M','L','Y',' ')}}, /* Duano -> Malay */ - {"dv", {HB_TAG('D','I','V',' '), /* Divehi (Dhivehi, Maldivian) */ - HB_TAG('D','H','V',' ')}}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ - {"dwu", {HB_TAG('D','U','J',' ')}}, /* Dhuwal */ - {"dwy", {HB_TAG('D','U','J',' ')}}, /* Dhuwaya -> Dhuwal */ - {"dyu", {HB_TAG('J','U','L',' ')}}, /* Dyula -> Jula */ - {"dz", {HB_TAG('D','Z','N',' ')}}, /* Dzongkha */ - {"ee", {HB_TAG('E','W','E',' ')}}, /* Ewe */ - {"efi", {HB_TAG('E','F','I',' ')}}, /* Efik */ - {"ekk", {HB_TAG('E','T','I',' ')}}, /* Standard Estonian -> Estonian */ - {"el", {HB_TAG('E','L','L',' ')}}, /* Modern Greek (1453-) -> Greek */ - {"emk", {HB_TAG('E','M','K',' '), /* Eastern Maninkakan */ - HB_TAG('M','N','K',' ')}}, /* Eastern Maninkakan -> Maninka */ - {"en", {HB_TAG('E','N','G',' ')}}, /* English */ - {"enb", {HB_TAG('K','A','L',' ')}}, /* Markweeta -> Kalenjin */ - {"enf", {HB_TAG('F','N','E',' ')}}, /* Forest Enets -> Forest Nenets */ - {"enh", {HB_TAG('T','N','E',' ')}}, /* Tundra Enets -> Tundra Nenets */ - {"eo", {HB_TAG('N','T','O',' ')}}, /* Esperanto */ - {"es", {HB_TAG('E','S','P',' ')}}, /* Spanish */ - {"esg", {HB_TAG('G','O','N',' ')}}, /* Aheri Gondi -> Gondi */ - {"esi", {HB_TAG('I','P','K',' ')}}, /* North Alaskan Inupiatun -> Inupiat */ - {"esk", {HB_TAG('I','P','K',' ')}}, /* Northwest Alaska Inupiatun -> Inupiat */ - {"esu", {HB_TAG('E','S','U',' ')}}, /* Central Yupik */ - {"et", {HB_TAG('E','T','I',' ')}}, /* Estonian [macrolanguage] */ - {"eto", {HB_TAG('B','T','I',' ')}}, /* Eton (Cameroon) -> Beti */ - {"eu", {HB_TAG('E','U','Q',' ')}}, /* Basque */ - {"eve", {HB_TAG('E','V','N',' ')}}, /* Even */ - {"evn", {HB_TAG('E','V','K',' ')}}, /* Evenki */ - {"ewo", {HB_TAG('B','T','I',' ')}}, /* Ewondo -> Beti */ - {"eyo", {HB_TAG('K','A','L',' ')}}, /* Keiyo -> Kalenjin */ - {"fa", {HB_TAG('F','A','R',' ')}}, /* Persian [macrolanguage] */ - {"fan", {HB_TAG('F','A','N','0')}}, /* Fang (Equatorial Guinea) */ - {"fat", {HB_TAG('F','A','T',' ')}}, /* Fanti */ - {"fbl", {HB_TAG('B','I','K',' ')}}, /* West Albay Bikol -> Bikol */ - {"ff", {HB_TAG('F','U','L',' ')}}, /* Fulah [macrolanguage] */ - {"ffm", {HB_TAG('F','U','L',' ')}}, /* Maasina Fulfulde -> Fulah */ - {"fi", {HB_TAG('F','I','N',' ')}}, /* Finnish */ - {"fil", {HB_TAG('P','I','L',' ')}}, /* Filipino */ - {"fj", {HB_TAG('F','J','I',' ')}}, /* Fijian */ - {"flm", {HB_TAG('H','A','L',' '), /* Halam (Falam Chin) (retired code) */ - HB_TAG('Q','I','N',' ')}}, /* Falam Chin (retired code) -> Chin */ - {"fmp", {HB_TAG('F','M','P',' ')}}, /* Fe'fe' */ - {"fo", {HB_TAG('F','O','S',' ')}}, /* Faroese */ - {"fon", {HB_TAG('F','O','N',' ')}}, /* Fon */ - {"fr", {HB_TAG('F','R','A',' ')}}, /* French */ - {"frc", {HB_TAG('F','R','C',' ')}}, /* Cajun French */ - {"frp", {HB_TAG('F','R','P',' ')}}, /* Arpitan */ - {"fub", {HB_TAG('F','U','L',' ')}}, /* Adamawa Fulfulde -> Fulah */ - {"fuc", {HB_TAG('F','U','L',' ')}}, /* Pulaar -> Fulah */ - {"fue", {HB_TAG('F','U','L',' ')}}, /* Borgu Fulfulde -> Fulah */ - {"fuf", {HB_TAG('F','T','A',' ')}}, /* Pular -> Futa */ - {"fuh", {HB_TAG('F','U','L',' ')}}, /* Western Niger Fulfulde -> Fulah */ - {"fui", {HB_TAG('F','U','L',' ')}}, /* Bagirmi Fulfulde -> Fulah */ - {"fuq", {HB_TAG('F','U','L',' ')}}, /* Central-Eastern Niger Fulfulde -> Fulah */ - {"fur", {HB_TAG('F','R','L',' ')}}, /* Friulian */ - {"fuv", {HB_TAG('F','U','V',' ')}}, /* Nigerian Fulfulde */ - {"fy", {HB_TAG('F','R','I',' ')}}, /* Western Frisian -> Frisian */ - {"ga", {HB_TAG('I','R','I',' ')}}, /* Irish */ - {"gaa", {HB_TAG('G','A','D',' ')}}, /* Ga */ - {"gag", {HB_TAG('G','A','G',' ')}}, /* Gagauz */ - {"gan", {HB_TAG('Z','H','S',' ')}}, /* Gan Chinese -> Chinese Simplified */ - {"gax", {HB_TAG('O','R','O',' ')}}, /* Borana-Arsi-Guji Oromo -> Oromo */ - {"gaz", {HB_TAG('O','R','O',' ')}}, /* West Central Oromo -> Oromo */ - {"gbm", {HB_TAG('G','A','W',' ')}}, /* Garhwali */ - {"gce", {HB_TAG('A','T','H',' ')}}, /* Galice -> Athapaskan */ - {"gd", {HB_TAG('G','A','E',' ')}}, /* Scottish Gaelic (Gaelic) */ - {"gda", {HB_TAG('R','A','J',' ')}}, /* Gade Lohar -> Rajasthani */ - {"gez", {HB_TAG('G','E','Z',' ')}}, /* Geez */ - {"ggo", {HB_TAG('G','O','N',' ')}}, /* Southern Gondi (retired code) -> Gondi */ - {"gih", {HB_TAG('G','I','H',' ')}}, /* Githabul */ - {"gil", {HB_TAG('G','I','L','0')}}, /* Kiribati (Gilbertese) */ - {"gju", {HB_TAG('R','A','J',' ')}}, /* Gujari -> Rajasthani */ - {"gkp", {HB_TAG('G','K','P',' ')}}, /* Guinea Kpelle -> Kpelle (Guinea) */ - {"gl", {HB_TAG('G','A','L',' ')}}, /* Galician */ - {"gld", {HB_TAG('N','A','N',' ')}}, /* Nanai */ - {"glk", {HB_TAG('G','L','K',' ')}}, /* Gilaki */ - {"gn", {HB_TAG('G','U','A',' ')}}, /* Guarani [macrolanguage] */ - {"gnn", {HB_TAG('G','N','N',' ')}}, /* Gumatj */ - {"gno", {HB_TAG('G','O','N',' ')}}, /* Northern Gondi -> Gondi */ - {"gnw", {HB_TAG('G','U','A',' ')}}, /* Western Bolivian Guaraní -> Guarani */ - {"gog", {HB_TAG('G','O','G',' ')}}, /* Gogo */ - {"gom", {HB_TAG('K','O','K',' ')}}, /* Goan Konkani -> Konkani */ - {"gon", {HB_TAG('G','O','N',' ')}}, /* Gondi [macrolanguage] */ - {"grt", {HB_TAG('G','R','O',' ')}}, /* Garo */ - {"gru", {HB_TAG('S','O','G',' ')}}, /* Kistane -> Sodo Gurage */ - {"gsw", {HB_TAG('A','L','S',' ')}}, /* Alsatian */ - {"gu", {HB_TAG('G','U','J',' ')}}, /* Gujarati */ - {"guc", {HB_TAG('G','U','C',' ')}}, /* Wayuu */ - {"guf", {HB_TAG('G','U','F',' ')}}, /* Gupapuyngu */ - {"gug", {HB_TAG('G','U','A',' ')}}, /* Paraguayan Guaraní -> Guarani */ - {"gui", {HB_TAG('G','U','A',' ')}}, /* Eastern Bolivian Guaraní -> Guarani */ - {"guk", {HB_TAG('G','M','Z',' '), /* Gumuz */ - HB_TAG('G','U','K',' ')}}, /* Gumuz (SIL fonts) */ - {"gun", {HB_TAG('G','U','A',' ')}}, /* Mbyá Guaraní -> Guarani */ - {"guz", {HB_TAG('G','U','Z',' ')}}, /* Gusii */ - {"gv", {HB_TAG('M','N','X',' ')}}, /* Manx */ - {"gwi", {HB_TAG('A','T','H',' ')}}, /* Gwichʼin -> Athapaskan */ - {"ha", {HB_TAG('H','A','U',' ')}}, /* Hausa */ - {"haa", {HB_TAG('A','T','H',' ')}}, /* Han -> Athapaskan */ - {"hae", {HB_TAG('O','R','O',' ')}}, /* Eastern Oromo -> Oromo */ - {"hak", {HB_TAG('Z','H','S',' ')}}, /* Hakka Chinese -> Chinese Simplified */ - {"har", {HB_TAG('H','R','I',' ')}}, /* Harari */ - {"haw", {HB_TAG('H','A','W',' ')}}, /* Hawaiian */ - {"hay", {HB_TAG('H','A','Y',' ')}}, /* Haya */ - {"haz", {HB_TAG('H','A','Z',' ')}}, /* Hazaragi */ - {"he", {HB_TAG('I','W','R',' ')}}, /* Hebrew */ - {"hea", {HB_TAG('H','M','N',' ')}}, /* Northern Qiandong Miao -> Hmong */ - {"hi", {HB_TAG('H','I','N',' ')}}, /* Hindi */ - {"hil", {HB_TAG('H','I','L',' ')}}, /* Hiligaynon */ - {"hji", {HB_TAG('M','L','Y',' ')}}, /* Haji -> Malay */ - {"hlt", {HB_TAG('Q','I','N',' ')}}, /* Matu Chin -> Chin */ - {"hma", {HB_TAG('H','M','N',' ')}}, /* Southern Mashan Hmong -> Hmong */ - {"hmc", {HB_TAG('H','M','N',' ')}}, /* Central Huishui Hmong -> Hmong */ - {"hmd", {HB_TAG('H','M','N',' ')}}, /* Large Flowery Miao -> Hmong */ - {"hme", {HB_TAG('H','M','N',' ')}}, /* Eastern Huishui Hmong -> Hmong */ - {"hmg", {HB_TAG('H','M','N',' ')}}, /* Southwestern Guiyang Hmong -> Hmong */ - {"hmh", {HB_TAG('H','M','N',' ')}}, /* Southwestern Huishui Hmong -> Hmong */ - {"hmi", {HB_TAG('H','M','N',' ')}}, /* Northern Huishui Hmong -> Hmong */ - {"hmj", {HB_TAG('H','M','N',' ')}}, /* Ge -> Hmong */ - {"hml", {HB_TAG('H','M','N',' ')}}, /* Luopohe Hmong -> Hmong */ - {"hmm", {HB_TAG('H','M','N',' ')}}, /* Central Mashan Hmong -> Hmong */ - {"hmn", {HB_TAG('H','M','N',' ')}}, /* Hmong [macrolanguage] */ - {"hmp", {HB_TAG('H','M','N',' ')}}, /* Northern Mashan Hmong -> Hmong */ - {"hmq", {HB_TAG('H','M','N',' ')}}, /* Eastern Qiandong Miao -> Hmong */ - {"hms", {HB_TAG('H','M','N',' ')}}, /* Southern Qiandong Miao -> Hmong */ - {"hmw", {HB_TAG('H','M','N',' ')}}, /* Western Mashan Hmong -> Hmong */ - {"hmy", {HB_TAG('H','M','N',' ')}}, /* Southern Guiyang Hmong -> Hmong */ - {"hmz", {HB_TAG('H','M','N',' ')}}, /* Hmong Shua -> Hmong */ - {"hnd", {HB_TAG('H','N','D',' ')}}, /* Southern Hindko -> Hindko */ - {"hne", {HB_TAG('C','H','H',' ')}}, /* Chhattisgarhi -> Chattisgarhi */ - {"hnj", {HB_TAG('H','M','N',' ')}}, /* Hmong Njua -> Hmong */ - {"hno", {HB_TAG('H','N','D',' ')}}, /* Northern Hindko -> Hindko */ - {"ho", {HB_TAG('H','M','O',' ')}}, /* Hiri Motu */ - {"hoc", {HB_TAG('H','O',' ',' ')}}, /* Ho */ - {"hoi", {HB_TAG('A','T','H',' ')}}, /* Holikachuk -> Athapaskan */ - {"hoj", {HB_TAG('H','A','R',' ')}}, /* Hadothi -> Harauti */ - {"hr", {HB_TAG('H','R','V',' ')}}, /* Croatian */ - {"hrm", {HB_TAG('H','M','N',' ')}}, /* Horned Miao -> Hmong */ - {"hsb", {HB_TAG('U','S','B',' ')}}, /* Upper Sorbian */ - {"hsn", {HB_TAG('Z','H','S',' ')}}, /* Xiang Chinese -> Chinese Simplified */ - {"ht", {HB_TAG('H','A','I',' ')}}, /* Haitian (Haitian Creole) */ - {"hu", {HB_TAG('H','U','N',' ')}}, /* Hungarian */ - {"huj", {HB_TAG('H','M','N',' ')}}, /* Northern Guiyang Hmong -> Hmong */ - {"hup", {HB_TAG('A','T','H',' ')}}, /* Hupa -> Athapaskan */ - {"hy", {HB_TAG('H','Y','E','0'), /* Armenian -> Armenian East */ - HB_TAG('H','Y','E',' ')}}, /* Armenian */ - {"hyw", {HB_TAG('H','Y','E',' ')}}, /* Western Armenian -> Armenian */ - {"hz", {HB_TAG('H','E','R',' ')}}, /* Herero */ - {"ia", {HB_TAG('I','N','A',' ')}}, /* Interlingua (International Auxiliary Language Association) */ - {"iba", {HB_TAG('I','B','A',' ')}}, /* Iban */ - {"ibb", {HB_TAG('I','B','B',' ')}}, /* Ibibio */ - {"id", {HB_TAG('I','N','D',' ')}}, /* Indonesian */ - {"ida", {HB_TAG('L','U','H',' ')}}, /* Idakho-Isukha-Tiriki -> Luyia */ - {"ie", {HB_TAG('I','L','E',' ')}}, /* Interlingue */ - {"ig", {HB_TAG('I','B','O',' ')}}, /* Igbo */ - {"igb", {HB_TAG('E','B','I',' ')}}, /* Ebira */ - {"ii", {HB_TAG('Y','I','M',' ')}}, /* Sichuan Yi -> Yi Modern */ - {"ijc", {HB_TAG('I','J','O',' ')}}, /* Izon -> Ijo */ - {"ijo", {HB_TAG('I','J','O',' ')}}, /* Ijo [family] */ - {"ik", {HB_TAG('I','P','K',' ')}}, /* Inupiaq [macrolanguage] -> Inupiat */ - {"ike", {HB_TAG('I','N','U',' ')}}, /* Eastern Canadian Inuktitut -> Inuktitut */ - {"ikt", {HB_TAG('I','N','U',' ')}}, /* Inuinnaqtun -> Inuktitut */ - {"ilo", {HB_TAG('I','L','O',' ')}}, /* Iloko -> Ilokano */ - {"in", {HB_TAG('I','N','D',' ')}}, /* Indonesian (retired code) */ - {"ing", {HB_TAG('A','T','H',' ')}}, /* Degexit'an -> Athapaskan */ - {"inh", {HB_TAG('I','N','G',' ')}}, /* Ingush */ - {"io", {HB_TAG('I','D','O',' ')}}, /* Ido */ - {"is", {HB_TAG('I','S','L',' ')}}, /* Icelandic */ - {"it", {HB_TAG('I','T','A',' ')}}, /* Italian */ - {"iu", {HB_TAG('I','N','U',' ')}}, /* Inuktitut [macrolanguage] */ - {"iw", {HB_TAG('I','W','R',' ')}}, /* Hebrew (retired code) */ - {"ja", {HB_TAG('J','A','N',' ')}}, /* Japanese */ - {"jak", {HB_TAG('M','L','Y',' ')}}, /* Jakun -> Malay */ - {"jam", {HB_TAG('J','A','M',' ')}}, /* Jamaican Creole English -> Jamaican Creole */ - {"jax", {HB_TAG('M','L','Y',' ')}}, /* Jambi Malay -> Malay */ - {"jbo", {HB_TAG('J','B','O',' ')}}, /* Lojban */ - {"jct", {HB_TAG('J','C','T',' ')}}, /* Krymchak */ - {"ji", {HB_TAG('J','I','I',' ')}}, /* Yiddish (retired code) */ - {"jv", {HB_TAG('J','A','V',' ')}}, /* Javanese */ - {"jw", {HB_TAG('J','A','V',' ')}}, /* Javanese (retired code) */ - {"ka", {HB_TAG('K','A','T',' ')}}, /* Georgian */ - {"kaa", {HB_TAG('K','R','K',' ')}}, /* Kara-Kalpak -> Karakalpak */ - {"kab", {HB_TAG('K','A','B','0')}}, /* Kabyle */ - {"kam", {HB_TAG('K','M','B',' ')}}, /* Kamba (Kenya) */ - {"kar", {HB_TAG('K','R','N',' ')}}, /* Karen [family] */ - {"kbd", {HB_TAG('K','A','B',' ')}}, /* Kabardian */ - {"kby", {HB_TAG('K','N','R',' ')}}, /* Manga Kanuri -> Kanuri */ - {"kca", {HB_TAG('K','H','K',' '), /* Khanty -> Khanty-Kazim */ - HB_TAG('K','H','S',' '), /* Khanty -> Khanty-Shurishkar */ - HB_TAG('K','H','V',' ')}}, /* Khanty -> Khanty-Vakhi */ - {"kde", {HB_TAG('K','D','E',' ')}}, /* Makonde */ - {"kdr", {HB_TAG('K','R','M',' ')}}, /* Karaim */ - {"kdt", {HB_TAG('K','U','Y',' ')}}, /* Kuy */ - {"kea", {HB_TAG('K','E','A',' ')}}, /* Kabuverdianu (Crioulo) */ - {"kek", {HB_TAG('K','E','K',' ')}}, /* Kekchi */ - {"kex", {HB_TAG('K','K','N',' ')}}, /* Kukna -> Kokni */ - {"kfa", {HB_TAG('K','O','D',' ')}}, /* Kodava -> Kodagu */ - {"kfr", {HB_TAG('K','A','C',' ')}}, /* Kachhi -> Kachchi */ - {"kfx", {HB_TAG('K','U','L',' ')}}, /* Kullu Pahari -> Kulvi */ - {"kfy", {HB_TAG('K','M','N',' ')}}, /* Kumaoni */ - {"kg", {HB_TAG('K','O','N','0')}}, /* Kongo [macrolanguage] */ - {"kha", {HB_TAG('K','S','I',' ')}}, /* Khasi */ - {"khb", {HB_TAG('X','B','D',' ')}}, /* Lü */ - {"khk", {HB_TAG('M','N','G',' ')}}, /* Halh Mongolian -> Mongolian */ - {"kht", {HB_TAG('K','H','N',' '), /* Khamti -> Khamti Shan (Microsoft fonts) */ - HB_TAG('K','H','T',' ')}}, /* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */ - {"khw", {HB_TAG('K','H','W',' ')}}, /* Khowar */ - {"ki", {HB_TAG('K','I','K',' ')}}, /* Kikuyu (Gikuyu) */ - {"kiu", {HB_TAG('K','I','U',' ')}}, /* Kirmanjki */ - {"kj", {HB_TAG('K','U','A',' ')}}, /* Kuanyama */ - {"kjd", {HB_TAG('K','J','D',' ')}}, /* Southern Kiwai */ - {"kjh", {HB_TAG('K','H','A',' ')}}, /* Khakas -> Khakass */ - {"kjp", {HB_TAG('K','J','P',' ')}}, /* Pwo Eastern Karen -> Eastern Pwo Karen */ - {"kjz", {HB_TAG('K','J','Z',' ')}}, /* Bumthangkha */ - {"kk", {HB_TAG('K','A','Z',' ')}}, /* Kazakh */ - {"kkz", {HB_TAG('A','T','H',' ')}}, /* Kaska -> Athapaskan */ - {"kl", {HB_TAG('G','R','N',' ')}}, /* Greenlandic */ - {"kln", {HB_TAG('K','A','L',' ')}}, /* Kalenjin [macrolanguage] */ - {"km", {HB_TAG('K','H','M',' ')}}, /* Khmer */ - {"kmb", {HB_TAG('M','B','N',' ')}}, /* Kimbundu -> Mbundu */ - {"kmr", {HB_TAG('K','U','R',' ')}}, /* Northern Kurdish -> Kurdish */ - {"kmw", {HB_TAG('K','M','O',' ')}}, /* Komo (Democratic Republic of Congo) */ - {"kmz", {HB_TAG('K','M','Z',' ')}}, /* Khorasani Turkish -> Khorasani Turkic */ - {"kn", {HB_TAG('K','A','N',' ')}}, /* Kannada */ - {"knc", {HB_TAG('K','N','R',' ')}}, /* Central Kanuri -> Kanuri */ - {"kng", {HB_TAG('K','O','N','0')}}, /* Koongo -> Kongo */ - {"knn", {HB_TAG('K','O','K',' ')}}, /* Konkani */ - {"ko", {HB_TAG('K','O','R',' ')}}, /* Korean */ - {"koi", {HB_TAG('K','O','P',' ')}}, /* Komi-Permyak */ - {"kok", {HB_TAG('K','O','K',' ')}}, /* Konkani [macrolanguage] */ - {"kos", {HB_TAG('K','O','S',' ')}}, /* Kosraean */ - {"koy", {HB_TAG('A','T','H',' ')}}, /* Koyukon -> Athapaskan */ - {"kpe", {HB_TAG('K','P','L',' ')}}, /* Kpelle [macrolanguage] */ - {"kpv", {HB_TAG('K','O','Z',' ')}}, /* Komi-Zyrian */ - {"kpy", {HB_TAG('K','Y','K',' ')}}, /* Koryak */ - {"kqs", {HB_TAG('K','I','S',' ')}}, /* Northern Kissi -> Kisii */ - {"kqy", {HB_TAG('K','R','T',' ')}}, /* Koorete */ - {"kr", {HB_TAG('K','N','R',' ')}}, /* Kanuri [macrolanguage] */ - {"krc", {HB_TAG('K','A','R',' '), /* Karachay-Balkar -> Karachay */ - HB_TAG('B','A','L',' ')}}, /* Karachay-Balkar -> Balkar */ - {"kri", {HB_TAG('K','R','I',' ')}}, /* Krio */ - {"krl", {HB_TAG('K','R','L',' ')}}, /* Karelian */ - {"krt", {HB_TAG('K','N','R',' ')}}, /* Tumari Kanuri -> Kanuri */ - {"kru", {HB_TAG('K','U','U',' ')}}, /* Kurukh */ - {"ks", {HB_TAG('K','S','H',' ')}}, /* Kashmiri */ - {"ksh", {HB_TAG('K','S','H','0')}}, /* Kölsch -> Ripuarian */ - {"kss", {HB_TAG('K','I','S',' ')}}, /* Southern Kisi -> Kisii */ - {"ksw", {HB_TAG('K','S','W',' ')}}, /* S’gaw Karen */ - {"ktb", {HB_TAG('K','E','B',' ')}}, /* Kambaata -> Kebena */ - {"ktu", {HB_TAG('K','O','N',' ')}}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ - {"ktw", {HB_TAG('A','T','H',' ')}}, /* Kato -> Athapaskan */ - {"ku", {HB_TAG('K','U','R',' ')}}, /* Kurdish [macrolanguage] */ - {"kum", {HB_TAG('K','U','M',' ')}}, /* Kumyk */ - {"kuu", {HB_TAG('A','T','H',' ')}}, /* Upper Kuskokwim -> Athapaskan */ - {"kv", {HB_TAG('K','O','M',' ')}}, /* Komi [macrolanguage] */ - {"kvb", {HB_TAG('M','L','Y',' ')}}, /* Kubu -> Malay */ - {"kvr", {HB_TAG('M','L','Y',' ')}}, /* Kerinci -> Malay */ - {"kw", {HB_TAG('C','O','R',' ')}}, /* Cornish */ - {"kwy", {HB_TAG('K','O','N','0')}}, /* San Salvador Kongo -> Kongo */ - {"kxc", {HB_TAG('K','M','S',' ')}}, /* Konso -> Komso */ - {"kxd", {HB_TAG('M','L','Y',' ')}}, /* Brunei -> Malay */ - {"kxu", {HB_TAG('K','U','I',' ')}}, /* Kui (India) */ - {"ky", {HB_TAG('K','I','R',' ')}}, /* Kirghiz (Kyrgyz) */ - {"kyu", {HB_TAG('K','Y','U',' ')}}, /* Western Kayah */ - {"la", {HB_TAG('L','A','T',' ')}}, /* Latin */ - {"lad", {HB_TAG('J','U','D',' ')}}, /* Ladino */ - {"lb", {HB_TAG('L','T','Z',' ')}}, /* Luxembourgish */ - {"lbe", {HB_TAG('L','A','K',' ')}}, /* Lak */ - {"lbj", {HB_TAG('L','D','K',' ')}}, /* Ladakhi */ - {"lbl", {HB_TAG('B','I','K',' ')}}, /* Libon Bikol -> Bikol */ - {"lce", {HB_TAG('M','L','Y',' ')}}, /* Loncong -> Malay */ - {"lcf", {HB_TAG('M','L','Y',' ')}}, /* Lubu -> Malay */ - {"ldi", {HB_TAG('K','O','N','0')}}, /* Laari -> Kongo */ - {"lez", {HB_TAG('L','E','Z',' ')}}, /* Lezghian -> Lezgi */ - {"lg", {HB_TAG('L','U','G',' ')}}, /* Ganda */ - {"li", {HB_TAG('L','I','M',' ')}}, /* Limburgish */ - {"lif", {HB_TAG('L','M','B',' ')}}, /* Limbu */ - {"lij", {HB_TAG('L','I','J',' ')}}, /* Ligurian */ - {"lis", {HB_TAG('L','I','S',' ')}}, /* Lisu */ - {"liw", {HB_TAG('M','L','Y',' ')}}, /* Col -> Malay */ - {"ljp", {HB_TAG('L','J','P',' ')}}, /* Lampung Api -> Lampung */ - {"lkb", {HB_TAG('L','U','H',' ')}}, /* Kabras -> Luyia */ - {"lki", {HB_TAG('L','K','I',' ')}}, /* Laki */ - {"lko", {HB_TAG('L','U','H',' ')}}, /* Khayo -> Luyia */ - {"lks", {HB_TAG('L','U','H',' ')}}, /* Kisa -> Luyia */ - {"lld", {HB_TAG('L','A','D',' ')}}, /* Ladin */ - {"lmn", {HB_TAG('L','A','M',' ')}}, /* Lambadi -> Lambani */ - {"lmo", {HB_TAG('L','M','O',' ')}}, /* Lombard */ - {"ln", {HB_TAG('L','I','N',' ')}}, /* Lingala */ - {"lo", {HB_TAG('L','A','O',' ')}}, /* Lao */ - {"lom", {HB_TAG('L','O','M',' ')}}, /* Loma (Liberia) */ - {"lrc", {HB_TAG('L','R','C',' ')}}, /* Northern Luri -> Luri */ - {"lri", {HB_TAG('L','U','H',' ')}}, /* Marachi -> Luyia */ - {"lrm", {HB_TAG('L','U','H',' ')}}, /* Marama -> Luyia */ - {"lsm", {HB_TAG('L','U','H',' ')}}, /* Saamia -> Luyia */ - {"lt", {HB_TAG('L','T','H',' ')}}, /* Lithuanian */ - {"ltg", {HB_TAG('L','V','I',' ')}}, /* Latgalian -> Latvian */ - {"lto", {HB_TAG('L','U','H',' ')}}, /* Tsotso -> Luyia */ - {"lts", {HB_TAG('L','U','H',' ')}}, /* Tachoni -> Luyia */ - {"lu", {HB_TAG('L','U','B',' ')}}, /* Luba-Katanga */ - {"lua", {HB_TAG('L','U','A',' ')}}, /* Luba-Lulua */ - {"luo", {HB_TAG('L','U','O',' ')}}, /* Luo (Kenya and Tanzania) */ - {"lus", {HB_TAG('M','I','Z',' ')}}, /* Lushai -> Mizo */ - {"luy", {HB_TAG('L','U','H',' ')}}, /* Luyia [macrolanguage] */ - {"luz", {HB_TAG('L','R','C',' ')}}, /* Southern Luri -> Luri */ - {"lv", {HB_TAG('L','V','I',' ')}}, /* Latvian [macrolanguage] */ - {"lvs", {HB_TAG('L','V','I',' ')}}, /* Standard Latvian -> Latvian */ - {"lwg", {HB_TAG('L','U','H',' ')}}, /* Wanga -> Luyia */ - {"lzh", {HB_TAG('Z','H','T',' ')}}, /* Literary Chinese -> Chinese Traditional */ - {"lzz", {HB_TAG('L','A','Z',' ')}}, /* Laz */ - {"mad", {HB_TAG('M','A','D',' ')}}, /* Madurese -> Madura */ - {"mag", {HB_TAG('M','A','G',' ')}}, /* Magahi */ - {"mai", {HB_TAG('M','T','H',' ')}}, /* Maithili */ - {"mak", {HB_TAG('M','K','R',' ')}}, /* Makasar */ - {"mam", {HB_TAG('M','A','M',' ')}}, /* Mam */ - {"man", {HB_TAG('M','N','K',' ')}}, /* Mandingo [macrolanguage] -> Maninka */ - {"max", {HB_TAG('M','L','Y',' ')}}, /* North Moluccan Malay -> Malay */ - {"mbo", {HB_TAG('M','B','O',' ')}}, /* Mbo (Cameroon) */ - {"mct", {HB_TAG('B','T','I',' ')}}, /* Mengisa -> Beti */ - {"mdf", {HB_TAG('M','O','K',' ')}}, /* Moksha */ - {"mdr", {HB_TAG('M','D','R',' ')}}, /* Mandar */ - {"mdy", {HB_TAG('M','L','E',' ')}}, /* Male (Ethiopia) */ - {"men", {HB_TAG('M','D','E',' ')}}, /* Mende (Sierra Leone) */ - {"meo", {HB_TAG('M','L','Y',' ')}}, /* Kedah Malay -> Malay */ - {"mer", {HB_TAG('M','E','R',' ')}}, /* Meru */ - {"mfa", {HB_TAG('M','F','A',' ')}}, /* Pattani Malay */ - {"mfb", {HB_TAG('M','L','Y',' ')}}, /* Bangka -> Malay */ - {"mfe", {HB_TAG('M','F','E',' ')}}, /* Morisyen */ - {"mg", {HB_TAG('M','L','G',' ')}}, /* Malagasy [macrolanguage] */ - {"mh", {HB_TAG('M','A','H',' ')}}, /* Marshallese */ - {"mhr", {HB_TAG('L','M','A',' ')}}, /* Eastern Mari -> Low Mari */ - {"mhv", {HB_TAG('A','R','K',' ')}}, /* Arakanese (retired code) -> Rakhine */ - {"mi", {HB_TAG('M','R','I',' ')}}, /* Maori */ - {"min", {HB_TAG('M','I','N',' ')}}, /* Minangkabau */ - {"mk", {HB_TAG('M','K','D',' ')}}, /* Macedonian */ - {"mku", {HB_TAG('M','N','K',' ')}}, /* Konyanka Maninka -> Maninka */ - {"mkw", {HB_TAG('M','K','W',' ')}}, /* Kituba (Congo) */ - {"ml", {HB_TAG('M','A','L',' '), /* Malayalam -> Malayalam Traditional */ - HB_TAG('M','L','R',' ')}}, /* Malayalam -> Malayalam Reformed */ - {"mlq", {HB_TAG('M','L','N',' '), /* Western Maninkakan -> Malinke */ - HB_TAG('M','N','K',' ')}}, /* Western Maninkakan -> Maninka */ - {"mmr", {HB_TAG('H','M','N',' ')}}, /* Western Xiangxi Miao -> Hmong */ - {"mn", {HB_TAG('M','N','G',' ')}}, /* Mongolian [macrolanguage] */ - {"mnc", {HB_TAG('M','C','H',' ')}}, /* Manchu */ - {"mni", {HB_TAG('M','N','I',' ')}}, /* Manipuri */ - {"mnk", {HB_TAG('M','N','D',' '), /* Mandinka */ - HB_TAG('M','N','K',' ')}}, /* Mandinka -> Maninka */ - {"mnp", {HB_TAG('Z','H','S',' ')}}, /* Min Bei Chinese -> Chinese Simplified */ - {"mns", {HB_TAG('M','A','N',' ')}}, /* Mansi */ - {"mnw", {HB_TAG('M','O','N',' ')}}, /* Mon */ - {"mo", {HB_TAG('M','O','L',' ')}}, /* Moldavian (retired code) */ - {"moh", {HB_TAG('M','O','H',' ')}}, /* Mohawk */ - {"mos", {HB_TAG('M','O','S',' ')}}, /* Mossi */ - {"mpe", {HB_TAG('M','A','J',' ')}}, /* Majang */ - {"mqg", {HB_TAG('M','L','Y',' ')}}, /* Kota Bangun Kutai Malay -> Malay */ - {"mr", {HB_TAG('M','A','R',' ')}}, /* Marathi */ - {"mrh", {HB_TAG('Q','I','N',' ')}}, /* Mara Chin -> Chin */ - {"mrj", {HB_TAG('H','M','A',' ')}}, /* Western Mari -> High Mari */ - {"ms", {HB_TAG('M','L','Y',' ')}}, /* Malay [macrolanguage] */ - {"msc", {HB_TAG('M','N','K',' ')}}, /* Sankaran Maninka -> Maninka */ - {"msh", {HB_TAG('M','L','G',' ')}}, /* Masikoro Malagasy -> Malagasy */ - {"msi", {HB_TAG('M','L','Y',' ')}}, /* Sabah Malay -> Malay */ - {"mt", {HB_TAG('M','T','S',' ')}}, /* Maltese */ - {"mtr", {HB_TAG('M','A','W',' ')}}, /* Mewari -> Marwari */ - {"mui", {HB_TAG('M','L','Y',' ')}}, /* Musi -> Malay */ - {"mup", {HB_TAG('R','A','J',' ')}}, /* Malvi -> Rajasthani */ - {"muq", {HB_TAG('H','M','N',' ')}}, /* Eastern Xiangxi Miao -> Hmong */ - {"mus", {HB_TAG('M','U','S',' ')}}, /* Creek -> Muscogee */ - {"mvb", {HB_TAG('A','T','H',' ')}}, /* Mattole -> Athapaskan */ - {"mve", {HB_TAG('M','A','W',' ')}}, /* Marwari (Pakistan) */ - {"mvf", {HB_TAG('M','N','G',' ')}}, /* Peripheral Mongolian -> Mongolian */ - {"mwk", {HB_TAG('M','N','K',' ')}}, /* Kita Maninkakan -> Maninka */ - {"mwl", {HB_TAG('M','W','L',' ')}}, /* Mirandese */ - {"mwr", {HB_TAG('M','A','W',' ')}}, /* Marwari [macrolanguage] */ - {"mww", {HB_TAG('M','W','W',' ')}}, /* Hmong Daw */ - {"my", {HB_TAG('B','R','M',' ')}}, /* Burmese */ - {"mym", {HB_TAG('M','E','N',' ')}}, /* Me'en */ - {"myn", {HB_TAG('M','Y','N',' ')}}, /* Mayan [family] */ - {"myq", {HB_TAG('M','N','K',' ')}}, /* Forest Maninka (retired code) -> Maninka */ - {"myv", {HB_TAG('E','R','Z',' ')}}, /* Erzya */ - {"mzn", {HB_TAG('M','Z','N',' ')}}, /* Mazanderani */ - {"na", {HB_TAG('N','A','U',' ')}}, /* Nauru -> Nauruan */ - {"nag", {HB_TAG('N','A','G',' ')}}, /* Naga Pidgin -> Naga-Assamese */ - {"nah", {HB_TAG('N','A','H',' ')}}, /* Nahuatl [family] */ - {"nan", {HB_TAG('Z','H','S',' ')}}, /* Min Nan Chinese -> Chinese Simplified */ - {"nap", {HB_TAG('N','A','P',' ')}}, /* Neapolitan */ - {"nb", {HB_TAG('N','O','R',' ')}}, /* Norwegian Bokmål -> Norwegian */ - {"nd", {HB_TAG('N','D','B',' ')}}, /* North Ndebele -> Ndebele */ - {"ndc", {HB_TAG('N','D','C',' ')}}, /* Ndau */ - {"nds", {HB_TAG('N','D','S',' ')}}, /* Low Saxon */ - {"ne", {HB_TAG('N','E','P',' ')}}, /* Nepali [macrolanguage] */ - {"new", {HB_TAG('N','E','W',' ')}}, /* Newari */ - {"ng", {HB_TAG('N','D','G',' ')}}, /* Ndonga */ - {"nga", {HB_TAG('N','G','A',' ')}}, /* Ngbaka */ - {"ngl", {HB_TAG('L','M','W',' ')}}, /* Lomwe */ - {"ngo", {HB_TAG('S','X','T',' ')}}, /* Ngoni -> Sutu */ - {"nhd", {HB_TAG('G','U','A',' ')}}, /* Chiripá -> Guarani */ - {"niq", {HB_TAG('K','A','L',' ')}}, /* Nandi -> Kalenjin */ - {"niu", {HB_TAG('N','I','U',' ')}}, /* Niuean */ - {"niv", {HB_TAG('G','I','L',' ')}}, /* Gilyak */ - {"njz", {HB_TAG('N','I','S',' ')}}, /* Nyishi -> Nisi */ - {"nl", {HB_TAG('N','L','D',' ')}}, /* Dutch */ - {"nle", {HB_TAG('L','U','H',' ')}}, /* East Nyala -> Luyia */ - {"nn", {HB_TAG('N','Y','N',' ')}}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ - {"no", {HB_TAG('N','O','R',' ')}}, /* Norwegian [macrolanguage] */ - {"nod", {HB_TAG('N','T','A',' ')}}, /* Northern Thai -> Northern Tai */ - {"noe", {HB_TAG('N','O','E',' ')}}, /* Nimadi */ - {"nog", {HB_TAG('N','O','G',' ')}}, /* Nogai */ - {"nov", {HB_TAG('N','O','V',' ')}}, /* Novial */ - {"npi", {HB_TAG('N','E','P',' ')}}, /* Nepali */ - {"nqo", {HB_TAG('N','K','O',' ')}}, /* N'Ko */ - {"nr", {HB_TAG('N','D','B',' ')}}, /* South Ndebele -> Ndebele */ - {"nsk", {HB_TAG('N','A','S',' ')}}, /* Naskapi */ - {"nso", {HB_TAG('N','S','O',' ')}}, /* Pedi -> Sotho, Northern */ - {"nv", {HB_TAG('N','A','V',' '), /* Navajo */ - HB_TAG('A','T','H',' ')}}, /* Navajo -> Athapaskan */ - {"ny", {HB_TAG('C','H','I',' ')}}, /* Chichewa (Chewa, Nyanja) */ - {"nyd", {HB_TAG('L','U','H',' ')}}, /* Nyore -> Luyia */ - {"nym", {HB_TAG('N','Y','M',' ')}}, /* Nyamwezi */ - {"nyn", {HB_TAG('N','K','L',' ')}}, /* Nyankole */ - {"nza", {HB_TAG('N','Z','A',' ')}}, /* Tigon Mbembe -> Mbembe Tigon */ - {"oc", {HB_TAG('O','C','I',' ')}}, /* Occitan (post 1500) */ - {"oj", {HB_TAG('O','J','B',' ')}}, /* Ojibwa [macrolanguage] -> Ojibway */ - {"ojb", {HB_TAG('O','J','B',' ')}}, /* Northwestern Ojibwa -> Ojibway */ - {"ojc", {HB_TAG('O','J','B',' ')}}, /* Central Ojibwa -> Ojibway */ - {"ojg", {HB_TAG('O','J','B',' ')}}, /* Eastern Ojibwa -> Ojibway */ - {"ojs", {HB_TAG('O','C','R',' ')}}, /* Severn Ojibwa -> Oji-Cree */ - {"ojw", {HB_TAG('O','J','B',' ')}}, /* Western Ojibwa -> Ojibway */ - {"oki", {HB_TAG('K','A','L',' ')}}, /* Okiek -> Kalenjin */ - {"okm", {HB_TAG('K','O','H',' ')}}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ - {"om", {HB_TAG('O','R','O',' ')}}, /* Oromo [macrolanguage] */ - {"or", {HB_TAG('O','R','I',' ')}}, /* Odia (formerly Oriya) [macrolanguage] */ - {"orc", {HB_TAG('O','R','O',' ')}}, /* Orma -> Oromo */ - {"orn", {HB_TAG('M','L','Y',' ')}}, /* Orang Kanaq -> Malay */ - {"ors", {HB_TAG('M','L','Y',' ')}}, /* Orang Seletar -> Malay */ - {"ory", {HB_TAG('O','R','I',' ')}}, /* Odia (formerly Oriya) */ - {"os", {HB_TAG('O','S','S',' ')}}, /* Ossetian */ - {"otw", {HB_TAG('O','J','B',' ')}}, /* Ottawa -> Ojibway */ - {"pa", {HB_TAG('P','A','N',' ')}}, /* Punjabi */ - {"pag", {HB_TAG('P','A','G',' ')}}, /* Pangasinan */ - {"pam", {HB_TAG('P','A','M',' ')}}, /* Pampanga -> Pampangan */ - {"pap", {HB_TAG('P','A','P','0')}}, /* Papiamento -> Papiamentu */ - {"pau", {HB_TAG('P','A','U',' ')}}, /* Palauan */ - {"pbt", {HB_TAG('P','A','S',' ')}}, /* Southern Pashto -> Pashto */ - {"pbu", {HB_TAG('P','A','S',' ')}}, /* Northern Pashto -> Pashto */ - {"pcc", {HB_TAG('P','C','C',' ')}}, /* Bouyei */ - {"pcd", {HB_TAG('P','C','D',' ')}}, /* Picard */ - {"pce", {HB_TAG('P','L','G',' ')}}, /* Ruching Palaung -> Palaung */ - {"pck", {HB_TAG('Q','I','N',' ')}}, /* Paite Chin -> Chin */ - {"pdc", {HB_TAG('P','D','C',' ')}}, /* Pennsylvania German */ - {"pel", {HB_TAG('M','L','Y',' ')}}, /* Pekal -> Malay */ - {"pes", {HB_TAG('F','A','R',' ')}}, /* Iranian Persian -> Persian */ - {"pga", {HB_TAG('A','R','A',' ')}}, /* Sudanese Creole Arabic -> Arabic */ - {"phk", {HB_TAG('P','H','K',' ')}}, /* Phake */ - {"pi", {HB_TAG('P','A','L',' ')}}, /* Pali */ - {"pih", {HB_TAG('P','I','H',' ')}}, /* Pitcairn-Norfolk -> Norfolk */ - {"pko", {HB_TAG('K','A','L',' ')}}, /* Pökoot -> Kalenjin */ - {"pl", {HB_TAG('P','L','K',' ')}}, /* Polish */ - {"pll", {HB_TAG('P','L','G',' ')}}, /* Shwe Palaung -> Palaung */ - {"plp", {HB_TAG('P','A','P',' ')}}, /* Palpa */ - {"plt", {HB_TAG('M','L','G',' ')}}, /* Plateau Malagasy -> Malagasy */ - {"pms", {HB_TAG('P','M','S',' ')}}, /* Piemontese */ - {"pnb", {HB_TAG('P','N','B',' ')}}, /* Western Panjabi */ - {"poh", {HB_TAG('P','O','H',' ')}}, /* Poqomchi' -> Pocomchi */ - {"pon", {HB_TAG('P','O','N',' ')}}, /* Pohnpeian */ - {"ppa", {HB_TAG('B','A','G',' ')}}, /* Pao (retired code) -> Baghelkhandi */ - {"pro", {HB_TAG('P','R','O',' ')}}, /* Old Provençal (to 1500) -> Provençal / Old Provençal */ - {"prs", {HB_TAG('D','R','I',' ')}}, /* Dari */ - {"ps", {HB_TAG('P','A','S',' ')}}, /* Pashto [macrolanguage] */ - {"pse", {HB_TAG('M','L','Y',' ')}}, /* Central Malay -> Malay */ - {"pst", {HB_TAG('P','A','S',' ')}}, /* Central Pashto -> Pashto */ - {"pt", {HB_TAG('P','T','G',' ')}}, /* Portuguese */ - {"pwo", {HB_TAG('P','W','O',' ')}}, /* Pwo Western Karen -> Western Pwo Karen */ - {"qu", {HB_TAG('Q','U','Z',' ')}}, /* Quechua [macrolanguage] */ - {"qub", {HB_TAG('Q','W','H',' ')}}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ - {"quc", {HB_TAG('Q','U','C',' ')}}, /* K’iche’ */ - {"qud", {HB_TAG('Q','V','I',' ')}}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ - {"quf", {HB_TAG('Q','U','Z',' ')}}, /* Lambayeque Quechua -> Quechua */ - {"qug", {HB_TAG('Q','V','I',' ')}}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ - {"quh", {HB_TAG('Q','U','H',' ')}}, /* South Bolivian Quechua -> Quechua (Bolivia) */ - {"quk", {HB_TAG('Q','U','Z',' ')}}, /* Chachapoyas Quechua -> Quechua */ - {"qul", {HB_TAG('Q','U','Z',' ')}}, /* North Bolivian Quechua -> Quechua */ - {"qup", {HB_TAG('Q','V','I',' ')}}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ - {"qur", {HB_TAG('Q','W','H',' ')}}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ - {"qus", {HB_TAG('Q','U','H',' ')}}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ - {"quw", {HB_TAG('Q','V','I',' ')}}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ - {"qux", {HB_TAG('Q','W','H',' ')}}, /* Yauyos Quechua -> Quechua (Peru) */ - {"quy", {HB_TAG('Q','U','Z',' ')}}, /* Ayacucho Quechua -> Quechua */ - {"quz", {HB_TAG('Q','U','Z',' ')}}, /* Cusco Quechua -> Quechua */ - {"qva", {HB_TAG('Q','W','H',' ')}}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ - {"qvc", {HB_TAG('Q','U','Z',' ')}}, /* Cajamarca Quechua -> Quechua */ - {"qve", {HB_TAG('Q','U','Z',' ')}}, /* Eastern Apurímac Quechua -> Quechua */ - {"qvh", {HB_TAG('Q','W','H',' ')}}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ - {"qvi", {HB_TAG('Q','V','I',' ')}}, /* Imbabura Highland Quichua -> Quechua (Ecuador) */ - {"qvj", {HB_TAG('Q','V','I',' ')}}, /* Loja Highland Quichua -> Quechua (Ecuador) */ - {"qvl", {HB_TAG('Q','W','H',' ')}}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ - {"qvm", {HB_TAG('Q','W','H',' ')}}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ - {"qvn", {HB_TAG('Q','W','H',' ')}}, /* North Junín Quechua -> Quechua (Peru) */ - {"qvo", {HB_TAG('Q','V','I',' ')}}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ - {"qvp", {HB_TAG('Q','W','H',' ')}}, /* Pacaraos Quechua -> Quechua (Peru) */ - {"qvs", {HB_TAG('Q','U','Z',' ')}}, /* San Martín Quechua -> Quechua */ - {"qvw", {HB_TAG('Q','W','H',' ')}}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ - {"qvz", {HB_TAG('Q','V','I',' ')}}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ - {"qwa", {HB_TAG('Q','W','H',' ')}}, /* Corongo Ancash Quechua -> Quechua (Peru) */ - {"qwc", {HB_TAG('Q','U','Z',' ')}}, /* Classical Quechua -> Quechua */ - {"qwh", {HB_TAG('Q','W','H',' ')}}, /* Huaylas Ancash Quechua -> Quechua (Peru) */ - {"qws", {HB_TAG('Q','W','H',' ')}}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ - {"qxa", {HB_TAG('Q','W','H',' ')}}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ - {"qxc", {HB_TAG('Q','W','H',' ')}}, /* Chincha Quechua -> Quechua (Peru) */ - {"qxh", {HB_TAG('Q','W','H',' ')}}, /* Panao Huánuco Quechua -> Quechua (Peru) */ - {"qxl", {HB_TAG('Q','V','I',' ')}}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ - {"qxn", {HB_TAG('Q','W','H',' ')}}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ - {"qxo", {HB_TAG('Q','W','H',' ')}}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ - {"qxp", {HB_TAG('Q','U','Z',' ')}}, /* Puno Quechua -> Quechua */ - {"qxr", {HB_TAG('Q','V','I',' ')}}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ - {"qxt", {HB_TAG('Q','W','H',' ')}}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ - {"qxu", {HB_TAG('Q','U','Z',' ')}}, /* Arequipa-La Unión Quechua -> Quechua */ - {"qxw", {HB_TAG('Q','W','H',' ')}}, /* Jauja Wanca Quechua -> Quechua (Peru) */ - {"rag", {HB_TAG('L','U','H',' ')}}, /* Logooli -> Luyia */ - {"raj", {HB_TAG('R','A','J',' ')}}, /* Rajasthani [macrolanguage] */ - {"rar", {HB_TAG('R','A','R',' ')}}, /* Rarotongan */ - {"rbb", {HB_TAG('P','L','G',' ')}}, /* Rumai Palaung -> Palaung */ - {"rbl", {HB_TAG('B','I','K',' ')}}, /* Miraya Bikol -> Bikol */ - {"rej", {HB_TAG('R','E','J',' ')}}, /* Rejang */ - {"ria", {HB_TAG('R','I','A',' ')}}, /* Riang (India) */ - {"rif", {HB_TAG('R','I','F',' ')}}, /* Tarifit */ - {"rit", {HB_TAG('R','I','T',' ')}}, /* Ritarungo */ - {"rki", {HB_TAG('A','R','K',' ')}}, /* Rakhine */ - {"rkw", {HB_TAG('R','K','W',' ')}}, /* Arakwal */ - {"rm", {HB_TAG('R','M','S',' ')}}, /* Romansh */ - {"rmc", {HB_TAG('R','O','Y',' ')}}, /* Carpathian Romani -> Romany */ - {"rmf", {HB_TAG('R','O','Y',' ')}}, /* Kalo Finnish Romani -> Romany */ - {"rml", {HB_TAG('R','O','Y',' ')}}, /* Baltic Romani -> Romany */ - {"rmn", {HB_TAG('R','O','Y',' ')}}, /* Balkan Romani -> Romany */ - {"rmo", {HB_TAG('R','O','Y',' ')}}, /* Sinte Romani -> Romany */ - {"rmw", {HB_TAG('R','O','Y',' ')}}, /* Welsh Romani -> Romany */ - {"rmy", {HB_TAG('R','M','Y',' ')}}, /* Vlax Romani */ - {"rmz", {HB_TAG('A','R','K',' ')}}, /* Marma -> Rakhine */ - {"rn", {HB_TAG('R','U','N',' ')}}, /* Rundi */ - {"rnl", {HB_TAG('H','A','L',' ')}}, /* Ranglong -> Halam (Falam Chin) */ - {"ro", {HB_TAG('R','O','M',' ')}}, /* Romanian */ - {"rom", {HB_TAG('R','O','Y',' ')}}, /* Romany [macrolanguage] */ - {"rtm", {HB_TAG('R','T','M',' ')}}, /* Rotuman */ - {"ru", {HB_TAG('R','U','S',' ')}}, /* Russian */ - {"rue", {HB_TAG('R','S','Y',' ')}}, /* Rusyn */ - {"rup", {HB_TAG('R','U','P',' ')}}, /* Aromanian */ - {"rw", {HB_TAG('R','U','A',' ')}}, /* Kinyarwanda */ - {"rwr", {HB_TAG('M','A','W',' ')}}, /* Marwari (India) */ - {"sa", {HB_TAG('S','A','N',' ')}}, /* Sanskrit */ - {"sah", {HB_TAG('Y','A','K',' ')}}, /* Yakut -> Sakha */ - {"sam", {HB_TAG('P','A','A',' ')}}, /* Samaritan Aramaic -> Palestinian Aramaic */ - {"sas", {HB_TAG('S','A','S',' ')}}, /* Sasak */ - {"sat", {HB_TAG('S','A','T',' ')}}, /* Santali */ - {"sc", {HB_TAG('S','R','D',' ')}}, /* Sardinian [macrolanguage] */ - {"sck", {HB_TAG('S','A','D',' ')}}, /* Sadri */ - {"scn", {HB_TAG('S','C','N',' ')}}, /* Sicilian */ - {"sco", {HB_TAG('S','C','O',' ')}}, /* Scots */ - {"scs", {HB_TAG('S','C','S',' '), /* North Slavey */ - HB_TAG('S','L','A',' '), /* North Slavey -> Slavey */ - HB_TAG('A','T','H',' ')}}, /* North Slavey -> Athapaskan */ - {"sd", {HB_TAG('S','N','D',' ')}}, /* Sindhi */ - {"sdc", {HB_TAG('S','R','D',' ')}}, /* Sassarese Sardinian -> Sardinian */ - {"sdh", {HB_TAG('K','U','R',' ')}}, /* Southern Kurdish -> Kurdish */ - {"sdn", {HB_TAG('S','R','D',' ')}}, /* Gallurese Sardinian -> Sardinian */ - {"se", {HB_TAG('N','S','M',' ')}}, /* Northern Sami */ - {"seh", {HB_TAG('S','N','A',' ')}}, /* Sena */ - {"sek", {HB_TAG('A','T','H',' ')}}, /* Sekani -> Athapaskan */ - {"sel", {HB_TAG('S','E','L',' ')}}, /* Selkup */ - {"sez", {HB_TAG('Q','I','N',' ')}}, /* Senthang Chin -> Chin */ - {"sfm", {HB_TAG('H','M','N',' ')}}, /* Small Flowery Miao -> Hmong */ - {"sg", {HB_TAG('S','G','O',' ')}}, /* Sango */ - {"sga", {HB_TAG('S','G','A',' ')}}, /* Old Irish (to 900) */ - {"sgc", {HB_TAG('K','A','L',' ')}}, /* Kipsigis -> Kalenjin */ - {"sgs", {HB_TAG('S','G','S',' ')}}, /* Samogitian */ - {"sgw", {HB_TAG('C','H','G',' '), /* Sebat Bet Gurage -> Chaha Gurage */ - HB_TAG('S','G','W',' ')}}, /* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */ - {"shi", {HB_TAG('S','H','I',' ')}}, /* Tachelhit */ - {"shn", {HB_TAG('S','H','N',' ')}}, /* Shan */ - {"shu", {HB_TAG('A','R','A',' ')}}, /* Chadian Arabic -> Arabic */ - {"si", {HB_TAG('S','N','H',' ')}}, /* Sinhala (Sinhalese) */ - {"sid", {HB_TAG('S','I','D',' ')}}, /* Sidamo */ - {"sjd", {HB_TAG('K','S','M',' ')}}, /* Kildin Sami */ - {"sjo", {HB_TAG('S','I','B',' ')}}, /* Xibe -> Sibe */ - {"sk", {HB_TAG('S','K','Y',' ')}}, /* Slovak */ - {"skg", {HB_TAG('M','L','G',' ')}}, /* Sakalava Malagasy -> Malagasy */ - {"skr", {HB_TAG('S','R','K',' ')}}, /* Saraiki */ - {"sl", {HB_TAG('S','L','V',' ')}}, /* Slovenian */ - {"sm", {HB_TAG('S','M','O',' ')}}, /* Samoan */ - {"sma", {HB_TAG('S','S','M',' ')}}, /* Southern Sami */ - {"smj", {HB_TAG('L','S','M',' ')}}, /* Lule Sami */ - {"smn", {HB_TAG('I','S','M',' ')}}, /* Inari Sami */ - {"sms", {HB_TAG('S','K','S',' ')}}, /* Skolt Sami */ - {"sn", {HB_TAG('S','N','A','0')}}, /* Shona */ - {"snk", {HB_TAG('S','N','K',' ')}}, /* Soninke */ - {"so", {HB_TAG('S','M','L',' ')}}, /* Somali */ - {"sop", {HB_TAG('S','O','P',' ')}}, /* Songe */ - {"spv", {HB_TAG('O','R','I',' ')}}, /* Sambalpuri -> Odia (formerly Oriya) */ - {"spy", {HB_TAG('K','A','L',' ')}}, /* Sabaot -> Kalenjin */ - {"sq", {HB_TAG('S','Q','I',' ')}}, /* Albanian [macrolanguage] */ - {"sr", {HB_TAG('S','R','B',' ')}}, /* Serbian */ - {"src", {HB_TAG('S','R','D',' ')}}, /* Logudorese Sardinian -> Sardinian */ - {"sro", {HB_TAG('S','R','D',' ')}}, /* Campidanese Sardinian -> Sardinian */ - {"srr", {HB_TAG('S','R','R',' ')}}, /* Serer */ - {"srs", {HB_TAG('A','T','H',' ')}}, /* Sarsi -> Athapaskan */ - {"ss", {HB_TAG('S','W','Z',' ')}}, /* Swati */ - {"ssh", {HB_TAG('A','R','A',' ')}}, /* Shihhi Arabic -> Arabic */ - {"st", {HB_TAG('S','O','T',' ')}}, /* Southern Sotho -> Sotho, Southern */ - {"stq", {HB_TAG('S','T','Q',' ')}}, /* Saterfriesisch -> Saterland Frisian */ - {"stv", {HB_TAG('S','I','G',' ')}}, /* Silt'e -> Silte Gurage */ - {"su", {HB_TAG('S','U','N',' ')}}, /* Sundanese */ - {"suk", {HB_TAG('S','U','K',' ')}}, /* Sukuma */ - {"suq", {HB_TAG('S','U','R',' ')}}, /* Suri */ - {"sv", {HB_TAG('S','V','E',' ')}}, /* Swedish */ - {"sva", {HB_TAG('S','V','A',' ')}}, /* Svan */ - {"sw", {HB_TAG('S','W','K',' ')}}, /* Swahili [macrolanguage] */ - {"swb", {HB_TAG('C','M','R',' ')}}, /* Maore Comorian -> Comorian */ - {"swc", {HB_TAG('S','W','K',' ')}}, /* Congo Swahili -> Swahili */ - {"swh", {HB_TAG('S','W','K',' ')}}, /* Swahili */ - {"swv", {HB_TAG('M','A','W',' ')}}, /* Shekhawati -> Marwari */ - {"sxu", {HB_TAG('S','X','U',' ')}}, /* Upper Saxon */ - {"syc", {HB_TAG('S','Y','R',' ')}}, /* Classical Syriac -> Syriac */ - {"syl", {HB_TAG('S','Y','L',' ')}}, /* Sylheti */ - {"syr", {HB_TAG('S','Y','R',' ')}}, /* Syriac [macrolanguage] */ - {"szl", {HB_TAG('S','Z','L',' ')}}, /* Silesian */ - {"ta", {HB_TAG('T','A','M',' ')}}, /* Tamil */ - {"taa", {HB_TAG('A','T','H',' ')}}, /* Lower Tanana -> Athapaskan */ - {"tab", {HB_TAG('T','A','B',' ')}}, /* Tabassaran -> Tabasaran */ - {"taq", {HB_TAG('T','M','H',' ')}}, /* Tamasheq -> Tamashek */ - {"tau", {HB_TAG('A','T','H',' ')}}, /* Upper Tanana -> Athapaskan */ - {"tcb", {HB_TAG('A','T','H',' ')}}, /* Tanacross -> Athapaskan */ - {"tce", {HB_TAG('A','T','H',' ')}}, /* Southern Tutchone -> Athapaskan */ - {"tcp", {HB_TAG('Q','I','N',' ')}}, /* Tawr Chin -> Chin */ - {"tcy", {HB_TAG('T','U','L',' ')}}, /* Tulu -> Tumbuka */ - {"tcz", {HB_TAG('Q','I','N',' ')}}, /* Thado Chin -> Chin */ - {"tdd", {HB_TAG('T','D','D',' ')}}, /* Tai Nüa -> Dehong Dai */ - {"tdx", {HB_TAG('M','L','G',' ')}}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ - {"te", {HB_TAG('T','E','L',' ')}}, /* Telugu */ - {"tec", {HB_TAG('K','A','L',' ')}}, /* Terik -> Kalenjin */ - {"tem", {HB_TAG('T','M','N',' ')}}, /* Timne -> Temne */ - {"tet", {HB_TAG('T','E','T',' ')}}, /* Tetum */ - {"tfn", {HB_TAG('A','T','H',' ')}}, /* Tanaina -> Athapaskan */ - {"tg", {HB_TAG('T','A','J',' ')}}, /* Tajik -> Tajiki */ - {"tgj", {HB_TAG('N','I','S',' ')}}, /* Tagin -> Nisi */ - {"tgx", {HB_TAG('A','T','H',' ')}}, /* Tagish -> Athapaskan */ - {"th", {HB_TAG('T','H','A',' ')}}, /* Thai */ - {"tht", {HB_TAG('A','T','H',' ')}}, /* Tahltan -> Athapaskan */ - {"thv", {HB_TAG('T','M','H',' ')}}, /* Tahaggart Tamahaq -> Tamashek */ - {"thz", {HB_TAG('T','M','H',' ')}}, /* Tayart Tamajeq -> Tamashek */ - {"ti", {HB_TAG('T','G','Y',' ')}}, /* Tigrinya */ - {"tig", {HB_TAG('T','G','R',' ')}}, /* Tigre */ - {"tiv", {HB_TAG('T','I','V',' ')}}, /* Tiv */ - {"tk", {HB_TAG('T','K','M',' ')}}, /* Turkmen */ - {"tkg", {HB_TAG('M','L','G',' ')}}, /* Tesaka Malagasy -> Malagasy */ - {"tl", {HB_TAG('T','G','L',' ')}}, /* Tagalog */ - {"tmh", {HB_TAG('T','M','H',' ')}}, /* Tamashek [macrolanguage] */ - {"tmw", {HB_TAG('M','L','Y',' ')}}, /* Temuan -> Malay */ - {"tn", {HB_TAG('T','N','A',' ')}}, /* Tswana */ - {"tnf", {HB_TAG('D','R','I',' ')}}, /* Tangshewi (retired code) -> Dari */ - {"to", {HB_TAG('T','G','N',' ')}}, /* Tonga (Tonga Islands) -> Tongan */ - {"tod", {HB_TAG('T','O','D','0')}}, /* Toma */ - {"toi", {HB_TAG('T','N','G',' ')}}, /* Tonga (Zambia) */ - {"tol", {HB_TAG('A','T','H',' ')}}, /* Tolowa -> Athapaskan */ - {"tpi", {HB_TAG('T','P','I',' ')}}, /* Tok Pisin */ - {"tr", {HB_TAG('T','R','K',' ')}}, /* Turkish */ - {"tru", {HB_TAG('T','U','A',' '), /* Turoyo -> Turoyo Aramaic */ - HB_TAG('S','Y','R',' ')}}, /* Turoyo -> Syriac */ - {"ts", {HB_TAG('T','S','G',' ')}}, /* Tsonga */ - {"tsj", {HB_TAG('T','S','J',' ')}}, /* Tshangla */ - {"tt", {HB_TAG('T','A','T',' ')}}, /* Tatar */ - {"ttm", {HB_TAG('A','T','H',' ')}}, /* Northern Tutchone -> Athapaskan */ - {"ttq", {HB_TAG('T','M','H',' ')}}, /* Tawallammat Tamajaq -> Tamashek */ - {"tum", {HB_TAG('T','U','M',' ')}}, /* Tumbuka -> Tulu */ - {"tuu", {HB_TAG('A','T','H',' ')}}, /* Tututni -> Athapaskan */ - {"tuy", {HB_TAG('K','A','L',' ')}}, /* Tugen -> Kalenjin */ - {"tvl", {HB_TAG('T','V','L',' ')}}, /* Tuvalu */ - {"tw", {HB_TAG('T','W','I',' '), /* Twi */ - HB_TAG('A','K','A',' ')}}, /* Twi -> Akan */ - {"txc", {HB_TAG('A','T','H',' ')}}, /* Tsetsaut -> Athapaskan */ - {"txy", {HB_TAG('M','L','G',' ')}}, /* Tanosy Malagasy -> Malagasy */ - {"ty", {HB_TAG('T','H','T',' ')}}, /* Tahitian */ - {"tyv", {HB_TAG('T','U','V',' ')}}, /* Tuvinian -> Tuvin */ - {"tyz", {HB_TAG('T','Y','Z',' ')}}, /* Tày */ - {"tzm", {HB_TAG('T','Z','M',' ')}}, /* Central Atlas Tamazight -> Tamazight */ - {"tzo", {HB_TAG('T','Z','O',' ')}}, /* Tzotzil */ - {"ubl", {HB_TAG('B','I','K',' ')}}, /* Buhi'non Bikol -> Bikol */ - {"udm", {HB_TAG('U','D','M',' ')}}, /* Udmurt */ - {"ug", {HB_TAG('U','Y','G',' ')}}, /* Uyghur */ - {"uk", {HB_TAG('U','K','R',' ')}}, /* Ukrainian */ - {"umb", {HB_TAG('U','M','B',' ')}}, /* Umbundu */ - {"unr", {HB_TAG('M','U','N',' ')}}, /* Mundari */ - {"ur", {HB_TAG('U','R','D',' ')}}, /* Urdu */ - {"urk", {HB_TAG('M','L','Y',' ')}}, /* Urak Lawoi' -> Malay */ - {"uz", {HB_TAG('U','Z','B',' ')}}, /* Uzbek [macrolanguage] */ - {"uzn", {HB_TAG('U','Z','B',' ')}}, /* Northern Uzbek -> Uzbek */ - {"uzs", {HB_TAG('U','Z','B',' ')}}, /* Southern Uzbek -> Uzbek */ - {"ve", {HB_TAG('V','E','N',' ')}}, /* Venda */ - {"vec", {HB_TAG('V','E','C',' ')}}, /* Venetian */ - {"vi", {HB_TAG('V','I','T',' ')}}, /* Vietnamese */ - {"vkk", {HB_TAG('M','L','Y',' ')}}, /* Kaur -> Malay */ - {"vkt", {HB_TAG('M','L','Y',' ')}}, /* Tenggarong Kutai Malay -> Malay */ - {"vls", {HB_TAG('F','L','E',' ')}}, /* Vlaams -> Dutch (Flemish) */ - {"vmw", {HB_TAG('M','A','K',' ')}}, /* Makhuwa */ - {"vo", {HB_TAG('V','O','L',' ')}}, /* Volapük */ - {"vro", {HB_TAG('V','R','O',' ')}}, /* Võro */ - {"wa", {HB_TAG('W','L','N',' ')}}, /* Walloon */ - {"war", {HB_TAG('W','A','R',' ')}}, /* Waray (Philippines) -> Waray-Waray */ - {"wbm", {HB_TAG('W','A',' ',' ')}}, /* Wa */ - {"wbr", {HB_TAG('W','A','G',' ')}}, /* Wagdi */ - {"wlc", {HB_TAG('C','M','R',' ')}}, /* Mwali Comorian -> Comorian */ - {"wle", {HB_TAG('S','I','G',' ')}}, /* Wolane -> Silte Gurage */ - {"wlk", {HB_TAG('A','T','H',' ')}}, /* Wailaki -> Athapaskan */ - {"wni", {HB_TAG('C','M','R',' ')}}, /* Ndzwani Comorian -> Comorian */ - {"wo", {HB_TAG('W','L','F',' ')}}, /* Wolof */ - {"wry", {HB_TAG('M','A','W',' ')}}, /* Merwari -> Marwari */ - {"wsg", {HB_TAG('G','O','N',' ')}}, /* Adilabad Gondi -> Gondi */ - {"wtm", {HB_TAG('W','T','M',' ')}}, /* Mewati */ - {"wuu", {HB_TAG('Z','H','S',' ')}}, /* Wu Chinese -> Chinese Simplified */ - {"xal", {HB_TAG('K','L','M',' '), /* Kalmyk */ - HB_TAG('T','O','D',' ')}}, /* Kalmyk -> Todo */ - {"xan", {HB_TAG('S','E','K',' ')}}, /* Xamtanga -> Sekota */ - {"xh", {HB_TAG('X','H','S',' ')}}, /* Xhosa */ - {"xjb", {HB_TAG('X','J','B',' ')}}, /* Minjungbal -> Minjangbal */ - {"xkf", {HB_TAG('X','K','F',' ')}}, /* Khengkha */ - {"xmm", {HB_TAG('M','L','Y',' ')}}, /* Manado Malay -> Malay */ - {"xmv", {HB_TAG('M','L','G',' ')}}, /* Antankarana Malagasy -> Malagasy */ - {"xmw", {HB_TAG('M','L','G',' ')}}, /* Tsimihety Malagasy -> Malagasy */ - {"xnr", {HB_TAG('D','G','R',' ')}}, /* Kangri -> Dogri */ - {"xog", {HB_TAG('X','O','G',' ')}}, /* Soga */ - {"xpe", {HB_TAG('X','P','E',' ')}}, /* Liberia Kpelle -> Kpelle (Liberia) */ - {"xsl", {HB_TAG('S','S','L',' '), /* South Slavey */ - HB_TAG('S','L','A',' '), /* South Slavey -> Slavey */ - HB_TAG('A','T','H',' ')}}, /* South Slavey -> Athapaskan */ - {"xst", {HB_TAG('S','I','G',' ')}}, /* Silt'e (retired code) -> Silte Gurage */ - {"xwo", {HB_TAG('T','O','D',' ')}}, /* Written Oirat -> Todo */ - {"yao", {HB_TAG('Y','A','O',' ')}}, /* Yao */ - {"yap", {HB_TAG('Y','A','P',' ')}}, /* Yapese */ - {"ybd", {HB_TAG('A','R','K',' ')}}, /* Yangbye (retired code) -> Rakhine */ - {"ydd", {HB_TAG('J','I','I',' ')}}, /* Eastern Yiddish -> Yiddish */ - {"yi", {HB_TAG('J','I','I',' ')}}, /* Yiddish [macrolanguage] */ - {"yih", {HB_TAG('J','I','I',' ')}}, /* Western Yiddish -> Yiddish */ - {"yo", {HB_TAG('Y','B','A',' ')}}, /* Yoruba */ - {"yos", {HB_TAG('Q','I','N',' ')}}, /* Yos (retired code) -> Chin */ - {"yrk", {HB_TAG('T','N','E',' '), /* Nenets -> Tundra Nenets */ - HB_TAG('F','N','E',' ')}}, /* Nenets -> Forest Nenets */ - {"yue", {HB_TAG('Z','H','H',' ')}}, /* Yue Chinese -> Chinese, Hong Kong SAR */ - {"za", {HB_TAG('Z','H','A',' ')}}, /* Zhuang [macrolanguage] */ - {"zch", {HB_TAG('Z','H','A',' ')}}, /* Central Hongshuihe Zhuang -> Zhuang */ - {"zdj", {HB_TAG('C','M','R',' ')}}, /* Ngazidja Comorian -> Comorian */ - {"zea", {HB_TAG('Z','E','A',' ')}}, /* Zeeuws -> Zealandic */ - {"zeh", {HB_TAG('Z','H','A',' ')}}, /* Eastern Hongshuihe Zhuang -> Zhuang */ - {"zgb", {HB_TAG('Z','H','A',' ')}}, /* Guibei Zhuang -> Zhuang */ - {"zgh", {HB_TAG('Z','G','H',' ')}}, /* Standard Moroccan Tamazight */ - {"zgm", {HB_TAG('Z','H','A',' ')}}, /* Minz Zhuang -> Zhuang */ - {"zgn", {HB_TAG('Z','H','A',' ')}}, /* Guibian Zhuang -> Zhuang */ - {"zh", {HB_TAG('Z','H','S',' ')}}, /* Chinese [macrolanguage] -> Chinese Simplified */ - {"zhd", {HB_TAG('Z','H','A',' ')}}, /* Dai Zhuang -> Zhuang */ - {"zhn", {HB_TAG('Z','H','A',' ')}}, /* Nong Zhuang -> Zhuang */ - {"zlj", {HB_TAG('Z','H','A',' ')}}, /* Liujiang Zhuang -> Zhuang */ - {"zlm", {HB_TAG('M','L','Y',' ')}}, /* Malay */ - {"zln", {HB_TAG('Z','H','A',' ')}}, /* Lianshan Zhuang -> Zhuang */ - {"zlq", {HB_TAG('Z','H','A',' ')}}, /* Liuqian Zhuang -> Zhuang */ - {"zmi", {HB_TAG('M','L','Y',' ')}}, /* Negeri Sembilan Malay -> Malay */ - {"zne", {HB_TAG('Z','N','D',' ')}}, /* Zande */ - {"zom", {HB_TAG('Q','I','N',' ')}}, /* Zou -> Chin */ - {"zqe", {HB_TAG('Z','H','A',' ')}}, /* Qiubei Zhuang -> Zhuang */ - {"zsm", {HB_TAG('M','L','Y',' ')}}, /* Standard Malay -> Malay */ - {"zu", {HB_TAG('Z','U','L',' ')}}, /* Zulu */ - {"zum", {HB_TAG('L','R','C',' ')}}, /* Kumzari -> Luri */ - {"zyb", {HB_TAG('Z','H','A',' ')}}, /* Yongbei Zhuang -> Zhuang */ - {"zyg", {HB_TAG('Z','H','A',' ')}}, /* Yang Zhuang -> Zhuang */ - {"zyj", {HB_TAG('Z','H','A',' ')}}, /* Youjiang Zhuang -> Zhuang */ - {"zyn", {HB_TAG('Z','H','A',' ')}}, /* Yongnan Zhuang -> Zhuang */ - {"zza", {HB_TAG('Z','Z','A',' ')}}, /* Zazaki [macrolanguage] */ - {"zzj", {HB_TAG('Z','H','A',' ')}}, /* Zuojiang Zhuang -> Zhuang */ + {"aa", HB_TAG('A','F','R',' ')}, /* Afar */ + {"aae", HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */ + {"aao", HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */ + {"aat", HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */ + {"ab", HB_TAG('A','B','K',' ')}, /* Abkhazian */ + {"abh", HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */ + {"abq", HB_TAG('A','B','A',' ')}, /* Abaza */ + {"abv", HB_TAG('A','R','A',' ')}, /* Baharna Arabic -> Arabic */ + {"acf", HB_TAG('F','A','N',' ')}, /* Saint Lucian Creole French -> French Antillean */ +/*{"ach", HB_TAG('A','C','H',' ')},*/ /* Acoli -> Acholi */ + {"acm", HB_TAG('A','R','A',' ')}, /* Mesopotamian Arabic -> Arabic */ + {"acq", HB_TAG('A','R','A',' ')}, /* Ta'izzi-Adeni Arabic -> Arabic */ +/*{"acr", HB_TAG('A','C','R',' ')},*/ /* Achi */ + {"acw", HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */ + {"acx", HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */ + {"acy", HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */ + {"ada", HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */ + {"adf", HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */ + {"adp", HB_TAG('D','Z','N',' ')}, /* Adap (retired code) -> Dzongkha */ +/*{"ady", HB_TAG('A','D','Y',' ')},*/ /* Adyghe */ + {"aeb", HB_TAG('A','R','A',' ')}, /* Tunisian Arabic -> Arabic */ + {"aec", HB_TAG('A','R','A',' ')}, /* Saidi Arabic -> Arabic */ + {"af", HB_TAG('A','F','K',' ')}, /* Afrikaans */ + {"afb", HB_TAG('A','R','A',' ')}, /* Gulf Arabic -> Arabic */ + {"ahg", HB_TAG('A','G','W',' ')}, /* Qimant -> Agaw */ + {"aht", HB_TAG('A','T','H',' ')}, /* Ahtena -> Athapaskan */ + {"aii", HB_TAG('S','W','A',' ')}, /* Assyrian Neo-Aramaic -> Swadaya Aramaic */ + {"aii", HB_TAG('S','Y','R',' ')}, /* Assyrian Neo-Aramaic -> Syriac */ +/*{"aio", HB_TAG('A','I','O',' ')},*/ /* Aiton */ + {"aiw", HB_TAG('A','R','I',' ')}, /* Aari */ + {"ajp", HB_TAG('A','R','A',' ')}, /* South Levantine Arabic -> Arabic */ + {"ak", HB_TAG('A','K','A',' ')}, /* Akan [macrolanguage] */ + {"ak", HB_TAG('T','W','I',' ')}, /* Akan [macrolanguage] -> Twi */ + {"aln", HB_TAG('S','Q','I',' ')}, /* Gheg Albanian -> Albanian */ + {"als", HB_TAG('S','Q','I',' ')}, /* Tosk Albanian -> Albanian */ +/*{"alt", HB_TAG('A','L','T',' ')},*/ /* Southern Altai -> Altai */ + {"am", HB_TAG('A','M','H',' ')}, /* Amharic */ + {"amf", HB_TAG('H','B','N',' ')}, /* Hamer-Banna -> Hammer-Banna */ + {"amw", HB_TAG('S','Y','R',' ')}, /* Western Neo-Aramaic -> Syriac */ + {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */ +/*{"ang", HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ + {"apc", HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */ + {"apd", HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */ + {"apj", HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */ + {"apk", HB_TAG('A','T','H',' ')}, /* Kiowa Apache -> Athapaskan */ + {"apl", HB_TAG('A','T','H',' ')}, /* Lipan Apache -> Athapaskan */ + {"apm", HB_TAG('A','T','H',' ')}, /* Mescalero-Chiricahua Apache -> Athapaskan */ + {"apw", HB_TAG('A','T','H',' ')}, /* Western Apache -> Athapaskan */ + {"ar", HB_TAG('A','R','A',' ')}, /* Arabic [macrolanguage] */ + {"arb", HB_TAG('A','R','A',' ')}, /* Standard Arabic -> Arabic */ + {"arn", HB_TAG('M','A','P',' ')}, /* Mapudungun */ + {"arq", HB_TAG('A','R','A',' ')}, /* Algerian Arabic -> Arabic */ + {"ars", HB_TAG('A','R','A',' ')}, /* Najdi Arabic -> Arabic */ + {"ary", HB_TAG('M','O','R',' ')}, /* Moroccan Arabic -> Moroccan */ + {"arz", HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ + {"as", HB_TAG('A','S','M',' ')}, /* Assamese */ +/*{"ast", HB_TAG('A','S','T',' ')},*/ /* Asturian */ +/*{"ath", HB_TAG('A','T','H',' ')},*/ /* Athapascan [family] -> Athapaskan */ + {"atj", HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ + {"atv", HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ + {"auz", HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */ + {"av", HB_TAG('A','V','R',' ')}, /* Avaric -> Avar */ + {"avl", HB_TAG('A','R','A',' ')}, /* Eastern Egyptian Bedawi Arabic -> Arabic */ +/*{"awa", HB_TAG('A','W','A',' ')},*/ /* Awadhi */ + {"ay", HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */ + {"ayc", HB_TAG('A','Y','M',' ')}, /* Southern Aymara -> Aymara */ + {"ayh", HB_TAG('A','R','A',' ')}, /* Hadrami Arabic -> Arabic */ + {"ayl", HB_TAG('A','R','A',' ')}, /* Libyan Arabic -> Arabic */ + {"ayn", HB_TAG('A','R','A',' ')}, /* Sanaani Arabic -> Arabic */ + {"ayp", HB_TAG('A','R','A',' ')}, /* North Mesopotamian Arabic -> Arabic */ + {"ayr", HB_TAG('A','Y','M',' ')}, /* Central Aymara -> Aymara */ + {"az", HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */ +/*{"azb", HB_TAG('A','Z','B',' ')},*/ /* South Azerbaijani -> Torki */ + {"azj", HB_TAG('A','Z','E',' ')}, /* North Azerbaijani -> Azerbaijani */ + {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ + {"bad", HB_TAG('B','A','D','0')}, /* Banda [family] */ + {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */ + {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ +/*{"ban", HB_TAG('B','A','N',' ')},*/ /* Balinese */ +/*{"bar", HB_TAG('B','A','R',' ')},*/ /* Bavarian */ +/*{"bbc", HB_TAG('B','B','C',' ')},*/ /* Batak Toba */ + {"bbz", HB_TAG('A','R','A',' ')}, /* Babalia Creole Arabic (retired code) -> Arabic */ + {"bcc", HB_TAG('B','L','I',' ')}, /* Southern Balochi -> Baluchi */ + {"bci", HB_TAG('B','A','U',' ')}, /* Baoulé -> Baulé */ + {"bcl", HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */ + {"bcq", HB_TAG('B','C','H',' ')}, /* Bench */ + {"bcr", HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */ +/*{"bdy", HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */ + {"be", HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */ + {"bea", HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */ + {"beb", HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ +/*{"bem", HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ + {"ber", HB_TAG('B','B','R',' ')}, /* Berber [family] */ + {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ + {"bft", HB_TAG('B','L','T',' ')}, /* Balti */ + {"bfu", HB_TAG('L','A','H',' ')}, /* Gahri -> Lahuli */ + {"bfy", HB_TAG('B','A','G',' ')}, /* Bagheli -> Baghelkhandi */ + {"bg", HB_TAG('B','G','R',' ')}, /* Bulgarian */ +/*{"bgc", HB_TAG('B','G','C',' ')},*/ /* Haryanvi */ + {"bgn", HB_TAG('B','L','I',' ')}, /* Western Balochi -> Baluchi */ + {"bgp", HB_TAG('B','L','I',' ')}, /* Eastern Balochi -> Baluchi */ +/*{"bgq", HB_TAG('B','G','Q',' ')},*/ /* Bagri */ + {"bgr", HB_TAG('Q','I','N',' ')}, /* Bawm Chin -> Chin */ + {"bhb", HB_TAG('B','H','I',' ')}, /* Bhili */ +/*{"bhi", HB_TAG('B','H','I',' ')},*/ /* Bhilali -> Bhili */ + {"bhk", HB_TAG('B','I','K',' ')}, /* Albay Bicolano (retired code) -> Bikol */ +/*{"bho", HB_TAG('B','H','O',' ')},*/ /* Bhojpuri */ + {"bhr", HB_TAG('M','L','G',' ')}, /* Bara Malagasy -> Malagasy */ + {"bi", HB_TAG('B','I','S',' ')}, /* Bislama */ +/*{"bik", HB_TAG('B','I','K',' ')},*/ /* Bikol [macrolanguage] */ + {"bin", HB_TAG('E','D','O',' ')}, /* Edo */ +/*{"bjj", HB_TAG('B','J','J',' ')},*/ /* Kanauji */ + {"bjn", HB_TAG('M','L','Y',' ')}, /* Banjar -> Malay */ + {"bjq", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy (retired code) -> Malagasy */ + {"bjt", HB_TAG('B','L','N',' ')}, /* Balanta-Ganja -> Balante */ + {"bla", HB_TAG('B','K','F',' ')}, /* Siksika -> Blackfoot */ + {"ble", HB_TAG('B','L','N',' ')}, /* Balanta-Kentohe -> Balante */ +/*{"blk", HB_TAG('B','L','K',' ')},*/ /* Pa’o Karen */ + {"bln", HB_TAG('B','I','K',' ')}, /* Southern Catanduanes Bikol -> Bikol */ + {"bm", HB_TAG('B','M','B',' ')}, /* Bambara (Bamanankan) */ + {"bmm", HB_TAG('M','L','G',' ')}, /* Northern Betsimisaraka Malagasy -> Malagasy */ + {"bn", HB_TAG('B','E','N',' ')}, /* Bengali */ + {"bo", HB_TAG('T','I','B',' ')}, /* Tibetan */ +/*{"bpy", HB_TAG('B','P','Y',' ')},*/ /* Bishnupriya -> Bishnupriya Manipuri */ + {"bqi", HB_TAG('L','R','C',' ')}, /* Bakhtiari -> Luri */ + {"br", HB_TAG('B','R','E',' ')}, /* Breton */ + {"bra", HB_TAG('B','R','I',' ')}, /* Braj -> Braj Bhasha */ +/*{"brh", HB_TAG('B','R','H',' ')},*/ /* Brahui */ +/*{"brx", HB_TAG('B','R','X',' ')},*/ /* Bodo (India) */ + {"bs", HB_TAG('B','O','S',' ')}, /* Bosnian */ +/*{"bsk", HB_TAG('B','S','K',' ')},*/ /* Burushaski */ + {"btb", HB_TAG('B','T','I',' ')}, /* Beti (Cameroon) (retired code) */ + {"btj", HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ + {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ +/*{"bts", HB_TAG('B','T','S',' ')},*/ /* Batak Simalungun */ +/*{"bug", HB_TAG('B','U','G',' ')},*/ /* Buginese -> Bugis */ + {"bum", HB_TAG('B','T','I',' ')}, /* Bulu (Cameroon) -> Beti */ + {"bve", HB_TAG('M','L','Y',' ')}, /* Berau Malay -> Malay */ + {"bvu", HB_TAG('M','L','Y',' ')}, /* Bukit Malay -> Malay */ + {"bxk", HB_TAG('L','U','H',' ')}, /* Bukusu -> Luyia */ + {"bxp", HB_TAG('B','T','I',' ')}, /* Bebil -> Beti */ + {"bxr", HB_TAG('R','B','U',' ')}, /* Russia Buriat -> Russian Buriat */ + {"byn", HB_TAG('B','I','L',' ')}, /* Bilin -> Bilen */ +/*{"byv", HB_TAG('B','Y','V',' ')},*/ /* Medumba */ + {"bzc", HB_TAG('M','L','G',' ')}, /* Southern Betsimisaraka Malagasy -> Malagasy */ + {"ca", HB_TAG('C','A','T',' ')}, /* Catalan */ + {"caf", HB_TAG('C','R','R',' ')}, /* Southern Carrier -> Carrier */ + {"caf", HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */ +/*{"cak", HB_TAG('C','A','K',' ')},*/ /* Kaqchikel */ +/*{"cbk", HB_TAG('C','B','K',' ')},*/ /* Chavacano -> Zamboanga Chavacano */ + {"cbl", HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */ + {"cco", HB_TAG('C','C','H','N')}, /* Comaltepec Chinantec -> Chinantec */ + {"ccq", HB_TAG('A','R','K',' ')}, /* Chaungtha (retired code) -> Rakhine */ + {"cdo", HB_TAG('Z','H','S',' ')}, /* Min Dong Chinese -> Chinese Simplified */ + {"ce", HB_TAG('C','H','E',' ')}, /* Chechen */ +/*{"ceb", HB_TAG('C','E','B',' ')},*/ /* Cebuano */ + {"cfm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) */ +/*{"cgg", HB_TAG('C','G','G',' ')},*/ /* Chiga */ + {"ch", HB_TAG('C','H','A',' ')}, /* Chamorro */ + {"chj", HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ + {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */ +/*{"cho", HB_TAG('C','H','O',' ')},*/ /* Choctaw */ + {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ + {"chp", HB_TAG('S','A','Y',' ')}, /* Chipewyan -> Sayisi */ + {"chp", HB_TAG('A','T','H',' ')}, /* Chipewyan -> Athapaskan */ + {"chq", HB_TAG('C','C','H','N')}, /* Quiotepec Chinantec -> Chinantec */ +/*{"chr", HB_TAG('C','H','R',' ')},*/ /* Cherokee */ +/*{"chy", HB_TAG('C','H','Y',' ')},*/ /* Cheyenne */ + {"chz", HB_TAG('C','C','H','N')}, /* Ozumacín Chinantec -> Chinantec */ + {"ciw", HB_TAG('O','J','B',' ')}, /* Chippewa -> Ojibway */ +/*{"cja", HB_TAG('C','J','A',' ')},*/ /* Western Cham */ +/*{"cjm", HB_TAG('C','J','M',' ')},*/ /* Eastern Cham */ + {"cjy", HB_TAG('Z','H','S',' ')}, /* Jinyu Chinese -> Chinese Simplified */ + {"cka", HB_TAG('Q','I','N',' ')}, /* Khumi Awa Chin (retired code) -> Chin */ + {"ckb", HB_TAG('K','U','R',' ')}, /* Central Kurdish -> Kurdish */ + {"ckt", HB_TAG('C','H','K',' ')}, /* Chukot -> Chukchi */ + {"clc", HB_TAG('A','T','H',' ')}, /* Chilcotin -> Athapaskan */ + {"cld", HB_TAG('S','Y','R',' ')}, /* Chaldean Neo-Aramaic -> Syriac */ + {"cle", HB_TAG('C','C','H','N')}, /* Lealao Chinantec -> Chinantec */ + {"cmn", HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese Simplified */ + {"cmr", HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */ + {"cnb", HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */ + {"cnh", HB_TAG('Q','I','N',' ')}, /* Hakha Chin -> Chin */ + {"cnk", HB_TAG('Q','I','N',' ')}, /* Khumi Chin -> Chin */ + {"cnl", HB_TAG('C','C','H','N')}, /* Lalana Chinantec -> Chinantec */ + {"cnp", HB_TAG('Z','H','S',' ')}, /* Northern Ping Chinese -> Chinese Simplified */ + {"cnt", HB_TAG('C','C','H','N')}, /* Tepetotutla Chinantec -> Chinantec */ + {"cnw", HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */ + {"co", HB_TAG('C','O','S',' ')}, /* Corsican */ + {"coa", HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */ +/*{"cop", HB_TAG('C','O','P',' ')},*/ /* Coptic */ + {"coq", HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ + {"cpa", HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ + {"cpe", HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [family] -> Creoles */ + {"cpf", HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [family] -> Creoles */ +/*{"cpp", HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [family] -> Creoles */ + {"cpx", HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese Simplified */ + {"cqd", HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ + {"cqu", HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ + {"cr", HB_TAG('C','R','E',' ')}, /* Cree [macrolanguage] */ + {"cr", HB_TAG('Y','C','R',' ')}, /* Cree [macrolanguage] -> Y-Cree */ + {"crh", HB_TAG('C','R','T',' ')}, /* Crimean Tatar */ + {"crj", HB_TAG('E','C','R',' ')}, /* Southern East Cree -> Eastern Cree */ + {"crk", HB_TAG('W','C','R',' ')}, /* Plains Cree -> West-Cree */ + {"crl", HB_TAG('E','C','R',' ')}, /* Northern East Cree -> Eastern Cree */ + {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ + {"crm", HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ + {"crp", HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [family] -> Creoles */ + {"crx", HB_TAG('C','R','R',' ')}, /* Carrier */ + {"crx", HB_TAG('A','T','H',' ')}, /* Carrier -> Athapaskan */ + {"cs", HB_TAG('C','S','Y',' ')}, /* Czech */ + {"csa", HB_TAG('C','C','H','N')}, /* Chiltepec Chinantec -> Chinantec */ +/*{"csb", HB_TAG('C','S','B',' ')},*/ /* Kashubian */ + {"csh", HB_TAG('Q','I','N',' ')}, /* Asho Chin -> Chin */ + {"cso", HB_TAG('C','C','H','N')}, /* Sochiapam Chinantec -> Chinantec */ + {"csp", HB_TAG('Z','H','S',' ')}, /* Southern Ping Chinese -> Chinese Simplified */ + {"csw", HB_TAG('N','C','R',' ')}, /* Swampy Cree -> N-Cree */ + {"csw", HB_TAG('N','H','C',' ')}, /* Swampy Cree -> Norway House Cree */ + {"csy", HB_TAG('Q','I','N',' ')}, /* Siyin Chin -> Chin */ + {"ctc", HB_TAG('A','T','H',' ')}, /* Chetco -> Athapaskan */ + {"ctd", HB_TAG('Q','I','N',' ')}, /* Tedim Chin -> Chin */ + {"cte", HB_TAG('C','C','H','N')}, /* Tepinapa Chinantec -> Chinantec */ +/*{"ctg", HB_TAG('C','T','G',' ')},*/ /* Chittagonian */ + {"ctl", HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */ + {"cts", HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */ + {"cu", HB_TAG('C','S','L',' ')}, /* Church Slavonic */ + {"cuc", HB_TAG('C','C','H','N')}, /* Usila Chinantec -> Chinantec */ +/*{"cuk", HB_TAG('C','U','K',' ')},*/ /* San Blas Kuna */ + {"cv", HB_TAG('C','H','U',' ')}, /* Chuvash */ + {"cvn", HB_TAG('C','C','H','N')}, /* Valle Nacional Chinantec -> Chinantec */ + {"cwd", HB_TAG('D','C','R',' ')}, /* Woods Cree */ + {"cwd", HB_TAG('T','C','R',' ')}, /* Woods Cree -> TH-Cree */ + {"cy", HB_TAG('W','E','L',' ')}, /* Welsh */ + {"czh", HB_TAG('Z','H','S',' ')}, /* Huizhou Chinese -> Chinese Simplified */ + {"czo", HB_TAG('Z','H','S',' ')}, /* Min Zhong Chinese -> Chinese Simplified */ + {"czt", HB_TAG('Q','I','N',' ')}, /* Zotung Chin -> Chin */ + {"da", HB_TAG('D','A','N',' ')}, /* Danish */ + {"dao", HB_TAG('Q','I','N',' ')}, /* Daai Chin -> Chin */ + {"dap", HB_TAG('N','I','S',' ')}, /* Nisi (India) (retired code) */ +/*{"dar", HB_TAG('D','A','R',' ')},*/ /* Dargwa */ +/*{"dax", HB_TAG('D','A','X',' ')},*/ /* Dayi */ + {"de", HB_TAG('D','E','U',' ')}, /* German */ + {"den", HB_TAG('S','L','A',' ')}, /* Slave (Athapascan) [macrolanguage] -> Slavey */ + {"den", HB_TAG('A','T','H',' ')}, /* Slave (Athapascan) [macrolanguage] -> Athapaskan */ +/*{"dgo", HB_TAG('D','G','O',' ')},*/ /* Dogri */ + {"dgr", HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */ + {"dhd", HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */ +/*{"dhg", HB_TAG('D','H','G',' ')},*/ /* Dhangu */ + {"dib", HB_TAG('D','N','K',' ')}, /* South Central Dinka -> Dinka */ + {"dik", HB_TAG('D','N','K',' ')}, /* Southwestern Dinka -> Dinka */ + {"din", HB_TAG('D','N','K',' ')}, /* Dinka [macrolanguage] */ + {"dip", HB_TAG('D','N','K',' ')}, /* Northeastern Dinka -> Dinka */ +/*{"diq", HB_TAG('D','I','Q',' ')},*/ /* Dimli */ + {"diw", HB_TAG('D','N','K',' ')}, /* Northwestern Dinka -> Dinka */ + {"dje", HB_TAG('D','J','R',' ')}, /* Zarma */ + {"djr", HB_TAG('D','J','R','0')}, /* Djambarrpuyngu */ + {"dks", HB_TAG('D','N','K',' ')}, /* Southeastern Dinka -> Dinka */ + {"dng", HB_TAG('D','U','N',' ')}, /* Dungan */ +/*{"dnj", HB_TAG('D','N','J',' ')},*/ /* Dan */ + {"doi", HB_TAG('D','G','R',' ')}, /* Dogri [macrolanguage] */ + {"drh", HB_TAG('M','N','G',' ')}, /* Darkhat (retired code) -> Mongolian */ + {"drw", HB_TAG('D','R','I',' ')}, /* Darwazi (retired code) -> Dari */ + {"dsb", HB_TAG('L','S','B',' ')}, /* Lower Sorbian */ + {"dty", HB_TAG('N','E','P',' ')}, /* Dotyali -> Nepali */ +/*{"duj", HB_TAG('D','U','J',' ')},*/ /* Dhuwal (retired code) */ + {"dup", HB_TAG('M','L','Y',' ')}, /* Duano -> Malay */ + {"dv", HB_TAG('D','I','V',' ')}, /* Divehi (Dhivehi, Maldivian) */ + {"dv", HB_TAG('D','H','V',' ')}, /* Divehi (Dhivehi, Maldivian) (deprecated) */ + {"dwk", HB_TAG('K','U','I',' ')}, /* Dawik Kui -> Kui */ + {"dwu", HB_TAG('D','U','J',' ')}, /* Dhuwal */ + {"dwy", HB_TAG('D','U','J',' ')}, /* Dhuwaya -> Dhuwal */ + {"dyu", HB_TAG('J','U','L',' ')}, /* Dyula -> Jula */ + {"dz", HB_TAG('D','Z','N',' ')}, /* Dzongkha */ + {"ee", HB_TAG('E','W','E',' ')}, /* Ewe */ +/*{"efi", HB_TAG('E','F','I',' ')},*/ /* Efik */ + {"ekk", HB_TAG('E','T','I',' ')}, /* Standard Estonian -> Estonian */ + {"el", HB_TAG('E','L','L',' ')}, /* Modern Greek (1453-) -> Greek */ + {"emk", HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */ + {"emk", HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */ + {"en", HB_TAG('E','N','G',' ')}, /* English */ + {"enb", HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */ + {"enf", HB_TAG('F','N','E',' ')}, /* Forest Enets -> Forest Nenets */ + {"enh", HB_TAG('T','N','E',' ')}, /* Tundra Enets -> Tundra Nenets */ + {"eo", HB_TAG('N','T','O',' ')}, /* Esperanto */ + {"es", HB_TAG('E','S','P',' ')}, /* Spanish */ + {"esg", HB_TAG('G','O','N',' ')}, /* Aheri Gondi -> Gondi */ + {"esi", HB_TAG('I','P','K',' ')}, /* North Alaskan Inupiatun -> Inupiat */ + {"esk", HB_TAG('I','P','K',' ')}, /* Northwest Alaska Inupiatun -> Inupiat */ +/*{"esu", HB_TAG('E','S','U',' ')},*/ /* Central Yupik */ + {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ + {"eto", HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ + {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */ + {"eve", HB_TAG('E','V','N',' ')}, /* Even */ + {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */ + {"ewo", HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ + {"eyo", HB_TAG('K','A','L',' ')}, /* Keiyo -> Kalenjin */ + {"fa", HB_TAG('F','A','R',' ')}, /* Persian [macrolanguage] */ + {"fan", HB_TAG('F','A','N','0')}, /* Fang (Equatorial Guinea) */ +/*{"fat", HB_TAG('F','A','T',' ')},*/ /* Fanti */ + {"fbl", HB_TAG('B','I','K',' ')}, /* West Albay Bikol -> Bikol */ + {"ff", HB_TAG('F','U','L',' ')}, /* Fulah [macrolanguage] */ + {"ffm", HB_TAG('F','U','L',' ')}, /* Maasina Fulfulde -> Fulah */ + {"fi", HB_TAG('F','I','N',' ')}, /* Finnish */ + {"fil", HB_TAG('P','I','L',' ')}, /* Filipino */ + {"fj", HB_TAG('F','J','I',' ')}, /* Fijian */ + {"flm", HB_TAG('H','A','L',' ')}, /* Halam (Falam Chin) (retired code) */ + {"flm", HB_TAG('Q','I','N',' ')}, /* Falam Chin (retired code) -> Chin */ +/*{"fmp", HB_TAG('F','M','P',' ')},*/ /* Fe’fe’ */ + {"fo", HB_TAG('F','O','S',' ')}, /* Faroese */ +/*{"fon", HB_TAG('F','O','N',' ')},*/ /* Fon */ + {"fr", HB_TAG('F','R','A',' ')}, /* French */ +/*{"frc", HB_TAG('F','R','C',' ')},*/ /* Cajun French */ +/*{"frp", HB_TAG('F','R','P',' ')},*/ /* Arpitan */ + {"fub", HB_TAG('F','U','L',' ')}, /* Adamawa Fulfulde -> Fulah */ + {"fuc", HB_TAG('F','U','L',' ')}, /* Pulaar -> Fulah */ + {"fue", HB_TAG('F','U','L',' ')}, /* Borgu Fulfulde -> Fulah */ + {"fuf", HB_TAG('F','T','A',' ')}, /* Pular -> Futa */ + {"fuh", HB_TAG('F','U','L',' ')}, /* Western Niger Fulfulde -> Fulah */ + {"fui", HB_TAG('F','U','L',' ')}, /* Bagirmi Fulfulde -> Fulah */ + {"fuq", HB_TAG('F','U','L',' ')}, /* Central-Eastern Niger Fulfulde -> Fulah */ + {"fur", HB_TAG('F','R','L',' ')}, /* Friulian */ +/*{"fuv", HB_TAG('F','U','V',' ')},*/ /* Nigerian Fulfulde */ + {"fy", HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */ + {"ga", HB_TAG('I','R','I',' ')}, /* Irish */ + {"gaa", HB_TAG('G','A','D',' ')}, /* Ga */ +/*{"gag", HB_TAG('G','A','G',' ')},*/ /* Gagauz */ + {"gan", HB_TAG('Z','H','S',' ')}, /* Gan Chinese -> Chinese Simplified */ + {"gax", HB_TAG('O','R','O',' ')}, /* Borana-Arsi-Guji Oromo -> Oromo */ + {"gaz", HB_TAG('O','R','O',' ')}, /* West Central Oromo -> Oromo */ + {"gbm", HB_TAG('G','A','W',' ')}, /* Garhwali */ + {"gce", HB_TAG('A','T','H',' ')}, /* Galice -> Athapaskan */ + {"gd", HB_TAG('G','A','E',' ')}, /* Scottish Gaelic (Gaelic) */ + {"gda", HB_TAG('R','A','J',' ')}, /* Gade Lohar -> Rajasthani */ +/*{"gez", HB_TAG('G','E','Z',' ')},*/ /* Geez */ + {"ggo", HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */ +/*{"gih", HB_TAG('G','I','H',' ')},*/ /* Githabul */ + {"gil", HB_TAG('G','I','L','0')}, /* Kiribati (Gilbertese) */ + {"gju", HB_TAG('R','A','J',' ')}, /* Gujari -> Rajasthani */ +/*{"gkp", HB_TAG('G','K','P',' ')},*/ /* Guinea Kpelle -> Kpelle (Guinea) */ + {"gl", HB_TAG('G','A','L',' ')}, /* Galician */ + {"gld", HB_TAG('N','A','N',' ')}, /* Nanai */ +/*{"glk", HB_TAG('G','L','K',' ')},*/ /* Gilaki */ + {"gn", HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */ +/*{"gnn", HB_TAG('G','N','N',' ')},*/ /* Gumatj */ + {"gno", HB_TAG('G','O','N',' ')}, /* Northern Gondi -> Gondi */ + {"gnw", HB_TAG('G','U','A',' ')}, /* Western Bolivian Guaraní -> Guarani */ +/*{"gog", HB_TAG('G','O','G',' ')},*/ /* Gogo */ + {"gom", HB_TAG('K','O','K',' ')}, /* Goan Konkani -> Konkani */ +/*{"gon", HB_TAG('G','O','N',' ')},*/ /* Gondi [macrolanguage] */ + {"grt", HB_TAG('G','R','O',' ')}, /* Garo */ + {"gru", HB_TAG('S','O','G',' ')}, /* Kistane -> Sodo Gurage */ + {"gsw", HB_TAG('A','L','S',' ')}, /* Alsatian */ + {"gu", HB_TAG('G','U','J',' ')}, /* Gujarati */ +/*{"guc", HB_TAG('G','U','C',' ')},*/ /* Wayuu */ +/*{"guf", HB_TAG('G','U','F',' ')},*/ /* Gupapuyngu */ + {"gug", HB_TAG('G','U','A',' ')}, /* Paraguayan Guaraní -> Guarani */ + {"gui", HB_TAG('G','U','A',' ')}, /* Eastern Bolivian Guaraní -> Guarani */ + {"guk", HB_TAG('G','M','Z',' ')}, /* Gumuz */ + {"guk", HB_TAG('G','U','K',' ')}, /* Gumuz (SIL fonts) */ + {"gun", HB_TAG('G','U','A',' ')}, /* Mbyá Guaraní -> Guarani */ +/*{"guz", HB_TAG('G','U','Z',' ')},*/ /* Gusii */ + {"gv", HB_TAG('M','N','X',' ')}, /* Manx */ + {"gwi", HB_TAG('A','T','H',' ')}, /* Gwichʼin -> Athapaskan */ + {"ha", HB_TAG('H','A','U',' ')}, /* Hausa */ + {"haa", HB_TAG('A','T','H',' ')}, /* Han -> Athapaskan */ + {"hae", HB_TAG('O','R','O',' ')}, /* Eastern Oromo -> Oromo */ + {"hak", HB_TAG('Z','H','S',' ')}, /* Hakka Chinese -> Chinese Simplified */ + {"har", HB_TAG('H','R','I',' ')}, /* Harari */ +/*{"haw", HB_TAG('H','A','W',' ')},*/ /* Hawaiian */ +/*{"hay", HB_TAG('H','A','Y',' ')},*/ /* Haya */ +/*{"haz", HB_TAG('H','A','Z',' ')},*/ /* Hazaragi */ + {"he", HB_TAG('I','W','R',' ')}, /* Hebrew */ + {"hea", HB_TAG('H','M','N',' ')}, /* Northern Qiandong Miao -> Hmong */ + {"hi", HB_TAG('H','I','N',' ')}, /* Hindi */ +/*{"hil", HB_TAG('H','I','L',' ')},*/ /* Hiligaynon */ + {"hji", HB_TAG('M','L','Y',' ')}, /* Haji -> Malay */ + {"hlt", HB_TAG('Q','I','N',' ')}, /* Matu Chin -> Chin */ + {"hma", HB_TAG('H','M','N',' ')}, /* Southern Mashan Hmong -> Hmong */ + {"hmc", HB_TAG('H','M','N',' ')}, /* Central Huishui Hmong -> Hmong */ + {"hmd", HB_TAG('H','M','N',' ')}, /* Large Flowery Miao -> Hmong */ + {"hme", HB_TAG('H','M','N',' ')}, /* Eastern Huishui Hmong -> Hmong */ + {"hmg", HB_TAG('H','M','N',' ')}, /* Southwestern Guiyang Hmong -> Hmong */ + {"hmh", HB_TAG('H','M','N',' ')}, /* Southwestern Huishui Hmong -> Hmong */ + {"hmi", HB_TAG('H','M','N',' ')}, /* Northern Huishui Hmong -> Hmong */ + {"hmj", HB_TAG('H','M','N',' ')}, /* Ge -> Hmong */ + {"hml", HB_TAG('H','M','N',' ')}, /* Luopohe Hmong -> Hmong */ + {"hmm", HB_TAG('H','M','N',' ')}, /* Central Mashan Hmong -> Hmong */ +/*{"hmn", HB_TAG('H','M','N',' ')},*/ /* Hmong [macrolanguage] */ + {"hmp", HB_TAG('H','M','N',' ')}, /* Northern Mashan Hmong -> Hmong */ + {"hmq", HB_TAG('H','M','N',' ')}, /* Eastern Qiandong Miao -> Hmong */ + {"hms", HB_TAG('H','M','N',' ')}, /* Southern Qiandong Miao -> Hmong */ + {"hmw", HB_TAG('H','M','N',' ')}, /* Western Mashan Hmong -> Hmong */ + {"hmy", HB_TAG('H','M','N',' ')}, /* Southern Guiyang Hmong -> Hmong */ + {"hmz", HB_TAG('H','M','N',' ')}, /* Hmong Shua -> Hmong */ +/*{"hnd", HB_TAG('H','N','D',' ')},*/ /* Southern Hindko -> Hindko */ + {"hne", HB_TAG('C','H','H',' ')}, /* Chhattisgarhi -> Chattisgarhi */ + {"hnj", HB_TAG('H','M','N',' ')}, /* Hmong Njua -> Hmong */ + {"hno", HB_TAG('H','N','D',' ')}, /* Northern Hindko -> Hindko */ + {"ho", HB_TAG('H','M','O',' ')}, /* Hiri Motu */ + {"hoc", HB_TAG('H','O',' ',' ')}, /* Ho */ + {"hoi", HB_TAG('A','T','H',' ')}, /* Holikachuk -> Athapaskan */ + {"hoj", HB_TAG('H','A','R',' ')}, /* Hadothi -> Harauti */ + {"hr", HB_TAG('H','R','V',' ')}, /* Croatian */ + {"hrm", HB_TAG('H','M','N',' ')}, /* Horned Miao -> Hmong */ + {"hsb", HB_TAG('U','S','B',' ')}, /* Upper Sorbian */ + {"hsn", HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese Simplified */ + {"ht", HB_TAG('H','A','I',' ')}, /* Haitian (Haitian Creole) */ + {"hu", HB_TAG('H','U','N',' ')}, /* Hungarian */ + {"huj", HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */ + {"hup", HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */ + {"hy", HB_TAG('H','Y','E','0')}, /* Armenian -> Armenian East */ + {"hy", HB_TAG('H','Y','E',' ')}, /* Armenian */ + {"hyw", HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */ + {"hz", HB_TAG('H','E','R',' ')}, /* Herero */ + {"ia", HB_TAG('I','N','A',' ')}, /* Interlingua (International Auxiliary Language Association) */ +/*{"iba", HB_TAG('I','B','A',' ')},*/ /* Iban */ +/*{"ibb", HB_TAG('I','B','B',' ')},*/ /* Ibibio */ + {"id", HB_TAG('I','N','D',' ')}, /* Indonesian */ + {"ida", HB_TAG('L','U','H',' ')}, /* Idakho-Isukha-Tiriki -> Luyia */ + {"ie", HB_TAG('I','L','E',' ')}, /* Interlingue */ + {"ig", HB_TAG('I','B','O',' ')}, /* Igbo */ + {"igb", HB_TAG('E','B','I',' ')}, /* Ebira */ + {"ii", HB_TAG('Y','I','M',' ')}, /* Sichuan Yi -> Yi Modern */ + {"ijc", HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ +/*{"ijo", HB_TAG('I','J','O',' ')},*/ /* Ijo [family] */ + {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */ + {"ike", HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ + {"ikt", HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ +/*{"ilo", HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ + {"in", HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */ + {"ing", HB_TAG('A','T','H',' ')}, /* Degexit'an -> Athapaskan */ + {"inh", HB_TAG('I','N','G',' ')}, /* Ingush */ + {"io", HB_TAG('I','D','O',' ')}, /* Ido */ + {"is", HB_TAG('I','S','L',' ')}, /* Icelandic */ + {"it", HB_TAG('I','T','A',' ')}, /* Italian */ + {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ + {"iw", HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */ + {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ + {"jak", HB_TAG('M','L','Y',' ')}, /* Jakun -> Malay */ +/*{"jam", HB_TAG('J','A','M',' ')},*/ /* Jamaican Creole English -> Jamaican Creole */ + {"jax", HB_TAG('M','L','Y',' ')}, /* Jambi Malay -> Malay */ +/*{"jbo", HB_TAG('J','B','O',' ')},*/ /* Lojban */ +/*{"jct", HB_TAG('J','C','T',' ')},*/ /* Krymchak */ + {"ji", HB_TAG('J','I','I',' ')}, /* Yiddish (retired code) */ + {"jv", HB_TAG('J','A','V',' ')}, /* Javanese */ + {"jw", HB_TAG('J','A','V',' ')}, /* Javanese (retired code) */ + {"ka", HB_TAG('K','A','T',' ')}, /* Georgian */ + {"kaa", HB_TAG('K','R','K',' ')}, /* Karakalpak */ + {"kab", HB_TAG('K','A','B','0')}, /* Kabyle */ + {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ + {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */ + {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ + {"kby", HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */ + {"kca", HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */ + {"kca", HB_TAG('K','H','S',' ')}, /* Khanty -> Khanty-Shurishkar */ + {"kca", HB_TAG('K','H','V',' ')}, /* Khanty -> Khanty-Vakhi */ +/*{"kde", HB_TAG('K','D','E',' ')},*/ /* Makonde */ + {"kdr", HB_TAG('K','R','M',' ')}, /* Karaim */ + {"kdt", HB_TAG('K','U','Y',' ')}, /* Kuy */ +/*{"kea", HB_TAG('K','E','A',' ')},*/ /* Kabuverdianu (Crioulo) */ +/*{"kek", HB_TAG('K','E','K',' ')},*/ /* Kekchi */ + {"kex", HB_TAG('K','K','N',' ')}, /* Kukna -> Kokni */ + {"kfa", HB_TAG('K','O','D',' ')}, /* Kodava -> Kodagu */ + {"kfr", HB_TAG('K','A','C',' ')}, /* Kachhi -> Kachchi */ + {"kfx", HB_TAG('K','U','L',' ')}, /* Kullu Pahari -> Kulvi */ + {"kfy", HB_TAG('K','M','N',' ')}, /* Kumaoni */ + {"kg", HB_TAG('K','O','N','0')}, /* Kongo [macrolanguage] */ + {"kha", HB_TAG('K','S','I',' ')}, /* Khasi */ + {"khb", HB_TAG('X','B','D',' ')}, /* Lü */ + {"khk", HB_TAG('M','N','G',' ')}, /* Halh Mongolian -> Mongolian */ + {"kht", HB_TAG('K','H','N',' ')}, /* Khamti -> Khamti Shan (Microsoft fonts) */ + {"kht", HB_TAG('K','H','T',' ')}, /* Khamti -> Khamti Shan (OpenType spec and SIL fonts) */ +/*{"khw", HB_TAG('K','H','W',' ')},*/ /* Khowar */ + {"ki", HB_TAG('K','I','K',' ')}, /* Kikuyu (Gikuyu) */ +/*{"kiu", HB_TAG('K','I','U',' ')},*/ /* Kirmanjki */ + {"kj", HB_TAG('K','U','A',' ')}, /* Kuanyama */ +/*{"kjd", HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */ + {"kjh", HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */ +/*{"kjp", HB_TAG('K','J','P',' ')},*/ /* Pwo Eastern Karen -> Eastern Pwo Karen */ +/*{"kjz", HB_TAG('K','J','Z',' ')},*/ /* Bumthangkha */ + {"kk", HB_TAG('K','A','Z',' ')}, /* Kazakh */ + {"kkz", HB_TAG('A','T','H',' ')}, /* Kaska -> Athapaskan */ + {"kl", HB_TAG('G','R','N',' ')}, /* Greenlandic */ + {"kln", HB_TAG('K','A','L',' ')}, /* Kalenjin [macrolanguage] */ + {"km", HB_TAG('K','H','M',' ')}, /* Khmer */ + {"kmb", HB_TAG('M','B','N',' ')}, /* Kimbundu -> Mbundu */ + {"kmr", HB_TAG('K','U','R',' ')}, /* Northern Kurdish -> Kurdish */ + {"kmw", HB_TAG('K','M','O',' ')}, /* Komo (Democratic Republic of Congo) */ +/*{"kmz", HB_TAG('K','M','Z',' ')},*/ /* Khorasani Turkish -> Khorasani Turkic */ + {"kn", HB_TAG('K','A','N',' ')}, /* Kannada */ + {"knc", HB_TAG('K','N','R',' ')}, /* Central Kanuri -> Kanuri */ + {"kng", HB_TAG('K','O','N','0')}, /* Koongo -> Kongo */ + {"knn", HB_TAG('K','O','K',' ')}, /* Konkani */ + {"ko", HB_TAG('K','O','R',' ')}, /* Korean */ + {"koi", HB_TAG('K','O','P',' ')}, /* Komi-Permyak */ +/*{"kok", HB_TAG('K','O','K',' ')},*/ /* Konkani [macrolanguage] */ +/*{"kos", HB_TAG('K','O','S',' ')},*/ /* Kosraean */ + {"koy", HB_TAG('A','T','H',' ')}, /* Koyukon -> Athapaskan */ + {"kpe", HB_TAG('K','P','L',' ')}, /* Kpelle [macrolanguage] */ + {"kpv", HB_TAG('K','O','Z',' ')}, /* Komi-Zyrian */ + {"kpy", HB_TAG('K','Y','K',' ')}, /* Koryak */ + {"kqs", HB_TAG('K','I','S',' ')}, /* Northern Kissi -> Kisii */ + {"kqy", HB_TAG('K','R','T',' ')}, /* Koorete */ + {"kr", HB_TAG('K','N','R',' ')}, /* Kanuri [macrolanguage] */ + {"krc", HB_TAG('K','A','R',' ')}, /* Karachay-Balkar -> Karachay */ + {"krc", HB_TAG('B','A','L',' ')}, /* Karachay-Balkar -> Balkar */ +/*{"kri", HB_TAG('K','R','I',' ')},*/ /* Krio */ +/*{"krl", HB_TAG('K','R','L',' ')},*/ /* Karelian */ + {"krt", HB_TAG('K','N','R',' ')}, /* Tumari Kanuri -> Kanuri */ + {"kru", HB_TAG('K','U','U',' ')}, /* Kurukh */ + {"ks", HB_TAG('K','S','H',' ')}, /* Kashmiri */ + {"ksh", HB_TAG('K','S','H','0')}, /* Kölsch -> Ripuarian */ + {"kss", HB_TAG('K','I','S',' ')}, /* Southern Kisi -> Kisii */ +/*{"ksw", HB_TAG('K','S','W',' ')},*/ /* S’gaw Karen */ + {"ktb", HB_TAG('K','E','B',' ')}, /* Kambaata -> Kebena */ + {"ktu", HB_TAG('K','O','N',' ')}, /* Kituba (Democratic Republic of Congo) -> Kikongo */ + {"ktw", HB_TAG('A','T','H',' ')}, /* Kato -> Athapaskan */ + {"ku", HB_TAG('K','U','R',' ')}, /* Kurdish [macrolanguage] */ +/*{"kum", HB_TAG('K','U','M',' ')},*/ /* Kumyk */ + {"kuu", HB_TAG('A','T','H',' ')}, /* Upper Kuskokwim -> Athapaskan */ + {"kv", HB_TAG('K','O','M',' ')}, /* Komi [macrolanguage] */ + {"kvb", HB_TAG('M','L','Y',' ')}, /* Kubu -> Malay */ + {"kvr", HB_TAG('M','L','Y',' ')}, /* Kerinci -> Malay */ + {"kw", HB_TAG('C','O','R',' ')}, /* Cornish */ + {"kwy", HB_TAG('K','O','N','0')}, /* San Salvador Kongo -> Kongo */ + {"kxc", HB_TAG('K','M','S',' ')}, /* Konso -> Komso */ + {"kxd", HB_TAG('M','L','Y',' ')}, /* Brunei -> Malay */ + {"kxl", HB_TAG('K','U','U',' ')}, /* Nepali Kurux (retired code) -> Kurukh */ + {"kxu", HB_TAG('K','U','I',' ')}, /* Kui (India) (retired code) */ + {"ky", HB_TAG('K','I','R',' ')}, /* Kirghiz (Kyrgyz) */ +/*{"kyu", HB_TAG('K','Y','U',' ')},*/ /* Western Kayah */ + {"la", HB_TAG('L','A','T',' ')}, /* Latin */ + {"lad", HB_TAG('J','U','D',' ')}, /* Ladino */ + {"lb", HB_TAG('L','T','Z',' ')}, /* Luxembourgish */ + {"lbe", HB_TAG('L','A','K',' ')}, /* Lak */ + {"lbj", HB_TAG('L','D','K',' ')}, /* Ladakhi */ + {"lbl", HB_TAG('B','I','K',' ')}, /* Libon Bikol -> Bikol */ + {"lce", HB_TAG('M','L','Y',' ')}, /* Loncong -> Malay */ + {"lcf", HB_TAG('M','L','Y',' ')}, /* Lubu -> Malay */ + {"ldi", HB_TAG('K','O','N','0')}, /* Laari -> Kongo */ +/*{"lez", HB_TAG('L','E','Z',' ')},*/ /* Lezghian -> Lezgi */ + {"lg", HB_TAG('L','U','G',' ')}, /* Ganda */ + {"li", HB_TAG('L','I','M',' ')}, /* Limburgish */ + {"lif", HB_TAG('L','M','B',' ')}, /* Limbu */ +/*{"lij", HB_TAG('L','I','J',' ')},*/ /* Ligurian */ +/*{"lis", HB_TAG('L','I','S',' ')},*/ /* Lisu */ + {"liw", HB_TAG('M','L','Y',' ')}, /* Col -> Malay */ +/*{"ljp", HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */ + {"lkb", HB_TAG('L','U','H',' ')}, /* Kabras -> Luyia */ +/*{"lki", HB_TAG('L','K','I',' ')},*/ /* Laki */ + {"lko", HB_TAG('L','U','H',' ')}, /* Khayo -> Luyia */ + {"lks", HB_TAG('L','U','H',' ')}, /* Kisa -> Luyia */ + {"lld", HB_TAG('L','A','D',' ')}, /* Ladin */ + {"lmn", HB_TAG('L','A','M',' ')}, /* Lambadi -> Lambani */ +/*{"lmo", HB_TAG('L','M','O',' ')},*/ /* Lombard */ + {"ln", HB_TAG('L','I','N',' ')}, /* Lingala */ + {"lo", HB_TAG('L','A','O',' ')}, /* Lao */ +/*{"lom", HB_TAG('L','O','M',' ')},*/ /* Loma (Liberia) */ +/*{"lrc", HB_TAG('L','R','C',' ')},*/ /* Northern Luri -> Luri */ + {"lri", HB_TAG('L','U','H',' ')}, /* Marachi -> Luyia */ + {"lrm", HB_TAG('L','U','H',' ')}, /* Marama -> Luyia */ + {"lsm", HB_TAG('L','U','H',' ')}, /* Saamia -> Luyia */ + {"lt", HB_TAG('L','T','H',' ')}, /* Lithuanian */ + {"ltg", HB_TAG('L','V','I',' ')}, /* Latgalian -> Latvian */ + {"lto", HB_TAG('L','U','H',' ')}, /* Tsotso -> Luyia */ + {"lts", HB_TAG('L','U','H',' ')}, /* Tachoni -> Luyia */ + {"lu", HB_TAG('L','U','B',' ')}, /* Luba-Katanga */ +/*{"lua", HB_TAG('L','U','A',' ')},*/ /* Luba-Lulua */ +/*{"luo", HB_TAG('L','U','O',' ')},*/ /* Luo (Kenya and Tanzania) */ + {"lus", HB_TAG('M','I','Z',' ')}, /* Lushai -> Mizo */ + {"luy", HB_TAG('L','U','H',' ')}, /* Luyia [macrolanguage] */ + {"luz", HB_TAG('L','R','C',' ')}, /* Southern Luri -> Luri */ + {"lv", HB_TAG('L','V','I',' ')}, /* Latvian [macrolanguage] */ + {"lvs", HB_TAG('L','V','I',' ')}, /* Standard Latvian -> Latvian */ + {"lwg", HB_TAG('L','U','H',' ')}, /* Wanga -> Luyia */ + {"lzh", HB_TAG('Z','H','T',' ')}, /* Literary Chinese -> Chinese Traditional */ + {"lzz", HB_TAG('L','A','Z',' ')}, /* Laz */ +/*{"mad", HB_TAG('M','A','D',' ')},*/ /* Madurese -> Madura */ +/*{"mag", HB_TAG('M','A','G',' ')},*/ /* Magahi */ + {"mai", HB_TAG('M','T','H',' ')}, /* Maithili */ + {"mak", HB_TAG('M','K','R',' ')}, /* Makasar */ +/*{"mam", HB_TAG('M','A','M',' ')},*/ /* Mam */ + {"man", HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ + {"max", HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ +/*{"mbo", HB_TAG('M','B','O',' ')},*/ /* Mbo (Cameroon) */ + {"mct", HB_TAG('B','T','I',' ')}, /* Mengisa -> Beti */ + {"mdf", HB_TAG('M','O','K',' ')}, /* Moksha */ +/*{"mdr", HB_TAG('M','D','R',' ')},*/ /* Mandar */ + {"mdy", HB_TAG('M','L','E',' ')}, /* Male (Ethiopia) */ + {"men", HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */ + {"meo", HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */ +/*{"mer", HB_TAG('M','E','R',' ')},*/ /* Meru */ +/*{"mfa", HB_TAG('M','F','A',' ')},*/ /* Pattani Malay */ + {"mfb", HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */ +/*{"mfe", HB_TAG('M','F','E',' ')},*/ /* Morisyen */ + {"mg", HB_TAG('M','L','G',' ')}, /* Malagasy [macrolanguage] */ + {"mh", HB_TAG('M','A','H',' ')}, /* Marshallese */ + {"mhr", HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */ + {"mhv", HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */ + {"mi", HB_TAG('M','R','I',' ')}, /* Maori */ +/*{"min", HB_TAG('M','I','N',' ')},*/ /* Minangkabau */ + {"mk", HB_TAG('M','K','D',' ')}, /* Macedonian */ + {"mku", HB_TAG('M','N','K',' ')}, /* Konyanka Maninka -> Maninka */ +/*{"mkw", HB_TAG('M','K','W',' ')},*/ /* Kituba (Congo) */ + {"ml", HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */ + {"ml", HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */ + {"mlq", HB_TAG('M','L','N',' ')}, /* Western Maninkakan -> Malinke */ + {"mlq", HB_TAG('M','N','K',' ')}, /* Western Maninkakan -> Maninka */ + {"mmr", HB_TAG('H','M','N',' ')}, /* Western Xiangxi Miao -> Hmong */ + {"mn", HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */ + {"mnc", HB_TAG('M','C','H',' ')}, /* Manchu */ +/*{"mni", HB_TAG('M','N','I',' ')},*/ /* Manipuri */ + {"mnk", HB_TAG('M','N','D',' ')}, /* Mandinka */ + {"mnk", HB_TAG('M','N','K',' ')}, /* Mandinka -> Maninka */ + {"mnp", HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese Simplified */ + {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */ + {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */ + {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */ +/*{"moh", HB_TAG('M','O','H',' ')},*/ /* Mohawk */ +/*{"mos", HB_TAG('M','O','S',' ')},*/ /* Mossi */ + {"mpe", HB_TAG('M','A','J',' ')}, /* Majang */ + {"mqg", HB_TAG('M','L','Y',' ')}, /* Kota Bangun Kutai Malay -> Malay */ + {"mr", HB_TAG('M','A','R',' ')}, /* Marathi */ + {"mrh", HB_TAG('Q','I','N',' ')}, /* Mara Chin -> Chin */ + {"mrj", HB_TAG('H','M','A',' ')}, /* Western Mari -> High Mari */ + {"ms", HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */ + {"msc", HB_TAG('M','N','K',' ')}, /* Sankaran Maninka -> Maninka */ + {"msh", HB_TAG('M','L','G',' ')}, /* Masikoro Malagasy -> Malagasy */ + {"msi", HB_TAG('M','L','Y',' ')}, /* Sabah Malay -> Malay */ + {"mt", HB_TAG('M','T','S',' ')}, /* Maltese */ + {"mtr", HB_TAG('M','A','W',' ')}, /* Mewari -> Marwari */ + {"mui", HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ + {"mup", HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ + {"muq", HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ +/*{"mus", HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ + {"mvb", HB_TAG('A','T','H',' ')}, /* Mattole -> Athapaskan */ + {"mve", HB_TAG('M','A','W',' ')}, /* Marwari (Pakistan) */ + {"mvf", HB_TAG('M','N','G',' ')}, /* Peripheral Mongolian -> Mongolian */ + {"mwk", HB_TAG('M','N','K',' ')}, /* Kita Maninkakan -> Maninka */ +/*{"mwl", HB_TAG('M','W','L',' ')},*/ /* Mirandese */ + {"mwr", HB_TAG('M','A','W',' ')}, /* Marwari [macrolanguage] */ +/*{"mww", HB_TAG('M','W','W',' ')},*/ /* Hmong Daw */ + {"my", HB_TAG('B','R','M',' ')}, /* Burmese */ + {"mym", HB_TAG('M','E','N',' ')}, /* Me’en */ +/*{"myn", HB_TAG('M','Y','N',' ')},*/ /* Mayan [family] */ + {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ + {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ +/*{"mzn", HB_TAG('M','Z','N',' ')},*/ /* Mazanderani */ + {"na", HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */ +/*{"nag", HB_TAG('N','A','G',' ')},*/ /* Naga Pidgin -> Naga-Assamese */ +/*{"nah", HB_TAG('N','A','H',' ')},*/ /* Nahuatl [family] */ + {"nan", HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese Simplified */ +/*{"nap", HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ + {"nb", HB_TAG('N','O','R',' ')}, /* Norwegian Bokmål -> Norwegian */ + {"nd", HB_TAG('N','D','B',' ')}, /* North Ndebele -> Ndebele */ +/*{"ndc", HB_TAG('N','D','C',' ')},*/ /* Ndau */ +/*{"nds", HB_TAG('N','D','S',' ')},*/ /* Low Saxon */ + {"ne", HB_TAG('N','E','P',' ')}, /* Nepali [macrolanguage] */ +/*{"new", HB_TAG('N','E','W',' ')},*/ /* Newari */ + {"ng", HB_TAG('N','D','G',' ')}, /* Ndonga */ +/*{"nga", HB_TAG('N','G','A',' ')},*/ /* Ngbaka */ + {"ngl", HB_TAG('L','M','W',' ')}, /* Lomwe */ + {"ngo", HB_TAG('S','X','T',' ')}, /* Ngoni -> Sutu */ + {"nhd", HB_TAG('G','U','A',' ')}, /* Chiripá -> Guarani */ + {"niq", HB_TAG('K','A','L',' ')}, /* Nandi -> Kalenjin */ +/*{"niu", HB_TAG('N','I','U',' ')},*/ /* Niuean */ + {"niv", HB_TAG('G','I','L',' ')}, /* Gilyak */ + {"njz", HB_TAG('N','I','S',' ')}, /* Nyishi -> Nisi */ + {"nl", HB_TAG('N','L','D',' ')}, /* Dutch */ + {"nle", HB_TAG('L','U','H',' ')}, /* East Nyala -> Luyia */ + {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ + {"nod", HB_TAG('N','T','A',' ')}, /* Northern Thai -> Northern Tai */ +/*{"noe", HB_TAG('N','O','E',' ')},*/ /* Nimadi */ +/*{"nog", HB_TAG('N','O','G',' ')},*/ /* Nogai */ +/*{"nov", HB_TAG('N','O','V',' ')},*/ /* Novial */ + {"npi", HB_TAG('N','E','P',' ')}, /* Nepali */ + {"nqo", HB_TAG('N','K','O',' ')}, /* N’Ko */ + {"nr", HB_TAG('N','D','B',' ')}, /* South Ndebele -> Ndebele */ + {"nsk", HB_TAG('N','A','S',' ')}, /* Naskapi */ +/*{"nso", HB_TAG('N','S','O',' ')},*/ /* Pedi -> Sotho, Northern */ + {"nv", HB_TAG('N','A','V',' ')}, /* Navajo */ + {"nv", HB_TAG('A','T','H',' ')}, /* Navajo -> Athapaskan */ + {"ny", HB_TAG('C','H','I',' ')}, /* Chichewa (Chewa, Nyanja) */ + {"nyd", HB_TAG('L','U','H',' ')}, /* Nyore -> Luyia */ +/*{"nym", HB_TAG('N','Y','M',' ')},*/ /* Nyamwezi */ + {"nyn", HB_TAG('N','K','L',' ')}, /* Nyankole */ +/*{"nza", HB_TAG('N','Z','A',' ')},*/ /* Tigon Mbembe -> Mbembe Tigon */ + {"oc", HB_TAG('O','C','I',' ')}, /* Occitan (post 1500) */ + {"oj", HB_TAG('O','J','B',' ')}, /* Ojibwa [macrolanguage] -> Ojibway */ +/*{"ojb", HB_TAG('O','J','B',' ')},*/ /* Northwestern Ojibwa -> Ojibway */ + {"ojc", HB_TAG('O','J','B',' ')}, /* Central Ojibwa -> Ojibway */ + {"ojg", HB_TAG('O','J','B',' ')}, /* Eastern Ojibwa -> Ojibway */ + {"ojs", HB_TAG('O','C','R',' ')}, /* Severn Ojibwa -> Oji-Cree */ + {"ojw", HB_TAG('O','J','B',' ')}, /* Western Ojibwa -> Ojibway */ + {"oki", HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */ + {"okm", HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */ + {"om", HB_TAG('O','R','O',' ')}, /* Oromo [macrolanguage] */ + {"or", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) [macrolanguage] */ + {"orc", HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */ + {"orn", HB_TAG('M','L','Y',' ')}, /* Orang Kanaq -> Malay */ + {"ors", HB_TAG('M','L','Y',' ')}, /* Orang Seletar -> Malay */ + {"ory", HB_TAG('O','R','I',' ')}, /* Odia (formerly Oriya) */ + {"os", HB_TAG('O','S','S',' ')}, /* Ossetian */ + {"otw", HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ + {"pa", HB_TAG('P','A','N',' ')}, /* Punjabi */ +/*{"pag", HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ +/*{"pam", HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ + {"pap", HB_TAG('P','A','P','0')}, /* Papiamento -> Papiamentu */ +/*{"pau", HB_TAG('P','A','U',' ')},*/ /* Palauan */ + {"pbt", HB_TAG('P','A','S',' ')}, /* Southern Pashto -> Pashto */ + {"pbu", HB_TAG('P','A','S',' ')}, /* Northern Pashto -> Pashto */ +/*{"pcc", HB_TAG('P','C','C',' ')},*/ /* Bouyei */ +/*{"pcd", HB_TAG('P','C','D',' ')},*/ /* Picard */ + {"pce", HB_TAG('P','L','G',' ')}, /* Ruching Palaung -> Palaung */ + {"pck", HB_TAG('Q','I','N',' ')}, /* Paite Chin -> Chin */ +/*{"pdc", HB_TAG('P','D','C',' ')},*/ /* Pennsylvania German */ + {"pel", HB_TAG('M','L','Y',' ')}, /* Pekal -> Malay */ + {"pes", HB_TAG('F','A','R',' ')}, /* Iranian Persian -> Persian */ + {"pga", HB_TAG('A','R','A',' ')}, /* Sudanese Creole Arabic -> Arabic */ +/*{"phk", HB_TAG('P','H','K',' ')},*/ /* Phake */ + {"pi", HB_TAG('P','A','L',' ')}, /* Pali */ +/*{"pih", HB_TAG('P','I','H',' ')},*/ /* Pitcairn-Norfolk -> Norfolk */ + {"pko", HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */ + {"pl", HB_TAG('P','L','K',' ')}, /* Polish */ + {"pll", HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */ + {"plp", HB_TAG('P','A','P',' ')}, /* Palpa (retired code) */ + {"plt", HB_TAG('M','L','G',' ')}, /* Plateau Malagasy -> Malagasy */ +/*{"pms", HB_TAG('P','M','S',' ')},*/ /* Piemontese */ +/*{"pnb", HB_TAG('P','N','B',' ')},*/ /* Western Panjabi */ +/*{"poh", HB_TAG('P','O','H',' ')},*/ /* Poqomchi' -> Pocomchi */ +/*{"pon", HB_TAG('P','O','N',' ')},*/ /* Pohnpeian */ + {"ppa", HB_TAG('B','A','G',' ')}, /* Pao (retired code) -> Baghelkhandi */ +/*{"pro", HB_TAG('P','R','O',' ')},*/ /* Old Provençal (to 1500) -> Provençal / Old Provençal */ + {"prs", HB_TAG('D','R','I',' ')}, /* Dari */ + {"ps", HB_TAG('P','A','S',' ')}, /* Pashto [macrolanguage] */ + {"pse", HB_TAG('M','L','Y',' ')}, /* Central Malay -> Malay */ + {"pst", HB_TAG('P','A','S',' ')}, /* Central Pashto -> Pashto */ + {"pt", HB_TAG('P','T','G',' ')}, /* Portuguese */ +/*{"pwo", HB_TAG('P','W','O',' ')},*/ /* Pwo Western Karen -> Western Pwo Karen */ + {"qu", HB_TAG('Q','U','Z',' ')}, /* Quechua [macrolanguage] */ + {"qub", HB_TAG('Q','W','H',' ')}, /* Huallaga Huánuco Quechua -> Quechua (Peru) */ +/*{"quc", HB_TAG('Q','U','C',' ')},*/ /* K’iche’ */ + {"qud", HB_TAG('Q','V','I',' ')}, /* Calderón Highland Quichua -> Quechua (Ecuador) */ + {"quf", HB_TAG('Q','U','Z',' ')}, /* Lambayeque Quechua -> Quechua */ + {"qug", HB_TAG('Q','V','I',' ')}, /* Chimborazo Highland Quichua -> Quechua (Ecuador) */ +/*{"quh", HB_TAG('Q','U','H',' ')},*/ /* South Bolivian Quechua -> Quechua (Bolivia) */ + {"quk", HB_TAG('Q','U','Z',' ')}, /* Chachapoyas Quechua -> Quechua */ + {"qul", HB_TAG('Q','U','Z',' ')}, /* North Bolivian Quechua -> Quechua */ + {"qup", HB_TAG('Q','V','I',' ')}, /* Southern Pastaza Quechua -> Quechua (Ecuador) */ + {"qur", HB_TAG('Q','W','H',' ')}, /* Yanahuanca Pasco Quechua -> Quechua (Peru) */ + {"qus", HB_TAG('Q','U','H',' ')}, /* Santiago del Estero Quichua -> Quechua (Bolivia) */ + {"quw", HB_TAG('Q','V','I',' ')}, /* Tena Lowland Quichua -> Quechua (Ecuador) */ + {"qux", HB_TAG('Q','W','H',' ')}, /* Yauyos Quechua -> Quechua (Peru) */ + {"quy", HB_TAG('Q','U','Z',' ')}, /* Ayacucho Quechua -> Quechua */ +/*{"quz", HB_TAG('Q','U','Z',' ')},*/ /* Cusco Quechua -> Quechua */ + {"qva", HB_TAG('Q','W','H',' ')}, /* Ambo-Pasco Quechua -> Quechua (Peru) */ + {"qvc", HB_TAG('Q','U','Z',' ')}, /* Cajamarca Quechua -> Quechua */ + {"qve", HB_TAG('Q','U','Z',' ')}, /* Eastern Apurímac Quechua -> Quechua */ + {"qvh", HB_TAG('Q','W','H',' ')}, /* Huamalíes-Dos de Mayo Huánuco Quechua -> Quechua (Peru) */ +/*{"qvi", HB_TAG('Q','V','I',' ')},*/ /* Imbabura Highland Quichua -> Quechua (Ecuador) */ + {"qvj", HB_TAG('Q','V','I',' ')}, /* Loja Highland Quichua -> Quechua (Ecuador) */ + {"qvl", HB_TAG('Q','W','H',' ')}, /* Cajatambo North Lima Quechua -> Quechua (Peru) */ + {"qvm", HB_TAG('Q','W','H',' ')}, /* Margos-Yarowilca-Lauricocha Quechua -> Quechua (Peru) */ + {"qvn", HB_TAG('Q','W','H',' ')}, /* North Junín Quechua -> Quechua (Peru) */ + {"qvo", HB_TAG('Q','V','I',' ')}, /* Napo Lowland Quechua -> Quechua (Ecuador) */ + {"qvp", HB_TAG('Q','W','H',' ')}, /* Pacaraos Quechua -> Quechua (Peru) */ + {"qvs", HB_TAG('Q','U','Z',' ')}, /* San Martín Quechua -> Quechua */ + {"qvw", HB_TAG('Q','W','H',' ')}, /* Huaylla Wanca Quechua -> Quechua (Peru) */ + {"qvz", HB_TAG('Q','V','I',' ')}, /* Northern Pastaza Quichua -> Quechua (Ecuador) */ + {"qwa", HB_TAG('Q','W','H',' ')}, /* Corongo Ancash Quechua -> Quechua (Peru) */ + {"qwc", HB_TAG('Q','U','Z',' ')}, /* Classical Quechua -> Quechua */ +/*{"qwh", HB_TAG('Q','W','H',' ')},*/ /* Huaylas Ancash Quechua -> Quechua (Peru) */ + {"qws", HB_TAG('Q','W','H',' ')}, /* Sihuas Ancash Quechua -> Quechua (Peru) */ + {"qxa", HB_TAG('Q','W','H',' ')}, /* Chiquián Ancash Quechua -> Quechua (Peru) */ + {"qxc", HB_TAG('Q','W','H',' ')}, /* Chincha Quechua -> Quechua (Peru) */ + {"qxh", HB_TAG('Q','W','H',' ')}, /* Panao Huánuco Quechua -> Quechua (Peru) */ + {"qxl", HB_TAG('Q','V','I',' ')}, /* Salasaca Highland Quichua -> Quechua (Ecuador) */ + {"qxn", HB_TAG('Q','W','H',' ')}, /* Northern Conchucos Ancash Quechua -> Quechua (Peru) */ + {"qxo", HB_TAG('Q','W','H',' ')}, /* Southern Conchucos Ancash Quechua -> Quechua (Peru) */ + {"qxp", HB_TAG('Q','U','Z',' ')}, /* Puno Quechua -> Quechua */ + {"qxr", HB_TAG('Q','V','I',' ')}, /* Cañar Highland Quichua -> Quechua (Ecuador) */ + {"qxt", HB_TAG('Q','W','H',' ')}, /* Santa Ana de Tusi Pasco Quechua -> Quechua (Peru) */ + {"qxu", HB_TAG('Q','U','Z',' ')}, /* Arequipa-La Unión Quechua -> Quechua */ + {"qxw", HB_TAG('Q','W','H',' ')}, /* Jauja Wanca Quechua -> Quechua (Peru) */ + {"rag", HB_TAG('L','U','H',' ')}, /* Logooli -> Luyia */ +/*{"raj", HB_TAG('R','A','J',' ')},*/ /* Rajasthani [macrolanguage] */ +/*{"rar", HB_TAG('R','A','R',' ')},*/ /* Rarotongan */ + {"rbb", HB_TAG('P','L','G',' ')}, /* Rumai Palaung -> Palaung */ + {"rbl", HB_TAG('B','I','K',' ')}, /* Miraya Bikol -> Bikol */ +/*{"rej", HB_TAG('R','E','J',' ')},*/ /* Rejang */ +/*{"ria", HB_TAG('R','I','A',' ')},*/ /* Riang (India) */ +/*{"rif", HB_TAG('R','I','F',' ')},*/ /* Tarifit */ +/*{"rit", HB_TAG('R','I','T',' ')},*/ /* Ritharrngu -> Ritarungo */ + {"rki", HB_TAG('A','R','K',' ')}, /* Rakhine */ +/*{"rkw", HB_TAG('R','K','W',' ')},*/ /* Arakwal */ + {"rm", HB_TAG('R','M','S',' ')}, /* Romansh */ + {"rmc", HB_TAG('R','O','Y',' ')}, /* Carpathian Romani -> Romany */ + {"rmf", HB_TAG('R','O','Y',' ')}, /* Kalo Finnish Romani -> Romany */ + {"rml", HB_TAG('R','O','Y',' ')}, /* Baltic Romani -> Romany */ + {"rmn", HB_TAG('R','O','Y',' ')}, /* Balkan Romani -> Romany */ + {"rmo", HB_TAG('R','O','Y',' ')}, /* Sinte Romani -> Romany */ + {"rmw", HB_TAG('R','O','Y',' ')}, /* Welsh Romani -> Romany */ +/*{"rmy", HB_TAG('R','M','Y',' ')},*/ /* Vlax Romani */ + {"rmz", HB_TAG('A','R','K',' ')}, /* Marma -> Rakhine */ + {"rn", HB_TAG('R','U','N',' ')}, /* Rundi */ + {"rnl", HB_TAG('H','A','L',' ')}, /* Ranglong -> Halam (Falam Chin) */ + {"ro", HB_TAG('R','O','M',' ')}, /* Romanian */ + {"rom", HB_TAG('R','O','Y',' ')}, /* Romany [macrolanguage] */ +/*{"rtm", HB_TAG('R','T','M',' ')},*/ /* Rotuman */ + {"ru", HB_TAG('R','U','S',' ')}, /* Russian */ + {"rue", HB_TAG('R','S','Y',' ')}, /* Rusyn */ +/*{"rup", HB_TAG('R','U','P',' ')},*/ /* Aromanian */ + {"rw", HB_TAG('R','U','A',' ')}, /* Kinyarwanda */ + {"rwr", HB_TAG('M','A','W',' ')}, /* Marwari (India) */ + {"sa", HB_TAG('S','A','N',' ')}, /* Sanskrit */ + {"sah", HB_TAG('Y','A','K',' ')}, /* Yakut -> Sakha */ + {"sam", HB_TAG('P','A','A',' ')}, /* Samaritan Aramaic -> Palestinian Aramaic */ +/*{"sas", HB_TAG('S','A','S',' ')},*/ /* Sasak */ +/*{"sat", HB_TAG('S','A','T',' ')},*/ /* Santali */ + {"sc", HB_TAG('S','R','D',' ')}, /* Sardinian [macrolanguage] */ + {"sck", HB_TAG('S','A','D',' ')}, /* Sadri */ +/*{"scn", HB_TAG('S','C','N',' ')},*/ /* Sicilian */ +/*{"sco", HB_TAG('S','C','O',' ')},*/ /* Scots */ + {"scs", HB_TAG('S','C','S',' ')}, /* North Slavey */ + {"scs", HB_TAG('S','L','A',' ')}, /* North Slavey -> Slavey */ + {"scs", HB_TAG('A','T','H',' ')}, /* North Slavey -> Athapaskan */ + {"sd", HB_TAG('S','N','D',' ')}, /* Sindhi */ + {"sdc", HB_TAG('S','R','D',' ')}, /* Sassarese Sardinian -> Sardinian */ + {"sdh", HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */ + {"sdn", HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */ + {"se", HB_TAG('N','S','M',' ')}, /* Northern Sami */ + {"seh", HB_TAG('S','N','A',' ')}, /* Sena */ + {"sek", HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */ +/*{"sel", HB_TAG('S','E','L',' ')},*/ /* Selkup */ + {"sez", HB_TAG('Q','I','N',' ')}, /* Senthang Chin -> Chin */ + {"sfm", HB_TAG('H','M','N',' ')}, /* Small Flowery Miao -> Hmong */ + {"sg", HB_TAG('S','G','O',' ')}, /* Sango */ +/*{"sga", HB_TAG('S','G','A',' ')},*/ /* Old Irish (to 900) */ + {"sgc", HB_TAG('K','A','L',' ')}, /* Kipsigis -> Kalenjin */ +/*{"sgs", HB_TAG('S','G','S',' ')},*/ /* Samogitian */ + {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ + {"sgw", HB_TAG('S','G','W',' ')}, /* Sebat Bet Gurage -> Chaha Gurage (SIL fonts) */ +/*{"shi", HB_TAG('S','H','I',' ')},*/ /* Tachelhit */ +/*{"shn", HB_TAG('S','H','N',' ')},*/ /* Shan */ + {"shu", HB_TAG('A','R','A',' ')}, /* Chadian Arabic -> Arabic */ + {"si", HB_TAG('S','N','H',' ')}, /* Sinhala (Sinhalese) */ +/*{"sid", HB_TAG('S','I','D',' ')},*/ /* Sidamo */ + {"sjd", HB_TAG('K','S','M',' ')}, /* Kildin Sami */ + {"sjo", HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */ + {"sk", HB_TAG('S','K','Y',' ')}, /* Slovak */ + {"skg", HB_TAG('M','L','G',' ')}, /* Sakalava Malagasy -> Malagasy */ + {"skr", HB_TAG('S','R','K',' ')}, /* Saraiki */ + {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */ + {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */ + {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */ + {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */ + {"smn", HB_TAG('I','S','M',' ')}, /* Inari Sami */ + {"sms", HB_TAG('S','K','S',' ')}, /* Skolt Sami */ + {"sn", HB_TAG('S','N','A','0')}, /* Shona */ +/*{"snk", HB_TAG('S','N','K',' ')},*/ /* Soninke */ + {"so", HB_TAG('S','M','L',' ')}, /* Somali */ +/*{"sop", HB_TAG('S','O','P',' ')},*/ /* Songe */ + {"spv", HB_TAG('O','R','I',' ')}, /* Sambalpuri -> Odia (formerly Oriya) */ + {"spy", HB_TAG('K','A','L',' ')}, /* Sabaot -> Kalenjin */ + {"sq", HB_TAG('S','Q','I',' ')}, /* Albanian [macrolanguage] */ + {"sr", HB_TAG('S','R','B',' ')}, /* Serbian */ + {"src", HB_TAG('S','R','D',' ')}, /* Logudorese Sardinian -> Sardinian */ + {"sro", HB_TAG('S','R','D',' ')}, /* Campidanese Sardinian -> Sardinian */ +/*{"srr", HB_TAG('S','R','R',' ')},*/ /* Serer */ + {"srs", HB_TAG('A','T','H',' ')}, /* Sarsi -> Athapaskan */ + {"ss", HB_TAG('S','W','Z',' ')}, /* Swati */ + {"ssh", HB_TAG('A','R','A',' ')}, /* Shihhi Arabic -> Arabic */ + {"st", HB_TAG('S','O','T',' ')}, /* Southern Sotho -> Sotho, Southern */ +/*{"stq", HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */ + {"stv", HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */ + {"su", HB_TAG('S','U','N',' ')}, /* Sundanese */ +/*{"suk", HB_TAG('S','U','K',' ')},*/ /* Sukuma */ + {"suq", HB_TAG('S','U','R',' ')}, /* Suri */ + {"sv", HB_TAG('S','V','E',' ')}, /* Swedish */ +/*{"sva", HB_TAG('S','V','A',' ')},*/ /* Svan */ + {"sw", HB_TAG('S','W','K',' ')}, /* Swahili [macrolanguage] */ + {"swb", HB_TAG('C','M','R',' ')}, /* Maore Comorian -> Comorian */ + {"swc", HB_TAG('S','W','K',' ')}, /* Congo Swahili -> Swahili */ + {"swh", HB_TAG('S','W','K',' ')}, /* Swahili */ + {"swv", HB_TAG('M','A','W',' ')}, /* Shekhawati -> Marwari */ +/*{"sxu", HB_TAG('S','X','U',' ')},*/ /* Upper Saxon */ + {"syc", HB_TAG('S','Y','R',' ')}, /* Classical Syriac -> Syriac */ +/*{"syl", HB_TAG('S','Y','L',' ')},*/ /* Sylheti */ +/*{"syr", HB_TAG('S','Y','R',' ')},*/ /* Syriac [macrolanguage] */ +/*{"szl", HB_TAG('S','Z','L',' ')},*/ /* Silesian */ + {"ta", HB_TAG('T','A','M',' ')}, /* Tamil */ + {"taa", HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */ +/*{"tab", HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */ + {"taq", HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */ + {"tau", HB_TAG('A','T','H',' ')}, /* Upper Tanana -> Athapaskan */ + {"tcb", HB_TAG('A','T','H',' ')}, /* Tanacross -> Athapaskan */ + {"tce", HB_TAG('A','T','H',' ')}, /* Southern Tutchone -> Athapaskan */ + {"tcp", HB_TAG('Q','I','N',' ')}, /* Tawr Chin -> Chin */ + {"tcy", HB_TAG('T','U','L',' ')}, /* Tulu -> Tumbuka */ + {"tcz", HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */ +/*{"tdd", HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */ + {"tdx", HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */ + {"te", HB_TAG('T','E','L',' ')}, /* Telugu */ + {"tec", HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */ + {"tem", HB_TAG('T','M','N',' ')}, /* Timne -> Temne */ +/*{"tet", HB_TAG('T','E','T',' ')},*/ /* Tetum */ + {"tfn", HB_TAG('A','T','H',' ')}, /* Tanaina -> Athapaskan */ + {"tg", HB_TAG('T','A','J',' ')}, /* Tajik -> Tajiki */ + {"tgj", HB_TAG('N','I','S',' ')}, /* Tagin -> Nisi */ + {"tgx", HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */ + {"th", HB_TAG('T','H','A',' ')}, /* Thai */ + {"tht", HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */ + {"thv", HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */ + {"thz", HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */ + {"ti", HB_TAG('T','G','Y',' ')}, /* Tigrinya */ + {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ +/*{"tiv", HB_TAG('T','I','V',' ')},*/ /* Tiv */ + {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ + {"tkg", HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ + {"tl", HB_TAG('T','G','L',' ')}, /* Tagalog */ +/*{"tmh", HB_TAG('T','M','H',' ')},*/ /* Tamashek [macrolanguage] */ + {"tmw", HB_TAG('M','L','Y',' ')}, /* Temuan -> Malay */ + {"tn", HB_TAG('T','N','A',' ')}, /* Tswana */ + {"tnf", HB_TAG('D','R','I',' ')}, /* Tangshewi (retired code) -> Dari */ + {"to", HB_TAG('T','G','N',' ')}, /* Tonga (Tonga Islands) -> Tongan */ + {"tod", HB_TAG('T','O','D','0')}, /* Toma */ + {"toi", HB_TAG('T','N','G',' ')}, /* Tonga (Zambia) */ + {"tol", HB_TAG('A','T','H',' ')}, /* Tolowa -> Athapaskan */ +/*{"tpi", HB_TAG('T','P','I',' ')},*/ /* Tok Pisin */ + {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ + {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ + {"tru", HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ + {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ +/*{"tsj", HB_TAG('T','S','J',' ')},*/ /* Tshangla */ + {"tt", HB_TAG('T','A','T',' ')}, /* Tatar */ + {"ttm", HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */ + {"ttq", HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */ +/*{"tum", HB_TAG('T','U','M',' ')},*/ /* Tumbuka -> Tulu */ + {"tuu", HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */ + {"tuy", HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */ +/*{"tvl", HB_TAG('T','V','L',' ')},*/ /* Tuvalu */ + {"tw", HB_TAG('T','W','I',' ')}, /* Twi */ + {"tw", HB_TAG('A','K','A',' ')}, /* Twi -> Akan */ + {"txc", HB_TAG('A','T','H',' ')}, /* Tsetsaut -> Athapaskan */ + {"txy", HB_TAG('M','L','G',' ')}, /* Tanosy Malagasy -> Malagasy */ + {"ty", HB_TAG('T','H','T',' ')}, /* Tahitian */ + {"tyv", HB_TAG('T','U','V',' ')}, /* Tuvinian -> Tuvin */ +/*{"tyz", HB_TAG('T','Y','Z',' ')},*/ /* Tày */ +/*{"tzm", HB_TAG('T','Z','M',' ')},*/ /* Central Atlas Tamazight -> Tamazight */ +/*{"tzo", HB_TAG('T','Z','O',' ')},*/ /* Tzotzil */ + {"ubl", HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */ +/*{"udm", HB_TAG('U','D','M',' ')},*/ /* Udmurt */ + {"ug", HB_TAG('U','Y','G',' ')}, /* Uyghur */ + {"uk", HB_TAG('U','K','R',' ')}, /* Ukrainian */ + {"uki", HB_TAG('K','U','I',' ')}, /* Kui (India) */ +/*{"umb", HB_TAG('U','M','B',' ')},*/ /* Umbundu */ + {"unr", HB_TAG('M','U','N',' ')}, /* Mundari */ + {"ur", HB_TAG('U','R','D',' ')}, /* Urdu */ + {"urk", HB_TAG('M','L','Y',' ')}, /* Urak Lawoi' -> Malay */ + {"uz", HB_TAG('U','Z','B',' ')}, /* Uzbek [macrolanguage] */ + {"uzn", HB_TAG('U','Z','B',' ')}, /* Northern Uzbek -> Uzbek */ + {"uzs", HB_TAG('U','Z','B',' ')}, /* Southern Uzbek -> Uzbek */ + {"ve", HB_TAG('V','E','N',' ')}, /* Venda */ +/*{"vec", HB_TAG('V','E','C',' ')},*/ /* Venetian */ + {"vi", HB_TAG('V','I','T',' ')}, /* Vietnamese */ + {"vkk", HB_TAG('M','L','Y',' ')}, /* Kaur -> Malay */ + {"vkt", HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */ + {"vls", HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */ + {"vmw", HB_TAG('M','A','K',' ')}, /* Makhuwa */ + {"vo", HB_TAG('V','O','L',' ')}, /* Volapük */ +/*{"vro", HB_TAG('V','R','O',' ')},*/ /* Võro */ + {"wa", HB_TAG('W','L','N',' ')}, /* Walloon */ +/*{"war", HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */ + {"wbm", HB_TAG('W','A',' ',' ')}, /* Wa */ + {"wbr", HB_TAG('W','A','G',' ')}, /* Wagdi */ + {"wlc", HB_TAG('C','M','R',' ')}, /* Mwali Comorian -> Comorian */ + {"wle", HB_TAG('S','I','G',' ')}, /* Wolane -> Silte Gurage */ + {"wlk", HB_TAG('A','T','H',' ')}, /* Wailaki -> Athapaskan */ + {"wni", HB_TAG('C','M','R',' ')}, /* Ndzwani Comorian -> Comorian */ + {"wo", HB_TAG('W','L','F',' ')}, /* Wolof */ + {"wry", HB_TAG('M','A','W',' ')}, /* Merwari -> Marwari */ + {"wsg", HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */ +/*{"wtm", HB_TAG('W','T','M',' ')},*/ /* Mewati */ + {"wuu", HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese Simplified */ + {"xal", HB_TAG('K','L','M',' ')}, /* Kalmyk */ + {"xal", HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */ + {"xan", HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */ + {"xh", HB_TAG('X','H','S',' ')}, /* Xhosa */ +/*{"xjb", HB_TAG('X','J','B',' ')},*/ /* Minjungbal -> Minjangbal */ +/*{"xkf", HB_TAG('X','K','F',' ')},*/ /* Khengkha */ + {"xmm", HB_TAG('M','L','Y',' ')}, /* Manado Malay -> Malay */ + {"xmv", HB_TAG('M','L','G',' ')}, /* Antankarana Malagasy -> Malagasy */ + {"xmw", HB_TAG('M','L','G',' ')}, /* Tsimihety Malagasy -> Malagasy */ + {"xnr", HB_TAG('D','G','R',' ')}, /* Kangri -> Dogri */ +/*{"xog", HB_TAG('X','O','G',' ')},*/ /* Soga */ +/*{"xpe", HB_TAG('X','P','E',' ')},*/ /* Liberia Kpelle -> Kpelle (Liberia) */ + {"xsl", HB_TAG('S','S','L',' ')}, /* South Slavey */ + {"xsl", HB_TAG('S','L','A',' ')}, /* South Slavey -> Slavey */ + {"xsl", HB_TAG('A','T','H',' ')}, /* South Slavey -> Athapaskan */ + {"xst", HB_TAG('S','I','G',' ')}, /* Silt'e (retired code) -> Silte Gurage */ + {"xwo", HB_TAG('T','O','D',' ')}, /* Written Oirat -> Todo */ +/*{"yao", HB_TAG('Y','A','O',' ')},*/ /* Yao */ +/*{"yap", HB_TAG('Y','A','P',' ')},*/ /* Yapese */ + {"ybd", HB_TAG('A','R','K',' ')}, /* Yangbye (retired code) -> Rakhine */ + {"ydd", HB_TAG('J','I','I',' ')}, /* Eastern Yiddish -> Yiddish */ + {"yi", HB_TAG('J','I','I',' ')}, /* Yiddish [macrolanguage] */ + {"yih", HB_TAG('J','I','I',' ')}, /* Western Yiddish -> Yiddish */ + {"yo", HB_TAG('Y','B','A',' ')}, /* Yoruba */ + {"yos", HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */ + {"yrk", HB_TAG('T','N','E',' ')}, /* Nenets -> Tundra Nenets */ + {"yrk", HB_TAG('F','N','E',' ')}, /* Nenets -> Forest Nenets */ + {"yue", HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Hong Kong SAR */ + {"za", HB_TAG('Z','H','A',' ')}, /* Zhuang [macrolanguage] */ + {"zch", HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */ + {"zdj", HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */ +/*{"zea", HB_TAG('Z','E','A',' ')},*/ /* Zeeuws -> Zealandic */ + {"zeh", HB_TAG('Z','H','A',' ')}, /* Eastern Hongshuihe Zhuang -> Zhuang */ + {"zgb", HB_TAG('Z','H','A',' ')}, /* Guibei Zhuang -> Zhuang */ +/*{"zgh", HB_TAG('Z','G','H',' ')},*/ /* Standard Moroccan Tamazight */ + {"zgm", HB_TAG('Z','H','A',' ')}, /* Minz Zhuang -> Zhuang */ + {"zgn", HB_TAG('Z','H','A',' ')}, /* Guibian Zhuang -> Zhuang */ + {"zh", HB_TAG('Z','H','S',' ')}, /* Chinese [macrolanguage] -> Chinese Simplified */ + {"zhd", HB_TAG('Z','H','A',' ')}, /* Dai Zhuang -> Zhuang */ + {"zhn", HB_TAG('Z','H','A',' ')}, /* Nong Zhuang -> Zhuang */ + {"zlj", HB_TAG('Z','H','A',' ')}, /* Liujiang Zhuang -> Zhuang */ + {"zlm", HB_TAG('M','L','Y',' ')}, /* Malay */ + {"zln", HB_TAG('Z','H','A',' ')}, /* Lianshan Zhuang -> Zhuang */ + {"zlq", HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ + {"zmi", HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ + {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ + {"zom", HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ + {"zqe", HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ + {"zsm", HB_TAG('M','L','Y',' ')}, /* Standard Malay -> Malay */ + {"zu", HB_TAG('Z','U','L',' ')}, /* Zulu */ + {"zum", HB_TAG('L','R','C',' ')}, /* Kumzari -> Luri */ + {"zyb", HB_TAG('Z','H','A',' ')}, /* Yongbei Zhuang -> Zhuang */ + {"zyg", HB_TAG('Z','H','A',' ')}, /* Yang Zhuang -> Zhuang */ + {"zyj", HB_TAG('Z','H','A',' ')}, /* Youjiang Zhuang -> Zhuang */ + {"zyn", HB_TAG('Z','H','A',' ')}, /* Yongnan Zhuang -> Zhuang */ +/*{"zza", HB_TAG('Z','Z','A',' ')},*/ /* Zazaki [macrolanguage] */ + {"zzj", HB_TAG('Z','H','A',' ')}, /* Zuojiang Zhuang -> Zhuang */ }; -static_assert (HB_OT_MAX_TAGS_PER_LANGUAGE == 3u, ""); - /** * hb_ot_tags_from_complex_language: * @lang_str: a BCP 47 language tag to convert. @@ -1185,6 +1188,20 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } + if (lang_matches (&lang_str[1], "np-hant-hk")) + { + /* Northern Ping Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hant-mo")) + { + /* Northern Ping Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } if (lang_matches (&lang_str[1], "px-hant-hk")) { /* Pu-Xian Chinese */ @@ -1199,6 +1216,20 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } + if (lang_matches (&lang_str[1], "sp-hant-hk")) + { + /* Southern Ping Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sp-hant-mo")) + { + /* Southern Ping Chinese */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } if (lang_matches (&lang_str[1], "zh-hant-hk")) { /* Huizhou Chinese */ @@ -1269,6 +1300,20 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } + if (lang_matches (&lang_str[1], "np-hans")) + { + /* Northern Ping Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "np-hant")) + { + /* Northern Ping Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } if (lang_matches (&lang_str[1], "px-hans")) { /* Pu-Xian Chinese */ @@ -1283,6 +1328,20 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } + if (lang_matches (&lang_str[1], "sp-hans")) + { + /* Southern Ping Chinese */ + tags[0] = HB_TAG('Z','H','S',' '); /* Chinese Simplified */ + *count = 1; + return true; + } + if (lang_matches (&lang_str[1], "sp-hant")) + { + /* Southern Ping Chinese */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } if (lang_matches (&lang_str[1], "zh-hans")) { /* Huizhou Chinese */ @@ -1383,6 +1442,30 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Northern Ping Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Northern Ping Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "np-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Northern Ping Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } if (0 == strncmp (&lang_str[1], "px-", 3) && subtag_matches (lang_str, limit, "-hk")) { @@ -1407,6 +1490,30 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } + if (0 == strncmp (&lang_str[1], "sp-", 3) + && subtag_matches (lang_str, limit, "-hk")) + { + /* Southern Ping Chinese; Hong Kong */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sp-", 3) + && subtag_matches (lang_str, limit, "-mo")) + { + /* Southern Ping Chinese; Macao */ + tags[0] = HB_TAG('Z','H','H',' '); /* Chinese, Hong Kong SAR */ + *count = 1; + return true; + } + if (0 == strncmp (&lang_str[1], "sp-", 3) + && subtag_matches (lang_str, limit, "-tw")) + { + /* Southern Ping Chinese; Taiwan, Province of China */ + tags[0] = HB_TAG('Z','H','T',' '); /* Chinese Traditional */ + *count = 1; + return true; + } if (0 == strncmp (&lang_str[1], "zh-", 3) && subtag_matches (lang_str, limit, "-hk")) { @@ -1934,7 +2041,8 @@ hb_ot_tags_from_complex_language (const char *lang_str, * * Converts @tag to a BCP 47 language tag if it is ambiguous (it corresponds to * many language tags) and the best tag is not the alphabetically first, or if - * the best tag consists of multiple subtags. + * the best tag consists of multiple subtags, or if the best tag does not appear + * in #ot_languages. * * Return value: The #hb_language_t corresponding to the BCP 47 language tag, * or #HB_LANGUAGE_INVALID if @tag is not ambiguous. @@ -1944,6 +2052,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) { switch (tag) { + case HB_TAG('A','L','T',' '): /* Altai */ + return hb_language_from_string ("alt", -1); /* Southern Altai */ case HB_TAG('A','P','P','H'): /* Phonetic transcription—Americanist conventions */ return hb_language_from_string ("und-fonnapa", -1); /* Undetermined; North American Phonetic Alphabet */ case HB_TAG('A','R','A',' '): /* Arabic */ @@ -1962,8 +2072,6 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) return hb_language_from_string ("din", -1); /* Dinka */ case HB_TAG('D','R','I',' '): /* Dari */ return hb_language_from_string ("prs", -1); /* Dari */ - case HB_TAG('D','U','J',' '): /* Dhuwal */ - return hb_language_from_string ("dwu", -1); /* Dhuwal */ case HB_TAG('D','Z','N',' '): /* Dzongkha */ return hb_language_from_string ("dz", -1); /* Dzongkha */ case HB_TAG('E','T','I',' '): /* Estonian */ @@ -1972,6 +2080,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) return hb_language_from_string ("gon", -1); /* Gondi */ case HB_TAG('H','M','N',' '): /* Hmong */ return hb_language_from_string ("hmn", -1); /* Hmong */ + case HB_TAG('H','N','D',' '): /* Hindko */ + return hb_language_from_string ("hnd", -1); /* Southern Hindko */ case HB_TAG('I','J','O',' '): /* Ijo */ return hb_language_from_string ("ijo", -1); /* Ijo */ case HB_TAG('I','N','U',' '): /* Inuktitut */ @@ -1992,6 +2102,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) return hb_language_from_string ("kr", -1); /* Kanuri */ case HB_TAG('K','O','K',' '): /* Konkani */ return hb_language_from_string ("kok", -1); /* Konkani */ + case HB_TAG('K','U','I',' '): /* Kui */ + return hb_language_from_string ("uki", -1); /* Kui (India) */ case HB_TAG('K','U','R',' '): /* Kurdish */ return hb_language_from_string ("ku", -1); /* Kurdish */ case HB_TAG('L','U','H',' '): /* Luyia */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc index 18b5686b5c8..36ff854e3ed 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-tag.cc @@ -28,6 +28,8 @@ #include "hb.hh" +#ifndef HB_NO_OT_TAG + /* hb_script_t */ @@ -113,6 +115,7 @@ hb_ot_new_tag_to_script (hb_tag_t tag) return HB_SCRIPT_UNKNOWN; } +#ifndef HB_DISABLE_DEPRECATED void hb_ot_tags_from_script (hb_script_t script, hb_tag_t *script_tag_1, @@ -124,6 +127,7 @@ hb_ot_tags_from_script (hb_script_t script, *script_tag_1 = count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_SCRIPT; *script_tag_2 = count > 1 ? tags[1] : HB_OT_TAG_DEFAULT_SCRIPT; } +#endif /* * Complete list at: @@ -143,7 +147,9 @@ hb_ot_all_tags_from_script (hb_script_t script, hb_tag_t new_tag = hb_ot_new_tag_from_script (script); if (unlikely (new_tag != HB_OT_TAG_DEFAULT_SCRIPT)) { - tags[i++] = new_tag | '3'; + /* HB_SCRIPT_MYANMAR maps to 'mym2', but there is no 'mym3'. */ + if (new_tag != HB_TAG('m','y','m','2')) + tags[i++] = new_tag | '3'; if (*count > i) tags[i++] = new_tag; } @@ -171,24 +177,6 @@ hb_ot_tag_to_script (hb_tag_t tag) /* hb_language_t */ -static int -lang_compare_first_component (const void *pa, - const void *pb) -{ - const char *a = (const char *) pa; - const char *b = (const char *) pb; - unsigned int da, db; - const char *p; - - p = strchr (a, '-'); - da = p ? (unsigned int) (p - a) : strlen (a); - - p = strchr (b, '-'); - db = p ? (unsigned int) (p - b) : strlen (b); - - return strncmp (a, b, MAX (da, db)); -} - static bool subtag_matches (const char *lang_str, const char *limit, @@ -213,10 +201,28 @@ lang_matches (const char *lang_str, const char *spec) (lang_str[len] == '\0' || lang_str[len] == '-'); } -typedef struct { +struct LangTag +{ char language[4]; - hb_tag_t tags[HB_OT_MAX_TAGS_PER_LANGUAGE]; -} LangTag; + hb_tag_t tag; + + int cmp (const char *a) const + { + const char *b = this->language; + unsigned int da, db; + const char *p; + + p = strchr (a, '-'); + da = p ? (unsigned int) (p - a) : strlen (a); + + p = strchr (b, '-'); + db = p ? (unsigned int) (p - b) : strlen (b); + + return strncmp (a, b, hb_max (da, db)); + } + int cmp (const LangTag *that) const + { return cmp (that->language); } +}; #include "hb-ot-tag-table.hh" @@ -230,6 +236,7 @@ typedef struct { /*{"??", {HB_TAG('Y','I','C',' ')}},*/ /* Yi Classic */ /*{"zh?", {HB_TAG('Z','H','P',' ')}},*/ /* Chinese Phonetic */ +#ifndef HB_DISABLE_DEPRECATED hb_tag_t hb_ot_tag_from_language (hb_language_t language) { @@ -238,6 +245,7 @@ hb_ot_tag_from_language (hb_language_t language) hb_ot_tags_from_script_and_language (HB_SCRIPT_UNKNOWN, language, nullptr, nullptr, &count, tags); return count > 0 ? tags[0] : HB_OT_TAG_DEFAULT_LANGUAGE; } +#endif static void hb_ot_tags_from_language (const char *lang_str, @@ -246,6 +254,7 @@ hb_ot_tags_from_language (const char *lang_str, hb_tag_t *tags) { const char *s; + unsigned int tag_idx; /* Check for matches of multiple subtags. */ if (hb_ot_tags_from_complex_language (lang_str, limit, count, tags)) @@ -254,7 +263,6 @@ hb_ot_tags_from_language (const char *lang_str, /* Find a language matching in the first component. */ s = strchr (lang_str, '-'); { - const LangTag *lang_tag; if (s && limit - lang_str >= 6) { const char *extlang_end = strchr (s + 1, '-'); @@ -263,14 +271,18 @@ hb_ot_tags_from_language (const char *lang_str, ISALPHA (s[1])) lang_str = s + 1; } - lang_tag = (LangTag *) bsearch (lang_str, ot_languages, - ARRAY_LENGTH (ot_languages), sizeof (LangTag), - lang_compare_first_component); - if (lang_tag) + if (hb_sorted_array (ot_languages).bfind (lang_str, &tag_idx)) { unsigned int i; - for (i = 0; i < *count && lang_tag->tags[i] != HB_TAG_NONE; i++) - tags[i] = lang_tag->tags[i]; + while (tag_idx != 0 && + 0 == strcmp (ot_languages[tag_idx].language, ot_languages[tag_idx - 1].language)) + tag_idx--; + for (i = 0; + i < *count && + tag_idx + i < ARRAY_LENGTH (ot_languages) && + 0 == strcmp (ot_languages[tag_idx + i].language, ot_languages[tag_idx].language); + i++) + tags[i] = ot_languages[tag_idx + i].tag; *count = i; return; } @@ -295,28 +307,42 @@ parse_private_use_subtag (const char *private_use_subtag, const char *prefix, unsigned char (*normalize) (unsigned char)) { - if (private_use_subtag && count && tags && *count) - { - const char *s = strstr (private_use_subtag, prefix); - if (s) +#ifdef HB_NO_LANGUAGE_PRIVATE_SUBTAG + return false; +#endif + + if (!(private_use_subtag && count && tags && *count)) return false; + + const char *s = strstr (private_use_subtag, prefix); + if (!s) return false; + + char tag[4]; + int i; + s += strlen (prefix); + if (s[0] == '-') { + s += 1; + char c; + for (i = 0; i < 8 && ISHEX (s[i]); i++) { - char tag[4]; - int i; - s += strlen (prefix); - for (i = 0; i < 4 && ISALNUM (s[i]); i++) - tag[i] = normalize (s[i]); - if (i) - { - for (; i < 4; i++) - tag[i] = ' '; - tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]); - if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT) - tags[0] ^= ~0xDFDFDFDF; - *count = 1; - return false; - } + c = FROMHEX (s[i]); + if (i % 2 == 0) + tag[i / 2] = c << 4; + else + tag[i / 2] += c; } + if (i != 8) return false; + } else { + for (i = 0; i < 4 && ISALNUM (s[i]); i++) + tag[i] = normalize (s[i]); + if (!i) return false; + + for (; i < 4; i++) + tag[i] = ' '; } + tags[0] = HB_TAG (tag[0], tag[1], tag[2], tag[3]); + if ((tags[0] & 0xDFDFDFDF) == HB_OT_TAG_DEFAULT_SCRIPT) + tags[0] ^= ~0xDFDFDFDF; + *count = 1; return true; } @@ -384,8 +410,8 @@ hb_ot_tags_from_script_and_language (hb_script_t script, limit = s; } - needs_script = parse_private_use_subtag (private_use_subtag, script_count, script_tags, "-hbsc", TOLOWER); - needs_language = parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER); + needs_script = !parse_private_use_subtag (private_use_subtag, script_count, script_tags, "-hbsc", TOLOWER); + needs_language = !parse_private_use_subtag (private_use_subtag, language_count, language_tags, "-hbot", TOUPPER); if (needs_language && language_count && language_tags && *language_count) hb_ot_tags_from_language (lang_str, limit, language_count, language_tags); @@ -419,20 +445,31 @@ hb_ot_tag_to_language (hb_tag_t tag) } for (i = 0; i < ARRAY_LENGTH (ot_languages); i++) - if (ot_languages[i].tags[0] == tag) + if (ot_languages[i].tag == tag) return hb_language_from_string (ot_languages[i].language, -1); - /* Else return a custom language in the form of "x-hbotABCD" */ + /* Return a custom language in the form of "x-hbot-AABBCCDD". + * If it's three letters long, also guess it's ISO 639-3 and lower-case and + * prepend it (if it's not a registered tag, the private use subtags will + * ensure that calling hb_ot_tag_from_language on the result will still return + * the same tag as the original tag). + */ { - unsigned char buf[11] = "x-hbot"; - buf[6] = tag >> 24; - buf[7] = (tag >> 16) & 0xFF; - buf[8] = (tag >> 8) & 0xFF; - buf[9] = tag & 0xFF; - if (buf[9] == 0x20) - buf[9] = '\0'; - buf[10] = '\0'; - return hb_language_from_string ((char *) buf, -1); + char buf[20]; + char *str = buf; + if (ISALPHA (tag >> 24) + && ISALPHA ((tag >> 16) & 0xFF) + && ISALPHA ((tag >> 8) & 0xFF) + && (tag & 0xFF) == ' ') + { + buf[0] = TOLOWER (tag >> 24); + buf[1] = TOLOWER ((tag >> 16) & 0xFF); + buf[2] = TOLOWER ((tag >> 8) & 0xFF); + buf[3] = '-'; + str += 4; + } + snprintf (str, 16, "x-hbot-%08x", tag); + return hb_language_from_string (&*buf, -1); } } @@ -473,13 +510,14 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag, unsigned char *buf; const char *lang_str = hb_language_to_string (*language); size_t len = strlen (lang_str); - buf = (unsigned char *) malloc (len + 11); + buf = (unsigned char *) malloc (len + 16); if (unlikely (!buf)) { *language = nullptr; } else { + int shift; memcpy (buf, lang_str, len); if (lang_str[0] != 'x' || lang_str[1] != '-') { buf[len++] = '-'; @@ -490,10 +528,9 @@ hb_ot_tags_to_script_and_language (hb_tag_t script_tag, buf[len++] = 'b'; buf[len++] = 's'; buf[len++] = 'c'; - buf[len++] = script_tag >> 24; - buf[len++] = (script_tag >> 16) & 0xFF; - buf[len++] = (script_tag >> 8) & 0xFF; - buf[len++] = script_tag & 0xFF; + buf[len++] = '-'; + for (shift = 28; shift >= 0; shift -= 4) + buf[len++] = TOHEX (script_tag >> shift); *language = hb_language_from_string ((char *) buf, len); free (buf); } @@ -507,8 +544,8 @@ test_langs_sorted () { for (unsigned int i = 1; i < ARRAY_LENGTH (ot_languages); i++) { - int c = lang_compare_first_component (ot_languages[i-1].language, ot_languages[i].language); - if (c >= 0) + int c = ot_languages[i].cmp (&ot_languages[i - 1]); + if (c > 0) { fprintf (stderr, "ot_languages not sorted at index %d: %s %d %s\n", i, ot_languages[i-1].language, c, ot_languages[i].language); @@ -525,3 +562,6 @@ main () } #endif + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh index 5ae0359e5b8..2c2934dd6fa 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-avar-table.hh @@ -49,9 +49,10 @@ struct AxisValueMap } public: - F2DOT14 fromCoord; /* A normalized coordinate value obtained using - * default normalization. */ - F2DOT14 toCoord; /* The modified, normalized coordinate value. */ + F2DOT14 coords[2]; +// F2DOT14 fromCoord; /* A normalized coordinate value obtained using +// * default normalization. */ +// F2DOT14 toCoord; /* The modified, normalized coordinate value. */ public: DEFINE_SIZE_STATIC (4); @@ -59,12 +60,13 @@ struct AxisValueMap struct SegmentMaps : ArrayOf { - int map (int value) const + int map (int value, unsigned int from_offset = 0, unsigned int to_offset = 1) const { +#define fromCoord coords[from_offset] +#define toCoord coords[to_offset] /* The following special-cases are not part of OpenType, which requires * that at least -1, 0, and +1 must be mapped. But we include these as * part of a better error recovery scheme. */ - if (len < 2) { if (!len) @@ -77,7 +79,7 @@ struct SegmentMaps : ArrayOf return value - arrayZ[0].fromCoord + arrayZ[0].toCoord; unsigned int i; - unsigned int count = len; + unsigned int count = len - 1; for (i = 1; i < count && value > arrayZ[i].fromCoord; i++) ; @@ -88,11 +90,14 @@ struct SegmentMaps : ArrayOf return arrayZ[i-1].toCoord; int denom = arrayZ[i].fromCoord - arrayZ[i-1].fromCoord; - return arrayZ[i-1].toCoord + - ((arrayZ[i].toCoord - arrayZ[i-1].toCoord) * - (value - arrayZ[i-1].fromCoord) + denom/2) / denom; + return roundf (arrayZ[i-1].toCoord + ((float) (arrayZ[i].toCoord - arrayZ[i-1].toCoord) * + (value - arrayZ[i-1].fromCoord)) / denom); +#undef toCoord +#undef fromCoord } + int unmap (int value) const { return map (value, 1, 0); } + public: DEFINE_SIZE_ARRAY (2, *this); }; @@ -123,7 +128,7 @@ struct avar void map_coords (int *coords, unsigned int coords_length) const { - unsigned int count = MIN (coords_length, axisCount); + unsigned int count = hb_min (coords_length, axisCount); const SegmentMaps *map = &firstAxisSegmentMaps; for (unsigned int i = 0; i < count; i++) @@ -133,6 +138,18 @@ struct avar } } + void unmap_coords (int *coords, unsigned int coords_length) const + { + unsigned int count = hb_min (coords_length, axisCount); + + const SegmentMaps *map = &firstAxisSegmentMaps; + for (unsigned int i = 0; i < count; i++) + { + coords[i] = map->unmap (coords[i]); + map = &StructAfter (*map); + } + } + protected: FixedVersion<>version; /* Version of the avar table * initially set to 0x00010000u */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh index 3785d099b5c..e20cfa4df0f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-fvar-table.hh @@ -44,7 +44,7 @@ struct InstanceRecord { friend struct fvar; - hb_array_t get_coordinates (unsigned int axis_count) const + hb_array_t get_coordinates (unsigned int axis_count) const { return coordinatesZ.as_array (axis_count); } bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const @@ -58,7 +58,7 @@ struct InstanceRecord NameID subfamilyNameID;/* The name ID for entries in the 'name' table * that provide subfamily names for this instance. */ HBUINT16 flags; /* Reserved for future use — set to 0. */ - UnsizedArrayOf + UnsizedArrayOf coordinatesZ; /* The coordinates array for this instance. */ //NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name' // * table that provide PostScript names for this @@ -70,22 +70,83 @@ struct InstanceRecord struct AxisRecord { + int cmp (hb_tag_t key) const { return axisTag.cmp (key); } + enum { AXIS_FLAG_HIDDEN = 0x0001, }; +#ifndef HB_DISABLE_DEPRECATED + void get_axis_deprecated (hb_ot_var_axis_t *info) const + { + info->tag = axisTag; + info->name_id = axisNameID; + get_coordinates (info->min_value, info->default_value, info->max_value); + } +#endif + + void get_axis_info (unsigned axis_index, hb_ot_var_axis_info_t *info) const + { + info->axis_index = axis_index; + info->tag = axisTag; + info->name_id = axisNameID; + info->flags = (hb_ot_var_axis_flags_t) (unsigned int) flags; + get_coordinates (info->min_value, info->default_value, info->max_value); + info->reserved = 0; + } + + int normalize_axis_value (float v) const + { + float min_value, default_value, max_value; + get_coordinates (min_value, default_value, max_value); + + v = hb_clamp (v, min_value, max_value); + + if (v == default_value) + return 0; + else if (v < default_value) + v = (v - default_value) / (default_value - min_value); + else + v = (v - default_value) / (max_value - default_value); + return roundf (v * 16384.f); + } + + float unnormalize_axis_value (int v) const + { + float min_value, default_value, max_value; + get_coordinates (min_value, default_value, max_value); + + if (v == 0) + return default_value; + else if (v < 0) + return v * (default_value - min_value) / 16384.f + default_value; + else + return v * (max_value - default_value) / 16384.f + default_value; + } + + hb_ot_name_id_t get_name_id () const { return axisNameID; } + bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); return_trace (c->check_struct (this)); } - public: + protected: + void get_coordinates (float &min, float &default_, float &max) const + { + default_ = defaultValue / 65536.f; + /* Ensure order, to simplify client math. */ + min = hb_min (default_, minValue / 65536.f); + max = hb_max (default_, maxValue / 65536.f); + } + + protected: Tag axisTag; /* Tag identifying the design variation for the axis. */ - Fixed minValue; /* The minimum coordinate value for the axis. */ - Fixed defaultValue; /* The default coordinate value for the axis. */ - Fixed maxValue; /* The maximum coordinate value for the axis. */ + HBFixed minValue; /* The minimum coordinate value for the axis. */ + HBFixed defaultValue; /* The default coordinate value for the axis. */ + HBFixed maxValue; /* The maximum coordinate value for the axis. */ HBUINT16 flags; /* Axis flags. */ NameID axisNameID; /* The name ID for entries in the 'name' table that * provide a display name for this axis. */ @@ -114,54 +175,20 @@ struct fvar unsigned int get_axis_count () const { return axisCount; } - void get_axis_deprecated (unsigned int axis_index, - hb_ot_var_axis_t *info) const - { - const AxisRecord &axis = get_axes ()[axis_index]; - info->tag = axis.axisTag; - info->name_id = axis.axisNameID; - info->default_value = axis.defaultValue / 65536.; - /* Ensure order, to simplify client math. */ - info->min_value = MIN (info->default_value, axis.minValue / 65536.); - info->max_value = MAX (info->default_value, axis.maxValue / 65536.); - } - - void get_axis_info (unsigned int axis_index, - hb_ot_var_axis_info_t *info) const - { - const AxisRecord &axis = get_axes ()[axis_index]; - info->axis_index = axis_index; - info->tag = axis.axisTag; - info->name_id = axis.axisNameID; - info->flags = (hb_ot_var_axis_flags_t) (unsigned int) axis.flags; - info->default_value = axis.defaultValue / 65536.; - /* Ensure order, to simplify client math. */ - info->min_value = MIN (info->default_value, axis.minValue / 65536.); - info->max_value = MAX (info->default_value, axis.maxValue / 65536.); - info->reserved = 0; - } - +#ifndef HB_DISABLE_DEPRECATED unsigned int get_axes_deprecated (unsigned int start_offset, unsigned int *axes_count /* IN/OUT */, hb_ot_var_axis_t *axes_array /* OUT */) const { if (axes_count) { - /* TODO Rewrite as hb_array_t<>::sub-array() */ - unsigned int count = axisCount; - start_offset = MIN (start_offset, count); - - count -= start_offset; - axes_array += start_offset; - - count = MIN (count, *axes_count); - *axes_count = count; - - for (unsigned int i = 0; i < count; i++) - get_axis_deprecated (start_offset + i, axes_array + i); + hb_array_t arr = get_axes ().sub_array (start_offset, axes_count); + for (unsigned i = 0; i < arr.length; ++i) + arr[i].get_axis_deprecated (&axes_array[i]); } return axisCount; } +#endif unsigned int get_axis_infos (unsigned int start_offset, unsigned int *axes_count /* IN/OUT */, @@ -169,70 +196,38 @@ struct fvar { if (axes_count) { - /* TODO Rewrite as hb_array_t<>::sub-array() */ - unsigned int count = axisCount; - start_offset = MIN (start_offset, count); - - count -= start_offset; - axes_array += start_offset; - - count = MIN (count, *axes_count); - *axes_count = count; - - for (unsigned int i = 0; i < count; i++) - get_axis_info (start_offset + i, axes_array + i); + hb_array_t arr = get_axes ().sub_array (start_offset, axes_count); + for (unsigned i = 0; i < arr.length; ++i) + arr[i].get_axis_info (start_offset + i, &axes_array[i]); } return axisCount; } - bool find_axis_deprecated (hb_tag_t tag, - unsigned int *axis_index, - hb_ot_var_axis_t *info) const +#ifndef HB_DISABLE_DEPRECATED + bool + find_axis_deprecated (hb_tag_t tag, unsigned *axis_index, hb_ot_var_axis_t *info) const { - const AxisRecord *axes = get_axes (); - unsigned int count = get_axis_count (); - for (unsigned int i = 0; i < count; i++) - if (axes[i].axisTag == tag) - { - if (axis_index) - *axis_index = i; - get_axis_deprecated (i, info); - return true; - } - if (axis_index) - *axis_index = HB_OT_VAR_NO_AXIS_INDEX; - return false; + unsigned i; + if (!axis_index) axis_index = &i; + *axis_index = HB_OT_VAR_NO_AXIS_INDEX; + auto axes = get_axes (); + return axes.lfind (tag, axis_index) && (axes[*axis_index].get_axis_deprecated (info), true); } +#endif - bool find_axis_info (hb_tag_t tag, - hb_ot_var_axis_info_t *info) const + bool + find_axis_info (hb_tag_t tag, hb_ot_var_axis_info_t *info) const { - const AxisRecord *axes = get_axes (); - unsigned int count = get_axis_count (); - for (unsigned int i = 0; i < count; i++) - if (axes[i].axisTag == tag) - { - get_axis_info (i, info); - return true; - } - return false; + unsigned i; + auto axes = get_axes (); + return axes.lfind (tag, &i) && (axes[i].get_axis_info (i, info), true); } int normalize_axis_value (unsigned int axis_index, float v) const - { - hb_ot_var_axis_info_t axis; - get_axis_info (axis_index, &axis); + { return get_axes ()[axis_index].normalize_axis_value (v); } - v = MAX (MIN (v, axis.max_value), axis.min_value); /* Clamp. */ - - if (v == axis.default_value) - return 0; - else if (v < axis.default_value) - v = (v - axis.default_value) / (axis.default_value - axis.min_value); - else - v = (v - axis.default_value) / (axis.max_value - axis.default_value); - return (int) (v * 16384.f + (v >= 0.f ? .5f : -.5f)); - } + float unnormalize_axis_value (unsigned int axis_index, int v) const + { return get_axes ()[axis_index].unnormalize_axis_value (v); } unsigned int get_instance_count () const { return instanceCount; } @@ -253,8 +248,8 @@ struct fvar } unsigned int get_instance_coords (unsigned int instance_index, - unsigned int *coords_length, /* IN/OUT */ - float *coords /* OUT */) const + unsigned int *coords_length, /* IN/OUT */ + float *coords /* OUT */) const { const InstanceRecord *instance = get_instance (instance_index); if (unlikely (!instance)) @@ -266,7 +261,7 @@ struct fvar if (coords_length && *coords_length) { - hb_array_t instanceCoords = instance->get_coordinates (axisCount) + hb_array_t instanceCoords = instance->get_coordinates (axisCount) .sub_array (0, *coords_length); for (unsigned int i = 0; i < instanceCoords.length; i++) coords[i] = instanceCoords.arrayZ[i].to_float (); @@ -274,6 +269,26 @@ struct fvar return axisCount; } + void collect_name_ids (hb_set_t *nameids) const + { + if (!has_data ()) return; + + + get_axes () + | hb_map (&AxisRecord::get_name_id) + | hb_sink (nameids) + ; + + + hb_range ((unsigned) instanceCount) + | hb_map ([this] (const unsigned _) { return get_instance_subfamily_name_id (_); }) + | hb_sink (nameids) + ; + + + hb_range ((unsigned) instanceCount) + | hb_map ([this] (const unsigned _) { return get_instance_postscript_name_id (_); }) + | hb_sink (nameids) + ; + } + protected: hb_array_t get_axes () const { return hb_array (&(this+firstAxis), axisCount); } @@ -299,8 +314,8 @@ struct fvar HBUINT16 instanceCount; /* The number of named instances defined in the font * (the number of records in the instances array). */ HBUINT16 instanceSize; /* The size in bytes of each InstanceRecord — set - * to either axisCount * sizeof(Fixed) + 4, or to - * axisCount * sizeof(Fixed) + 6. */ + * to either axisCount * sizeof(HBFixed) + 4, or to + * axisCount * sizeof(HBFixed) + 6. */ public: DEFINE_SIZE_STATIC (16); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh new file mode 100644 index 00000000000..7c99b5de061 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-gvar-table.hh @@ -0,0 +1,701 @@ +/* + * Copyright © 2019 Adobe Inc. + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Adobe Author(s): Michiharu Ariza + */ + +#ifndef HB_OT_VAR_GVAR_TABLE_HH +#define HB_OT_VAR_GVAR_TABLE_HH + +#include "hb-open-type.hh" + +/* + * gvar -- Glyph Variation Table + * https://docs.microsoft.com/en-us/typography/opentype/spec/gvar + */ +#define HB_OT_TAG_gvar HB_TAG('g','v','a','r') + +namespace OT { + +struct contour_point_t +{ + void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false) + { flag = 0; x = x_; y = y_; is_end_point = is_end_point_; } + + void translate (const contour_point_t &p) { x += p.x; y += p.y; } + + uint8_t flag; + float x, y; + bool is_end_point; +}; + +struct contour_point_vector_t : hb_vector_t +{ + void extend (const hb_array_t &a) + { + unsigned int old_len = length; + resize (old_len + a.length); + for (unsigned int i = 0; i < a.length; i++) + (*this)[old_len + i] = a[i]; + } + + void transform (const float (&matrix)[4]) + { + for (unsigned int i = 0; i < length; i++) + { + contour_point_t &p = (*this)[i]; + float x_ = p.x * matrix[0] + p.y * matrix[2]; + p.y = p.x * matrix[1] + p.y * matrix[3]; + p.x = x_; + } + } + + void translate (const contour_point_t& delta) + { + for (unsigned int i = 0; i < length; i++) + (*this)[i].translate (delta); + } +}; + +/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */ +struct TupleVariationHeader +{ + unsigned get_size (unsigned axis_count) const + { return min_size + get_all_tuples (axis_count).get_size (); } + + unsigned get_data_size () const { return varDataSize; } + + const TupleVariationHeader &get_next (unsigned axis_count) const + { return StructAtOffset (this, get_size (axis_count)); } + + float calculate_scalar (const int *coords, unsigned int coord_count, + const hb_array_t shared_tuples) const + { + hb_array_t peak_tuple; + + if (has_peak ()) + peak_tuple = get_peak_tuple (coord_count); + else + { + unsigned int index = get_index (); + if (unlikely (index * coord_count >= shared_tuples.length)) + return 0.f; + peak_tuple = shared_tuples.sub_array (coord_count * index, coord_count); + } + + hb_array_t start_tuple; + hb_array_t end_tuple; + if (has_intermediate ()) + { + start_tuple = get_start_tuple (coord_count); + end_tuple = get_end_tuple (coord_count); + } + + float scalar = 1.f; + for (unsigned int i = 0; i < coord_count; i++) + { + int v = coords[i]; + int peak = peak_tuple[i]; + if (!peak || v == peak) continue; + + if (has_intermediate ()) + { + int start = start_tuple[i]; + int end = end_tuple[i]; + if (unlikely (start > peak || peak > end || + (start < 0 && end > 0 && peak))) continue; + if (v < start || v > end) return 0.f; + if (v < peak) + { if (peak != start) scalar *= (float) (v - start) / (peak - start); } + else + { if (peak != end) scalar *= (float) (end - v) / (end - peak); } + } + else if (!v || v < hb_min (0, peak) || v > hb_max (0, peak)) return 0.f; + else + scalar *= (float) v / peak; + } + return scalar; + } + + bool has_peak () const { return tupleIndex & TuppleIndex::EmbeddedPeakTuple; } + bool has_intermediate () const { return tupleIndex & TuppleIndex::IntermediateRegion; } + bool has_private_points () const { return tupleIndex & TuppleIndex::PrivatePointNumbers; } + unsigned get_index () const { return tupleIndex & TuppleIndex::TupleIndexMask; } + + protected: + struct TuppleIndex : HBUINT16 + { + enum Flags { + EmbeddedPeakTuple = 0x8000u, + IntermediateRegion = 0x4000u, + PrivatePointNumbers = 0x2000u, + TupleIndexMask = 0x0FFFu + }; + + DEFINE_SIZE_STATIC (2); + }; + + hb_array_t get_all_tuples (unsigned axis_count) const + { return StructAfter> (tupleIndex).as_array ((has_peak () + has_intermediate () * 2) * axis_count); } + hb_array_t get_peak_tuple (unsigned axis_count) const + { return get_all_tuples (axis_count).sub_array (0, axis_count); } + hb_array_t get_start_tuple (unsigned axis_count) const + { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count, axis_count); } + hb_array_t get_end_tuple (unsigned axis_count) const + { return get_all_tuples (axis_count).sub_array (has_peak () * axis_count + axis_count, axis_count); } + + HBUINT16 varDataSize; /* The size in bytes of the serialized + * data for this tuple variation table. */ + TuppleIndex tupleIndex; /* A packed field. The high 4 bits are flags (see below). + The low 12 bits are an index into a shared tuple + records array. */ + /* UnsizedArrayOf peakTuple - optional */ + /* Peak tuple record for this tuple variation table — optional, + * determined by flags in the tupleIndex value. + * + * Note that this must always be included in the 'cvar' table. */ + /* UnsizedArrayOf intermediateStartTuple - optional */ + /* Intermediate start tuple record for this tuple variation table — optional, + determined by flags in the tupleIndex value. */ + /* UnsizedArrayOf intermediateEndTuple - optional */ + /* Intermediate end tuple record for this tuple variation table — optional, + * determined by flags in the tupleIndex value. */ + public: + DEFINE_SIZE_MIN (4); +}; + +struct GlyphVariationData +{ + const TupleVariationHeader &get_tuple_var_header (void) const + { return StructAfter (data); } + + struct tuple_iterator_t + { + void init (hb_bytes_t var_data_bytes_, unsigned int axis_count_) + { + var_data_bytes = var_data_bytes_; + var_data = var_data_bytes_.as (); + index = 0; + axis_count = axis_count_; + current_tuple = &var_data->get_tuple_var_header (); + data_offset = 0; + } + + bool get_shared_indices (hb_vector_t &shared_indices /* OUT */) + { + if (var_data->has_shared_point_numbers ()) + { + const HBUINT8 *base = &(var_data+var_data->data); + const HBUINT8 *p = base; + if (!unpack_points (p, shared_indices, var_data_bytes)) return false; + data_offset = p - base; + } + return true; + } + + bool is_valid () const + { + return (index < var_data->tupleVarCount.get_count ()) && + var_data_bytes.check_range (current_tuple, TupleVariationHeader::min_size) && + var_data_bytes.check_range (current_tuple, hb_max (current_tuple->get_data_size (), current_tuple->get_size (axis_count))) && + current_tuple->get_size (axis_count); + } + + bool move_to_next () + { + data_offset += current_tuple->get_data_size (); + current_tuple = ¤t_tuple->get_next (axis_count); + index++; + return is_valid (); + } + + const HBUINT8 *get_serialized_data () const + { return &(var_data+var_data->data) + data_offset; } + + private: + const GlyphVariationData *var_data; + unsigned int index; + unsigned int axis_count; + unsigned int data_offset; + + public: + hb_bytes_t var_data_bytes; + const TupleVariationHeader *current_tuple; + }; + + static bool get_tuple_iterator (hb_bytes_t var_data_bytes, unsigned axis_count, + hb_vector_t &shared_indices /* OUT */, + tuple_iterator_t *iterator /* OUT */) + { + iterator->init (var_data_bytes, axis_count); + if (!iterator->get_shared_indices (shared_indices)) + return false; + return iterator->is_valid (); + } + + bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); } + + static bool unpack_points (const HBUINT8 *&p /* IN/OUT */, + hb_vector_t &points /* OUT */, + const hb_bytes_t &bytes) + { + enum packed_point_flag_t + { + POINTS_ARE_WORDS = 0x80, + POINT_RUN_COUNT_MASK = 0x7F + }; + + if (unlikely (!bytes.check_range (p))) return false; + + uint16_t count = *p++; + if (count & POINTS_ARE_WORDS) + { + if (unlikely (!bytes.check_range (p))) return false; + count = ((count & POINT_RUN_COUNT_MASK) << 8) | *p++; + } + points.resize (count); + + unsigned int n = 0; + uint16_t i = 0; + while (i < count) + { + if (unlikely (!bytes.check_range (p))) return false; + uint16_t j; + uint8_t control = *p++; + uint16_t run_count = (control & POINT_RUN_COUNT_MASK) + 1; + if (control & POINTS_ARE_WORDS) + { + for (j = 0; j < run_count && i < count; j++, i++) + { + if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) + return false; + n += *(const HBUINT16 *)p; + points[i] = n; + p += HBUINT16::static_size; + } + } + else + { + for (j = 0; j < run_count && i < count; j++, i++) + { + if (unlikely (!bytes.check_range (p))) return false; + n += *p++; + points[i] = n; + } + } + if (j < run_count) return false; + } + return true; + } + + static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */, + hb_vector_t &deltas /* IN/OUT */, + const hb_bytes_t &bytes) + { + enum packed_delta_flag_t + { + DELTAS_ARE_ZERO = 0x80, + DELTAS_ARE_WORDS = 0x40, + DELTA_RUN_COUNT_MASK = 0x3F + }; + + unsigned int i = 0; + unsigned int count = deltas.length; + while (i < count) + { + if (unlikely (!bytes.check_range (p))) return false; + uint8_t control = *p++; + unsigned int run_count = (control & DELTA_RUN_COUNT_MASK) + 1; + unsigned int j; + if (control & DELTAS_ARE_ZERO) + for (j = 0; j < run_count && i < count; j++, i++) + deltas[i] = 0; + else if (control & DELTAS_ARE_WORDS) + for (j = 0; j < run_count && i < count; j++, i++) + { + if (unlikely (!bytes.check_range ((const HBUINT16 *) p))) + return false; + deltas[i] = *(const HBINT16 *) p; + p += HBUINT16::static_size; + } + else + for (j = 0; j < run_count && i < count; j++, i++) + { + if (unlikely (!bytes.check_range (p))) + return false; + deltas[i] = *(const HBINT8 *) p++; + } + if (j < run_count) + return false; + } + return true; + } + + bool has_data () const { return tupleVarCount; } + + protected: + struct TupleVarCount : HBUINT16 + { + bool has_shared_point_numbers () const { return ((*this) & SharedPointNumbers); } + unsigned int get_count () const { return (*this) & CountMask; } + + protected: + enum Flags + { + SharedPointNumbers= 0x8000u, + CountMask = 0x0FFFu + }; + public: + DEFINE_SIZE_STATIC (2); + }; + + TupleVarCount tupleVarCount; /* A packed field. The high 4 bits are flags, and the + * low 12 bits are the number of tuple variation tables + * for this glyph. The number of tuple variation tables + * can be any number between 1 and 4095. */ + OffsetTo + data; /* Offset from the start of the GlyphVariationData table + * to the serialized data. */ + /* TupleVariationHeader tupleVariationHeaders[] *//* Array of tuple variation headers. */ + public: + DEFINE_SIZE_MIN (4); +}; + +struct gvar +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_gvar; + + bool sanitize_shallow (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && (version.major == 1) && + (glyphCount == c->get_num_glyphs ()) && + sharedTuples.sanitize (c, this, axisCount * sharedTupleCount) && + (is_long_offset () ? + c->check_array (get_long_offset_array (), glyphCount+1) : + c->check_array (get_short_offset_array (), glyphCount+1)) && + c->check_array (((const HBUINT8*)&(this+dataZ)) + get_offset (0), + get_offset (glyphCount) - get_offset (0))); + } + + /* GlyphVariationData not sanitized here; must be checked while accessing each glyph varation data */ + bool sanitize (hb_sanitize_context_t *c) const + { return sanitize_shallow (c); } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + gvar *out = c->serializer->allocate_min (); + if (unlikely (!out)) return_trace (false); + + out->version.major = 1; + out->version.minor = 0; + out->axisCount = axisCount; + out->sharedTupleCount = sharedTupleCount; + + unsigned int num_glyphs = c->plan->num_output_glyphs (); + out->glyphCount = num_glyphs; + + unsigned int subset_data_size = 0; + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t old_gid; + if (!c->plan->old_gid_for_new_gid (gid, &old_gid)) continue; + subset_data_size += get_glyph_var_data_bytes (c->source_blob, old_gid).length; + } + + bool long_offset = subset_data_size & ~0xFFFFu; + out->flags = long_offset ? 1 : 0; + + HBUINT8 *subset_offsets = c->serializer->allocate_size ((long_offset ? 4 : 2) * (num_glyphs + 1)); + if (!subset_offsets) return_trace (false); + + /* shared tuples */ + if (!sharedTupleCount || !sharedTuples) + out->sharedTuples = 0; + else + { + unsigned int shared_tuple_size = F2DOT14::static_size * axisCount * sharedTupleCount; + F2DOT14 *tuples = c->serializer->allocate_size (shared_tuple_size); + if (!tuples) return_trace (false); + out->sharedTuples = (char *) tuples - (char *) out; + memcpy (tuples, this+sharedTuples, shared_tuple_size); + } + + char *subset_data = c->serializer->allocate_size (subset_data_size); + if (!subset_data) return_trace (false); + out->dataZ = subset_data - (char *) out; + + unsigned int glyph_offset = 0; + for (hb_codepoint_t gid = 0; gid < num_glyphs; gid++) + { + hb_codepoint_t old_gid; + hb_bytes_t var_data_bytes = c->plan->old_gid_for_new_gid (gid, &old_gid) + ? get_glyph_var_data_bytes (c->source_blob, old_gid) + : hb_bytes_t (); + + if (long_offset) + ((HBUINT32 *) subset_offsets)[gid] = glyph_offset; + else + ((HBUINT16 *) subset_offsets)[gid] = glyph_offset / 2; + + if (var_data_bytes.length > 0) + memcpy (subset_data, var_data_bytes.arrayZ, var_data_bytes.length); + subset_data += var_data_bytes.length; + glyph_offset += var_data_bytes.length; + } + if (long_offset) + ((HBUINT32 *) subset_offsets)[num_glyphs] = glyph_offset; + else + ((HBUINT16 *) subset_offsets)[num_glyphs] = glyph_offset / 2; + + return_trace (true); + } + + protected: + const hb_bytes_t get_glyph_var_data_bytes (hb_blob_t *blob, hb_codepoint_t glyph) const + { + unsigned start_offset = get_offset (glyph); + unsigned length = get_offset (glyph+1) - start_offset; + hb_bytes_t var_data = blob->as_bytes ().sub_array (((unsigned) dataZ) + start_offset, length); + return likely (var_data.length >= GlyphVariationData::min_size) ? var_data : hb_bytes_t (); + } + + bool is_long_offset () const { return flags & 1; } + + unsigned get_offset (unsigned i) const + { return is_long_offset () ? get_long_offset_array ()[i] : get_short_offset_array ()[i] * 2; } + + const HBUINT32 * get_long_offset_array () const { return (const HBUINT32 *) &offsetZ; } + const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *) &offsetZ; } + + public: + struct accelerator_t + { + void init (hb_face_t *face) + { table = hb_sanitize_context_t ().reference_table (face); } + void fini () { table.destroy (); } + + private: + struct x_getter { static float get (const contour_point_t &p) { return p.x; } }; + struct y_getter { static float get (const contour_point_t &p) { return p.y; } }; + + template + static float infer_delta (const hb_array_t points, + const hb_array_t deltas, + unsigned int target, unsigned int prev, unsigned int next) + { + float target_val = T::get (points[target]); + float prev_val = T::get (points[prev]); + float next_val = T::get (points[next]); + float prev_delta = T::get (deltas[prev]); + float next_delta = T::get (deltas[next]); + + if (prev_val == next_val) + return (prev_delta == next_delta) ? prev_delta : 0.f; + else if (target_val <= hb_min (prev_val, next_val)) + return (prev_val < next_val) ? prev_delta : next_delta; + else if (target_val >= hb_max (prev_val, next_val)) + return (prev_val > next_val) ? prev_delta : next_delta; + + /* linear interpolation */ + float r = (target_val - prev_val) / (next_val - prev_val); + return (1.f - r) * prev_delta + r * next_delta; + } + + static unsigned int next_index (unsigned int i, unsigned int start, unsigned int end) + { return (i >= end) ? start : (i + 1); } + + public: + bool apply_deltas_to_points (hb_codepoint_t glyph, hb_font_t *font, + const hb_array_t points) const + { + /* num_coords should exactly match gvar's axisCount due to how GlyphVariationData tuples are aligned */ + if (!font->num_coords || font->num_coords != table->axisCount) return true; + + if (unlikely (glyph >= table->glyphCount)) return true; + + hb_bytes_t var_data_bytes = table->get_glyph_var_data_bytes (table.get_blob (), glyph); + if (!var_data_bytes.as ()->has_data ()) return true; + hb_vector_t shared_indices; + GlyphVariationData::tuple_iterator_t iterator; + if (!GlyphVariationData::get_tuple_iterator (var_data_bytes, table->axisCount, + shared_indices, &iterator)) + return true; /* so isn't applied at all */ + + /* Save original points for inferred delta calculation */ + contour_point_vector_t orig_points; + orig_points.resize (points.length); + for (unsigned int i = 0; i < orig_points.length; i++) + orig_points[i] = points[i]; + + contour_point_vector_t deltas; /* flag is used to indicate referenced point */ + deltas.resize (points.length); + + hb_vector_t end_points; + for (unsigned i = 0; i < points.length; ++i) + if (points[i].is_end_point) + end_points.push (i); + + int *coords = font->coords; + unsigned num_coords = font->num_coords; + hb_array_t shared_tuples = (table+table->sharedTuples).as_array (table->sharedTupleCount * table->axisCount); + do + { + float scalar = iterator.current_tuple->calculate_scalar (coords, num_coords, shared_tuples); + if (scalar == 0.f) continue; + const HBUINT8 *p = iterator.get_serialized_data (); + unsigned int length = iterator.current_tuple->get_data_size (); + if (unlikely (!iterator.var_data_bytes.check_range (p, length))) + return false; + + hb_bytes_t bytes ((const char *) p, length); + hb_vector_t private_indices; + if (iterator.current_tuple->has_private_points () && + !GlyphVariationData::unpack_points (p, private_indices, bytes)) + return false; + const hb_array_t &indices = private_indices.length ? private_indices : shared_indices; + + bool apply_to_all = (indices.length == 0); + unsigned int num_deltas = apply_to_all ? points.length : indices.length; + hb_vector_t x_deltas; + x_deltas.resize (num_deltas); + if (!GlyphVariationData::unpack_deltas (p, x_deltas, bytes)) + return false; + hb_vector_t y_deltas; + y_deltas.resize (num_deltas); + if (!GlyphVariationData::unpack_deltas (p, y_deltas, bytes)) + return false; + + for (unsigned int i = 0; i < deltas.length; i++) + deltas[i].init (); + for (unsigned int i = 0; i < num_deltas; i++) + { + unsigned int pt_index = apply_to_all ? i : indices[i]; + deltas[pt_index].flag = 1; /* this point is referenced, i.e., explicit deltas specified */ + deltas[pt_index].x += x_deltas[i] * scalar; + deltas[pt_index].y += y_deltas[i] * scalar; + } + + /* infer deltas for unreferenced points */ + unsigned start_point = 0; + for (unsigned c = 0; c < end_points.length; c++) + { + unsigned end_point = end_points[c]; + + /* Check the number of unreferenced points in a contour. If no unref points or no ref points, nothing to do. */ + unsigned unref_count = 0; + for (unsigned i = start_point; i <= end_point; i++) + if (!deltas[i].flag) unref_count++; + + unsigned j = start_point; + if (unref_count == 0 || unref_count > end_point - start_point) + goto no_more_gaps; + + for (;;) + { + /* Locate the next gap of unreferenced points between two referenced points prev and next. + * Note that a gap may wrap around at left (start_point) and/or at right (end_point). + */ + unsigned int prev, next, i; + for (;;) + { + i = j; + j = next_index (i, start_point, end_point); + if (deltas[i].flag && !deltas[j].flag) break; + } + prev = j = i; + for (;;) + { + i = j; + j = next_index (i, start_point, end_point); + if (!deltas[i].flag && deltas[j].flag) break; + } + next = j; + /* Infer deltas for all unref points in the gap between prev and next */ + i = prev; + for (;;) + { + i = next_index (i, start_point, end_point); + if (i == next) break; + deltas[i].x = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next); + deltas[i].y = infer_delta (orig_points.as_array (), deltas.as_array (), i, prev, next); + if (--unref_count == 0) goto no_more_gaps; + } + } +no_more_gaps: + start_point = end_point + 1; + } + + /* apply specified / inferred deltas to points */ + for (unsigned int i = 0; i < points.length; i++) + { + points[i].x += roundf (deltas[i].x); + points[i].y += roundf (deltas[i].y); + } + } while (iterator.move_to_next ()); + + return true; + } + + unsigned int get_axis_count () const { return table->axisCount; } + + private: + hb_blob_ptr_t table; + }; + + protected: + FixedVersion<>version; /* Version number of the glyph variations table + * Set to 0x00010000u. */ + HBUINT16 axisCount; /* The number of variation axes for this font. This must be + * the same number as axisCount in the 'fvar' table. */ + HBUINT16 sharedTupleCount; + /* The number of shared tuple records. Shared tuple records + * can be referenced within glyph variation data tables for + * multiple glyphs, as opposed to other tuple records stored + * directly within a glyph variation data table. */ + LNNOffsetTo> + sharedTuples; /* Offset from the start of this table to the shared tuple records. + * Array of tuple records shared across all glyph variation data tables. */ + HBUINT16 glyphCount; /* The number of glyphs in this font. This must match the number of + * glyphs stored elsewhere in the font. */ + HBUINT16 flags; /* Bit-field that gives the format of the offset array that follows. + * If bit 0 is clear, the offsets are uint16; if bit 0 is set, the + * offsets are uint32. */ + LOffsetTo + dataZ; /* Offset from the start of this table to the array of + * GlyphVariationData tables. */ + UnsizedArrayOf + offsetZ; /* Offsets from the start of the GlyphVariationData array + * to each GlyphVariationData table. */ + public: + DEFINE_SIZE_MIN (20); +}; + +struct gvar_accelerator_t : gvar::accelerator_t {}; + +} /* namespace OT */ + +#endif /* HB_OT_VAR_GVAR_TABLE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh index 4d030f3d7cf..d024147183f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-hvar-table.hh @@ -44,6 +44,38 @@ struct DeltaSetIndexMap get_width ())); } + template + bool serialize (hb_serialize_context_t *c, const T &plan) + { + unsigned int width = plan.get_width (); + unsigned int inner_bit_count = plan.get_inner_bit_count (); + const hb_array_t output_map = plan.get_output_map (); + + TRACE_SERIALIZE (this); + if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0)))) + return_trace (false); + if (unlikely (!c->extend_min (*this))) return_trace (false); + + format = ((width-1)<<4)|(inner_bit_count-1); + mapCount = output_map.length; + HBUINT8 *p = c->allocate_size (width * output_map.length); + if (unlikely (!p)) return_trace (false); + for (unsigned int i = 0; i < output_map.length; i++) + { + unsigned int v = output_map[i]; + unsigned int outer = v >> 16; + unsigned int inner = v & 0xFFFF; + unsigned int u = (outer << inner_bit_count) | inner; + for (unsigned int w = width; w > 0;) + { + p[--w] = u; + u >>= 8; + } + p += width; + } + return_trace (true); + } + unsigned int map (unsigned int v) const /* Returns 16.16 outer.inner. */ { /* If count is zero, pass value unchanged. This takes @@ -63,7 +95,7 @@ struct DeltaSetIndexMap } { /* Repack it. */ - unsigned int n = get_inner_bitcount (); + unsigned int n = get_inner_bit_count (); unsigned int outer = u >> n; unsigned int inner = u & ((1 << n) - 1); u = (outer<<16) | inner; @@ -72,10 +104,9 @@ struct DeltaSetIndexMap return u; } - protected: - unsigned int get_width () const { return ((format >> 4) & 3) + 1; } - - unsigned int get_inner_bitcount () const { return (format & 0xF) + 1; } + unsigned int get_map_count () const { return mapCount; } + unsigned int get_width () const { return ((format >> 4) & 3) + 1; } + unsigned int get_inner_bit_count () const { return (format & 0xF) + 1; } protected: HBUINT16 format; /* A packed field that describes the compressed @@ -88,6 +119,215 @@ struct DeltaSetIndexMap DEFINE_SIZE_ARRAY (4, mapDataZ); }; +struct index_map_subset_plan_t +{ + enum index_map_index_t { + ADV_INDEX, + LSB_INDEX, /* dual as TSB */ + RSB_INDEX, /* dual as BSB */ + VORG_INDEX + }; + + void init (const DeltaSetIndexMap &index_map, + hb_inc_bimap_t &outer_map, + hb_vector_t &inner_sets, + const hb_subset_plan_t *plan) + { + map_count = 0; + outer_bit_count = 0; + inner_bit_count = 1; + max_inners.init (); + output_map.init (); + + if (&index_map == &Null (DeltaSetIndexMap)) return; + + unsigned int last_val = (unsigned int)-1; + hb_codepoint_t last_gid = (hb_codepoint_t)-1; + hb_codepoint_t gid = (hb_codepoint_t) hb_min (index_map.get_map_count (), plan->num_output_glyphs ()); + + outer_bit_count = (index_map.get_width () * 8) - index_map.get_inner_bit_count (); + max_inners.resize (inner_sets.length); + for (unsigned i = 0; i < inner_sets.length; i++) max_inners[i] = 0; + + /* Search backwards for a map value different from the last map value */ + for (; gid > 0; gid--) + { + hb_codepoint_t old_gid; + if (!plan->old_gid_for_new_gid (gid - 1, &old_gid)) + { + if (last_gid == (hb_codepoint_t) -1) + continue; + else + break; + } + + unsigned int v = index_map.map (old_gid); + if (last_gid == (hb_codepoint_t) -1) + { + last_val = v; + last_gid = gid; + continue; + } + if (v != last_val) break; + + last_gid = gid; + } + + if (unlikely (last_gid == (hb_codepoint_t)-1)) return; + map_count = last_gid; + for (gid = 0; gid < map_count; gid++) + { + hb_codepoint_t old_gid; + if (plan->old_gid_for_new_gid (gid, &old_gid)) + { + unsigned int v = index_map.map (old_gid); + unsigned int outer = v >> 16; + unsigned int inner = v & 0xFFFF; + outer_map.add (outer); + if (inner > max_inners[outer]) max_inners[outer] = inner; + if (outer >= inner_sets.length) return; + inner_sets[outer]->add (inner); + } + } + } + + void fini () + { + max_inners.fini (); + output_map.fini (); + } + + void remap (const DeltaSetIndexMap *input_map, + const hb_inc_bimap_t &outer_map, + const hb_vector_t &inner_maps, + const hb_subset_plan_t *plan) + { + if (input_map == &Null (DeltaSetIndexMap)) return; + + for (unsigned int i = 0; i < max_inners.length; i++) + { + if (inner_maps[i].get_population () == 0) continue; + unsigned int bit_count = (max_inners[i]==0)? 1: hb_bit_storage (inner_maps[i][max_inners[i]]); + if (bit_count > inner_bit_count) inner_bit_count = bit_count; + } + + output_map.resize (map_count); + for (hb_codepoint_t gid = 0; gid < output_map.length; gid++) + { + hb_codepoint_t old_gid; + if (plan->old_gid_for_new_gid (gid, &old_gid)) + { + unsigned int v = input_map->map (old_gid); + unsigned int outer = v >> 16; + output_map[gid] = (outer_map[outer] << 16) | (inner_maps[outer][v & 0xFFFF]); + } + else + output_map[gid] = 0; /* Map unused glyph to outer/inner=0/0 */ + } + } + + unsigned int get_inner_bit_count () const { return inner_bit_count; } + unsigned int get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); } + unsigned int get_map_count () const { return map_count; } + + unsigned int get_size () const + { return (map_count? (DeltaSetIndexMap::min_size + get_width () * map_count): 0); } + + bool is_identity () const { return get_output_map ().length == 0; } + hb_array_t get_output_map () const { return output_map.as_array (); } + + protected: + unsigned int map_count; + hb_vector_t max_inners; + unsigned int outer_bit_count; + unsigned int inner_bit_count; + hb_vector_t output_map; +}; + +struct hvarvvar_subset_plan_t +{ + hvarvvar_subset_plan_t() : inner_maps (), index_map_plans () {} + ~hvarvvar_subset_plan_t() { fini (); } + + void init (const hb_array_t &index_maps, + const VariationStore &_var_store, + const hb_subset_plan_t *plan) + { + index_map_plans.resize (index_maps.length); + + var_store = &_var_store; + inner_sets.resize (var_store->get_sub_table_count ()); + for (unsigned int i = 0; i < inner_sets.length; i++) + inner_sets[i] = hb_set_create (); + adv_set = hb_set_create (); + + inner_maps.resize (var_store->get_sub_table_count ()); + + for (unsigned int i = 0; i < inner_maps.length; i++) + inner_maps[i].init (); + + if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return; + + bool retain_adv_map = false; + index_map_plans[0].init (*index_maps[0], outer_map, inner_sets, plan); + if (index_maps[0] == &Null (DeltaSetIndexMap)) + { + retain_adv_map = plan->retain_gids; + outer_map.add (0); + for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) + { + hb_codepoint_t old_gid; + if (plan->old_gid_for_new_gid (gid, &old_gid)) + inner_sets[0]->add (old_gid); + } + hb_set_union (adv_set, inner_sets[0]); + } + + for (unsigned int i = 1; i < index_maps.length; i++) + index_map_plans[i].init (*index_maps[i], outer_map, inner_sets, plan); + + outer_map.sort (); + + if (retain_adv_map) + { + for (hb_codepoint_t gid = 0; gid < plan->num_output_glyphs (); gid++) + if (inner_sets[0]->has (gid)) + inner_maps[0].add (gid); + else + inner_maps[0].skip (); + } + else + { + inner_maps[0].add_set (adv_set); + hb_set_subtract (inner_sets[0], adv_set); + inner_maps[0].add_set (inner_sets[0]); + } + + for (unsigned int i = 1; i < inner_maps.length; i++) + inner_maps[i].add_set (inner_sets[i]); + + for (unsigned int i = 0; i < index_maps.length; i++) + index_map_plans[i].remap (index_maps[i], outer_map, inner_maps, plan); + } + + void fini () + { + for (unsigned int i = 0; i < inner_sets.length; i++) + hb_set_destroy (inner_sets[i]); + hb_set_destroy (adv_set); + inner_maps.fini_deep (); + index_map_plans.fini_deep (); + } + + hb_inc_bimap_t outer_map; + hb_vector_t inner_maps; + hb_vector_t index_map_plans; + const VariationStore *var_store; + + protected: + hb_vector_t inner_sets; + hb_set_t *adv_set; +}; /* * HVAR -- Horizontal Metrics Variations @@ -114,14 +354,73 @@ struct HVARVVAR rsbMap.sanitize (c, this)); } - float get_advance_var (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count) const + void listup_index_maps (hb_vector_t &index_maps) const + { + index_maps.push (&(this+advMap)); + index_maps.push (&(this+lsbMap)); + index_maps.push (&(this+rsbMap)); + } + + bool serialize_index_maps (hb_serialize_context_t *c, + const hb_array_t &im_plans) + { + TRACE_SERIALIZE (this); + if (im_plans[index_map_subset_plan_t::ADV_INDEX].is_identity ()) + advMap = 0; + else if (unlikely (!advMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::ADV_INDEX]))) + return_trace (false); + if (im_plans[index_map_subset_plan_t::LSB_INDEX].is_identity ()) + lsbMap = 0; + else if (unlikely (!lsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::LSB_INDEX]))) + return_trace (false); + if (im_plans[index_map_subset_plan_t::RSB_INDEX].is_identity ()) + rsbMap = 0; + else if (unlikely (!rsbMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::RSB_INDEX]))) + return_trace (false); + + return_trace (true); + } + + template + bool _subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + hvarvvar_subset_plan_t hvar_plan; + hb_vector_t + index_maps; + + ((T*)this)->listup_index_maps (index_maps); + hvar_plan.init (index_maps.as_array (), this+varStore, c->plan); + + T *out = c->serializer->allocate_min (); + if (unlikely (!out)) return_trace (false); + + out->version.major = 1; + out->version.minor = 0; + + if (unlikely (!out->varStore.serialize (c->serializer, out) + .serialize (c->serializer, hvar_plan.var_store, hvar_plan.inner_maps.as_array ()))) + return_trace (false); + + return_trace (out->T::serialize_index_maps (c->serializer, + hvar_plan.index_map_plans.as_array ())); + } + + float get_advance_var (hb_codepoint_t glyph, hb_font_t *font) const { unsigned int varidx = (this+advMap).map (glyph); + return (this+varStore).get_delta (varidx, font->coords, font->num_coords); + } + + float get_side_bearing_var (hb_codepoint_t glyph, + const int *coords, unsigned int coord_count) const + { + if (!has_side_bearing_deltas ()) return 0.f; + unsigned int varidx = (this+lsbMap).map (glyph); return (this+varStore).get_delta (varidx, coords, coord_count); } - bool has_sidebearing_deltas () const { return lsbMap && rsbMap; } + bool has_side_bearing_deltas () const { return lsbMap && rsbMap; } protected: FixedVersion<>version; /* Version of the metrics variation table @@ -141,6 +440,7 @@ struct HVARVVAR struct HVAR : HVARVVAR { static constexpr hb_tag_t tableTag = HB_OT_TAG_HVAR; + bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset (c); } }; struct VVAR : HVARVVAR { static constexpr hb_tag_t tableTag = HB_OT_TAG_VVAR; @@ -152,6 +452,28 @@ struct VVAR : HVARVVAR { vorgMap.sanitize (c, this)); } + void listup_index_maps (hb_vector_t &index_maps) const + { + HVARVVAR::listup_index_maps (index_maps); + index_maps.push (&(this+vorgMap)); + } + + bool serialize_index_maps (hb_serialize_context_t *c, + const hb_array_t &im_plans) + { + TRACE_SERIALIZE (this); + if (unlikely (!HVARVVAR::serialize_index_maps (c, im_plans))) + return_trace (false); + if (!im_plans[index_map_subset_plan_t::VORG_INDEX].get_map_count ()) + vorgMap = 0; + else if (unlikely (!vorgMap.serialize (c, this).serialize (c, im_plans[index_map_subset_plan_t::VORG_INDEX]))) + return_trace (false); + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const { return HVARVVAR::_subset (c); } + protected: LOffsetTo vorgMap; /* Offset to vertical-origin var-idx mapping. */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-mvar-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-mvar-table.hh index 374ce665f76..37a47ff1d41 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var-mvar-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var-mvar-table.hh @@ -77,9 +77,11 @@ struct MVAR const int *coords, unsigned int coord_count) const { const VariationValueRecord *record; - record = (VariationValueRecord *) bsearch (&tag, valuesZ.arrayZ, - valueRecordCount, valueRecordSize, - tag_compare); + record = (VariationValueRecord *) hb_bsearch (tag, + (const VariationValueRecord *) + (const HBUINT8 *) valuesZ, + valueRecordCount, valueRecordSize, + tag_compare); if (!record) return 0.; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc index ed360125148..1c12d566582 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.cc @@ -24,13 +24,15 @@ * Google Author(s): Behdad Esfahbod */ -#include "hb-open-type.hh" +#include "hb.hh" + +#ifndef HB_NO_VAR + +#include "hb-ot-var.h" -#include "hb-ot-face.hh" #include "hb-ot-var-avar-table.hh" #include "hb-ot-var-fvar-table.hh" #include "hb-ot-var-mvar-table.hh" -#include "hb-ot-var.h" /** @@ -75,6 +77,7 @@ hb_ot_var_get_axis_count (hb_face_t *face) return face->table.fvar->get_axis_count (); } +#ifndef HB_DISABLE_DEPRECATED /** * hb_ot_var_get_axes: * @@ -104,6 +107,7 @@ hb_ot_var_find_axis (hb_face_t *face, { return face->table.fvar->find_axis_deprecated (axis_tag, axis_index, axis_info); } +#endif /** * hb_ot_var_get_axis_infos: @@ -211,3 +215,6 @@ hb_ot_var_normalize_coords (hb_face_t *face, face->table.avar->map_coords (normalized_coords, coords_length); } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.h index 5b028240d30..92494c24a0f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-var.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-var.h @@ -68,7 +68,7 @@ hb_ot_var_get_axis_count (hb_face_t *face); typedef enum { /*< flags >*/ HB_OT_VAR_AXIS_FLAG_HIDDEN = 0x00000001u, - _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= 0x7FFFFFFFu /*< skip >*/ + _HB_OT_VAR_AXIS_FLAG_MAX_VALUE= HB_TAG_MAX_SIGNED /*< skip >*/ } hb_ot_var_axis_flags_t; /** diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh index c2dc77b62bb..4dd8dfdb02a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-vorg-table.hh @@ -48,7 +48,7 @@ struct VertOriginMetric } public: - GlyphID glyph; + HBGlyphID glyph; FWORD vertOriginY; public: @@ -69,94 +69,48 @@ struct VORG return vertYOrigins[i].vertOriginY; } - bool _subset (const hb_subset_plan_t *plan HB_UNUSED, - const VORG *vorg_table, - const hb_vector_t &subset_metrics, - unsigned int dest_sz, - void *dest) const + template + void serialize (hb_serialize_context_t *c, + Iterator it, + FWORD defaultVertOriginY) { - hb_serialize_context_t c (dest, dest_sz); - - VORG *subset_table = c.start_serialize (); - if (unlikely (!c.extend_min (*subset_table))) - return false; - - subset_table->version.major.set (1); - subset_table->version.minor.set (0); - - subset_table->defaultVertOriginY.set (vorg_table->defaultVertOriginY); - subset_table->vertYOrigins.len.set (subset_metrics.length); - - bool success = true; - if (subset_metrics.length > 0) - { - unsigned int size = VertOriginMetric::static_size * subset_metrics.length; - VertOriginMetric *metrics = c.allocate_size (size); - if (likely (metrics != nullptr)) - memcpy (metrics, &subset_metrics[0], size); - else - success = false; - } - c.end_serialize (); - - return success; + + if (unlikely (!c->extend_min ((*this)))) return; + + this->version.major = 1; + this->version.minor = 0; + + this->defaultVertOriginY = defaultVertOriginY; + this->vertYOrigins.len = it.len (); + + c->copy_all (it); } - bool subset (hb_subset_plan_t *plan) const + bool subset (hb_subset_context_t *c) const { - hb_blob_t *vorg_blob = hb_sanitize_context_t().reference_table (plan->source); - const VORG *vorg_table = vorg_blob->as (); - - /* count the number of glyphs to be included in the subset table */ - hb_vector_t subset_metrics; - subset_metrics.init (); - unsigned int glyph = 0; - unsigned int i = 0; - while ((glyph < plan->glyphs.length) && (i < vertYOrigins.len)) - { - if (plan->glyphs[glyph] > vertYOrigins[i].glyph) - i++; - else if (plan->glyphs[glyph] < vertYOrigins[i].glyph) - glyph++; - else - { - VertOriginMetric *metrics = subset_metrics.push (); - metrics->glyph.set (glyph); - metrics->vertOriginY.set (vertYOrigins[i].vertOriginY); - glyph++; - i++; - } - } - - /* alloc the new table */ - unsigned int dest_sz = VORG::min_size + VertOriginMetric::static_size * subset_metrics.length; - void *dest = (void *) malloc (dest_sz); - if (unlikely (!dest)) - { - subset_metrics.fini (); - hb_blob_destroy (vorg_blob); - return false; - } + TRACE_SUBSET (this); + VORG *vorg_prime = c->serializer->start_embed (); + if (unlikely (!c->serializer->check_success (vorg_prime))) return_trace (false); + + auto it = + + vertYOrigins.as_array () + | hb_filter (c->plan->glyphset (), &VertOriginMetric::glyph) + | hb_map ([&] (const VertOriginMetric& _) + { + hb_codepoint_t new_glyph = HB_SET_VALUE_INVALID; + c->plan->new_gid_for_old_gid (_.glyph, &new_glyph); + + VertOriginMetric metric; + metric.glyph = new_glyph; + metric.vertOriginY = _.vertOriginY; + return metric; + }) + ; /* serialize the new table */ - if (!_subset (plan, vorg_table, subset_metrics, dest_sz, dest)) - { - subset_metrics.fini (); - free (dest); - hb_blob_destroy (vorg_blob); - return false; - } - - hb_blob_t *result = hb_blob_create ((const char *)dest, - dest_sz, - HB_MEMORY_MODE_READONLY, - dest, - free); - bool success = plan->add_table (HB_OT_TAG_VORG, result); - hb_blob_destroy (result); - subset_metrics.fini (); - hb_blob_destroy (vorg_blob); - return success; + vorg_prime->serialize (c->serializer, it, defaultVertOriginY); + return_trace (true); } bool sanitize (hb_sanitize_context_t *c) const @@ -168,10 +122,11 @@ struct VORG } protected: - FixedVersion<> version; /* Version of VORG table. Set to 0x00010000u. */ - FWORD defaultVertOriginY; /* The default vertical origin. */ + FixedVersion<>version; /* Version of VORG table. Set to 0x00010000u. */ + FWORD defaultVertOriginY; + /* The default vertical origin. */ SortedArrayOf - vertYOrigins; /* The array of vertical origins. */ + vertYOrigins; /* The array of vertical origins. */ public: DEFINE_SIZE_ARRAY(8, vertYOrigins); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot.h b/src/java.desktop/share/native/libharfbuzz/hb-ot.h index db784694c6a..f2dbaa1b317 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot.h @@ -35,6 +35,8 @@ #include "hb-ot-font.h" #include "hb-ot-layout.h" #include "hb-ot-math.h" +#include "hb-ot-meta.h" +#include "hb-ot-metrics.h" #include "hb-ot-name.h" #include "hb-ot-shape.h" #include "hb-ot-var.h" diff --git a/src/java.desktop/share/native/libharfbuzz/hb-pool.hh b/src/java.desktop/share/native/libharfbuzz/hb-pool.hh new file mode 100644 index 00000000000..a2266a38461 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-pool.hh @@ -0,0 +1,100 @@ +/* + * Copyright © 2019 Facebook, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Facebook Author(s): Behdad Esfahbod + */ + +#ifndef HB_POOL_HH +#define HB_POOL_HH + +#include "hb.hh" + +/* Memory pool for persistent allocation of small objects. */ + +template +struct hb_pool_t +{ + hb_pool_t () : next (nullptr) {} + ~hb_pool_t () { fini (); } + + void fini () + { + next = nullptr; + + for (chunk_t *_ : chunks) ::free (_); + + chunks.fini (); + } + + T* alloc () + { + if (unlikely (!next)) + { + if (unlikely (!chunks.alloc (chunks.length + 1))) return nullptr; + chunk_t *chunk = (chunk_t *) calloc (1, sizeof (chunk_t)); + if (unlikely (!chunk)) return nullptr; + chunks.push (chunk); + next = chunk->thread (); + } + + T* obj = next; + next = * ((T**) next); + + memset (obj, 0, sizeof (T)); + + return obj; + } + + void free (T* obj) + { + * (T**) obj = next; + next = obj; + } + + private: + + static_assert (ChunkLen > 1, ""); + static_assert (sizeof (T) >= sizeof (void *), ""); + static_assert (alignof (T) % alignof (void *) == 0, ""); + + struct chunk_t + { + T* thread () + { + for (unsigned i = 0; i < ARRAY_LENGTH (arrayZ) - 1; i++) + * (T**) &arrayZ[i] = &arrayZ[i + 1]; + + * (T**) &arrayZ[ARRAY_LENGTH (arrayZ) - 1] = nullptr; + + return arrayZ; + } + + T arrayZ[ChunkLen]; + }; + + T* next; + hb_vector_t chunks; +}; + + +#endif /* HB_POOL_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh b/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh new file mode 100644 index 00000000000..0e293e9eb1b --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-sanitize.hh @@ -0,0 +1,412 @@ +/* + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2012,2018 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_SANITIZE_HH +#define HB_SANITIZE_HH + +#include "hb.hh" +#include "hb-blob.hh" +#include "hb-dispatch.hh" + + +/* + * Sanitize + * + * + * === Introduction === + * + * The sanitize machinery is at the core of our zero-cost font loading. We + * mmap() font file into memory and create a blob out of it. Font subtables + * are returned as a readonly sub-blob of the main font blob. These table + * blobs are then sanitized before use, to ensure invalid memory access does + * not happen. The toplevel sanitize API use is like, eg. to load the 'head' + * table: + * + * hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table (face); + * + * The blob then can be converted to a head table struct with: + * + * const head *head_table = head_blob->as (); + * + * What the reference_table does is, to call hb_face_reference_table() to load + * the table blob, sanitize it and return either the sanitized blob, or empty + * blob if sanitization failed. The blob->as() function returns the null + * object of its template type argument if the blob is empty. Otherwise, it + * just casts the blob contents to the desired type. + * + * Sanitizing a blob of data with a type T works as follows (with minor + * simplification): + * + * - Cast blob content to T*, call sanitize() method of it, + * - If sanitize succeeded, return blob. + * - Otherwise, if blob is not writable, try making it writable, + * or copy if cannot be made writable in-place, + * - Call sanitize() again. Return blob if sanitize succeeded. + * - Return empty blob otherwise. + * + * + * === The sanitize() contract === + * + * The sanitize() method of each object type shall return true if it's safe to + * call other methods of the object, and false otherwise. + * + * Note that what sanitize() checks for might align with what the specification + * describes as valid table data, but does not have to be. In particular, we + * do NOT want to be pedantic and concern ourselves with validity checks that + * are irrelevant to our use of the table. On the contrary, we want to be + * lenient with error handling and accept invalid data to the extent that it + * does not impose extra burden on us. + * + * Based on the sanitize contract, one can see that what we check for depends + * on how we use the data in other table methods. Ie. if other table methods + * assume that offsets do NOT point out of the table data block, then that's + * something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way). On + * the other hand, if other methods do such checks themselves, then sanitize() + * does not have to bother with them (glyf/local work this way). The choice + * depends on the table structure and sanitize() performance. For example, to + * check glyf/loca offsets in sanitize() would cost O(num-glyphs). We try hard + * to avoid such costs during font loading. By postponing such checks to the + * actual glyph loading, we reduce the sanitize cost to O(1) and total runtime + * cost to O(used-glyphs). As such, this is preferred. + * + * The same argument can be made re GSUB/GPOS/GDEF, but there, the table + * structure is so complicated that by checking all offsets at sanitize() time, + * we make the code much simpler in other methods, as offsets and referenced + * objects do not need to be validated at each use site. + */ + +/* This limits sanitizing time on really broken fonts. */ +#ifndef HB_SANITIZE_MAX_EDITS +#define HB_SANITIZE_MAX_EDITS 32 +#endif +#ifndef HB_SANITIZE_MAX_OPS_FACTOR +#define HB_SANITIZE_MAX_OPS_FACTOR 8 +#endif +#ifndef HB_SANITIZE_MAX_OPS_MIN +#define HB_SANITIZE_MAX_OPS_MIN 16384 +#endif +#ifndef HB_SANITIZE_MAX_OPS_MAX +#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF +#endif +#ifndef HB_SANITIZE_MAX_SUTABLES +#define HB_SANITIZE_MAX_SUTABLES 0x4000 +#endif + +struct hb_sanitize_context_t : + hb_dispatch_context_t +{ + hb_sanitize_context_t () : + start (nullptr), end (nullptr), + max_ops (0), max_subtables (0), + writable (false), edit_count (0), + blob (nullptr), + num_glyphs (65536), + num_glyphs_set (false) {} + + const char *get_name () { return "SANITIZE"; } + template + bool may_dispatch (const T *obj HB_UNUSED, const F *format) + { return format->sanitize (this); } + static return_t default_return_value () { return true; } + static return_t no_dispatch_return_value () { return false; } + bool stop_sublookup_iteration (const return_t r) const { return !r; } + + bool visit_subtables (unsigned count) + { + max_subtables += count; + return max_subtables < HB_SANITIZE_MAX_SUTABLES; + } + + private: + template auto + _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN + ( obj.sanitize (this, hb_forward (ds)...) ) + template auto + _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN + ( obj.dispatch (this, hb_forward (ds)...) ) + public: + template auto + dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN + ( _dispatch (obj, hb_prioritize, hb_forward (ds)...) ) + + + void init (hb_blob_t *b) + { + this->blob = hb_blob_reference (b); + this->writable = false; + } + + void set_num_glyphs (unsigned int num_glyphs_) + { + num_glyphs = num_glyphs_; + num_glyphs_set = true; + } + unsigned int get_num_glyphs () { return num_glyphs; } + + void set_max_ops (int max_ops_) { max_ops = max_ops_; } + + template + void set_object (const T *obj) + { + reset_object (); + + if (!obj) return; + + const char *obj_start = (const char *) obj; + if (unlikely (obj_start < this->start || this->end <= obj_start)) + this->start = this->end = nullptr; + else + { + this->start = obj_start; + this->end = obj_start + hb_min (size_t (this->end - obj_start), obj->get_size ()); + } + } + + void reset_object () + { + this->start = this->blob->data; + this->end = this->start + this->blob->length; + assert (this->start <= this->end); /* Must not overflow. */ + } + + void start_processing () + { + reset_object (); + if (unlikely (hb_unsigned_mul_overflows (this->end - this->start, HB_SANITIZE_MAX_OPS_FACTOR))) + this->max_ops = HB_SANITIZE_MAX_OPS_MAX; + else + this->max_ops = hb_clamp ((unsigned) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR, + (unsigned) HB_SANITIZE_MAX_OPS_MIN, + (unsigned) HB_SANITIZE_MAX_OPS_MAX); + this->edit_count = 0; + this->debug_depth = 0; + + DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1, + "start [%p..%p] (%lu bytes)", + this->start, this->end, + (unsigned long) (this->end - this->start)); + } + + void end_processing () + { + DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1, + "end [%p..%p] %u edit requests", + this->start, this->end, this->edit_count); + + hb_blob_destroy (this->blob); + this->blob = nullptr; + this->start = this->end = nullptr; + } + + unsigned get_edit_count () { return edit_count; } + + bool check_range (const void *base, + unsigned int len) const + { + const char *p = (const char *) base; + bool ok = !len || + (this->start <= p && + p <= this->end && + (unsigned int) (this->end - p) >= len && + this->max_ops-- > 0); + + DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, + "check_range [%p..%p]" + " (%d bytes) in [%p..%p] -> %s", + p, p + len, len, + this->start, this->end, + ok ? "OK" : "OUT-OF-RANGE"); + + return likely (ok); + } + + template + bool check_range (const T *base, + unsigned int a, + unsigned int b) const + { + return !hb_unsigned_mul_overflows (a, b) && + this->check_range (base, a * b); + } + + template + bool check_range (const T *base, + unsigned int a, + unsigned int b, + unsigned int c) const + { + return !hb_unsigned_mul_overflows (a, b) && + this->check_range (base, a * b, c); + } + + template + bool check_array (const T *base, unsigned int len) const + { + return this->check_range (base, len, hb_static_size (T)); + } + + template + bool check_array (const T *base, + unsigned int a, + unsigned int b) const + { + return this->check_range (base, a, b, hb_static_size (T)); + } + + template + bool check_struct (const Type *obj) const + { return likely (this->check_range (obj, obj->min_size)); } + + bool may_edit (const void *base, unsigned int len) + { + if (this->edit_count >= HB_SANITIZE_MAX_EDITS) + return false; + + const char *p = (const char *) base; + this->edit_count++; + + DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0, + "may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s", + this->edit_count, + p, p + len, len, + this->start, this->end, + this->writable ? "GRANTED" : "DENIED"); + + return this->writable; + } + + template + bool try_set (const Type *obj, const ValueType &v) + { + if (this->may_edit (obj, hb_static_size (Type))) + { + * const_cast (obj) = v; + return true; + } + return false; + } + + template + hb_blob_t *sanitize_blob (hb_blob_t *blob) + { + bool sane; + + init (blob); + + retry: + DEBUG_MSG_FUNC (SANITIZE, start, "start"); + + start_processing (); + + if (unlikely (!start)) + { + end_processing (); + return blob; + } + + Type *t = reinterpret_cast (const_cast (start)); + + sane = t->sanitize (this); + if (sane) + { + if (edit_count) + { + DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count); + + /* sanitize again to ensure no toe-stepping */ + edit_count = 0; + sane = t->sanitize (this); + if (edit_count) { + DEBUG_MSG_FUNC (SANITIZE, start, "requested %d edits in second round; FAILLING", edit_count); + sane = false; + } + } + } + else + { + if (edit_count && !writable) { + start = hb_blob_get_data_writable (blob, nullptr); + end = start + blob->length; + + if (start) + { + writable = true; + /* ok, we made it writable by relocating. try again */ + DEBUG_MSG_FUNC (SANITIZE, start, "retry"); + goto retry; + } + } + } + + end_processing (); + + DEBUG_MSG_FUNC (SANITIZE, start, sane ? "PASSED" : "FAILED"); + if (sane) + { + hb_blob_make_immutable (blob); + return blob; + } + else + { + hb_blob_destroy (blob); + return hb_blob_get_empty (); + } + } + + template + hb_blob_t *reference_table (const hb_face_t *face, hb_tag_t tableTag = Type::tableTag) + { + if (!num_glyphs_set) + set_num_glyphs (hb_face_get_glyph_count (face)); + return sanitize_blob (hb_face_reference_table (face, tableTag)); + } + + const char *start, *end; + mutable int max_ops, max_subtables; + private: + bool writable; + unsigned int edit_count; + hb_blob_t *blob; + unsigned int num_glyphs; + bool num_glyphs_set; +}; + +struct hb_sanitize_with_object_t +{ + template + hb_sanitize_with_object_t (hb_sanitize_context_t *c, const T& obj) : c (c) + { c->set_object (obj); } + ~hb_sanitize_with_object_t () + { c->reset_object (); } + + private: + hb_sanitize_context_t *c; +}; + + +#endif /* HB_SANITIZE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh new file mode 100644 index 00000000000..e0ceae2c4a1 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-serialize.hh @@ -0,0 +1,553 @@ +/* + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. + * Copyright © 2012,2018 Google, Inc. + * Copyright © 2019 Facebook, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + * Facebook Author(s): Behdad Esfahbod + */ + +#ifndef HB_SERIALIZE_HH +#define HB_SERIALIZE_HH + +#include "hb.hh" +#include "hb-blob.hh" +#include "hb-map.hh" +#include "hb-pool.hh" + + +/* + * Serialize + */ + +struct hb_serialize_context_t +{ + typedef unsigned objidx_t; + + enum whence_t { + Head, /* Relative to the current object head (default). */ + Tail, /* Relative to the current object tail after packed. */ + Absolute /* Absolute: from the start of the serialize buffer. */ + }; + + struct object_t + { + void fini () { links.fini (); } + + bool operator == (const object_t &o) const + { + return (tail - head == o.tail - o.head) + && (links.length == o.links.length) + && 0 == hb_memcmp (head, o.head, tail - head) + && links.as_bytes () == o.links.as_bytes (); + } + uint32_t hash () const + { + return hb_bytes_t (head, tail - head).hash () ^ + links.as_bytes ().hash (); + } + + struct link_t + { + bool is_wide: 1; + bool is_signed: 1; + unsigned whence: 2; + unsigned position: 28; + unsigned bias; + objidx_t objidx; + }; + + char *head; + char *tail; + hb_vector_t links; + object_t *next; + }; + + struct snapshot_t + { + char *head; + char *tail; + object_t *current; // Just for sanity check + unsigned num_links; + }; + + snapshot_t snapshot () + { return snapshot_t { head, tail, current, current->links.length }; } + + hb_serialize_context_t (void *start_, unsigned int size) : + start ((char *) start_), + end (start + size), + current (nullptr) + { reset (); } + ~hb_serialize_context_t () { fini (); } + + void fini () + { + for (object_t *_ : ++hb_iter (packed)) _->fini (); + packed.fini (); + this->packed_map.fini (); + + while (current) + { + auto *_ = current; + current = current->next; + _->fini (); + } + object_pool.fini (); + } + + bool in_error () const { return !this->successful; } + + void reset () + { + this->successful = true; + this->ran_out_of_room = false; + this->head = this->start; + this->tail = this->end; + this->debug_depth = 0; + + fini (); + this->packed.push (nullptr); + } + + bool check_success (bool success) + { return this->successful && (success || (err_other_error (), false)); } + + template + bool check_equal (T1 &&v1, T2 &&v2) + { return check_success ((long long) v1 == (long long) v2); } + + template + bool check_assign (T1 &v1, T2 &&v2) + { return check_equal (v1 = v2, v2); } + + template bool propagate_error (T &&obj) + { return check_success (!hb_deref (obj).in_error ()); } + + template bool propagate_error (T1 &&o1, Ts&&... os) + { return propagate_error (hb_forward (o1)) && + propagate_error (hb_forward (os)...); } + + /* To be called around main operation. */ + template + Type *start_serialize () + { + DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1, + "start [%p..%p] (%lu bytes)", + this->start, this->end, + (unsigned long) (this->end - this->start)); + + assert (!current); + return push (); + } + void end_serialize () + { + DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1, + "end [%p..%p] serialized %u bytes; %s", + this->start, this->end, + (unsigned) (this->head - this->start), + this->successful ? "successful" : "UNSUCCESSFUL"); + + propagate_error (packed, packed_map); + + if (unlikely (!current)) return; + if (unlikely (in_error())) return; + + assert (!current->next); + + /* Only "pack" if there exist other objects... Otherwise, don't bother. + * Saves a move. */ + if (packed.length <= 1) + return; + + pop_pack (false); + + resolve_links (); + } + + template + Type *push () + { + if (unlikely (in_error ())) return start_embed (); + + object_t *obj = object_pool.alloc (); + if (unlikely (!obj)) + check_success (false); + else + { + obj->head = head; + obj->tail = tail; + obj->next = current; + current = obj; + } + return start_embed (); + } + void pop_discard () + { + object_t *obj = current; + if (unlikely (!obj)) return; + if (unlikely (in_error())) return; + + current = current->next; + revert (obj->head, obj->tail); + obj->fini (); + object_pool.free (obj); + } + + /* Set share to false when an object is unlikely sharable with others + * so not worth an attempt, or a contiguous table is serialized as + * multiple consecutive objects in the reverse order so can't be shared. + */ + objidx_t pop_pack (bool share=true) + { + object_t *obj = current; + if (unlikely (!obj)) return 0; + if (unlikely (in_error())) return 0; + + current = current->next; + obj->tail = head; + obj->next = nullptr; + unsigned len = obj->tail - obj->head; + head = obj->head; /* Rewind head. */ + + if (!len) + { + assert (!obj->links.length); + return 0; + } + + objidx_t objidx; + if (share) + { + objidx = packed_map.get (obj); + if (objidx) + { + obj->fini (); + return objidx; + } + } + + tail -= len; + memmove (tail, obj->head, len); + + obj->head = tail; + obj->tail = tail + len; + + packed.push (obj); + + if (unlikely (packed.in_error ())) { + // obj wasn't successfully added to packed, so clean it up otherwise it's + // links will be leaked. + propagate_error (packed); + obj->fini (); + return 0; + } + + objidx = packed.length - 1; + + if (share) packed_map.set (obj, objidx); + propagate_error (packed_map); + + return objidx; + } + + void revert (snapshot_t snap) + { + if (unlikely (in_error ())) return; + assert (snap.current == current); + current->links.shrink (snap.num_links); + revert (snap.head, snap.tail); + } + + void revert (char *snap_head, + char *snap_tail) + { + if (unlikely (in_error ())) return; + assert (snap_head <= head); + assert (tail <= snap_tail); + head = snap_head; + tail = snap_tail; + discard_stale_objects (); + } + + void discard_stale_objects () + { + if (unlikely (in_error ())) return; + while (packed.length > 1 && + packed.tail ()->head < tail) + { + packed_map.del (packed.tail ()); + assert (!packed.tail ()->next); + packed.tail ()->fini (); + packed.pop (); + } + if (packed.length > 1) + assert (packed.tail ()->head == tail); + } + + template + void add_link (T &ofs, objidx_t objidx, + whence_t whence = Head, + unsigned bias = 0) + { + static_assert (sizeof (T) == 2 || sizeof (T) == 4, ""); + if (unlikely (in_error ())) return; + + if (!objidx) + return; + + assert (current); + assert (current->head <= (const char *) &ofs); + + auto& link = *current->links.push (); + + link.is_wide = sizeof (T) == 4; + link.is_signed = hb_is_signed (hb_unwrap_type (T)); + link.whence = (unsigned) whence; + link.position = (const char *) &ofs - current->head; + link.bias = bias; + link.objidx = objidx; + } + + unsigned to_bias (const void *base) const + { + if (unlikely (in_error ())) return 0; + if (!base) return 0; + assert (current); + assert (current->head <= (const char *) base); + return (const char *) base - current->head; + } + + void resolve_links () + { + if (unlikely (in_error ())) return; + + assert (!current); + assert (packed.length > 1); + + for (const object_t* parent : ++hb_iter (packed)) + for (const object_t::link_t &link : parent->links) + { + const object_t* child = packed[link.objidx]; + if (unlikely (!child)) { err_other_error(); return; } + unsigned offset = 0; + switch ((whence_t) link.whence) { + case Head: offset = child->head - parent->head; break; + case Tail: offset = child->head - parent->tail; break; + case Absolute: offset = (head - start) + (child->head - tail); break; + } + + assert (offset >= link.bias); + offset -= link.bias; + if (link.is_signed) + { + if (link.is_wide) + assign_offset (parent, link, offset); + else + assign_offset (parent, link, offset); + } + else + { + if (link.is_wide) + assign_offset (parent, link, offset); + else + assign_offset (parent, link, offset); + } + } + } + + unsigned int length () const + { + if (unlikely (!current)) return 0; + return this->head - current->head; + } + + void align (unsigned int alignment) + { + unsigned int l = length () % alignment; + if (l) + allocate_size (alignment - l); + } + + template + Type *start_embed (const Type *obj HB_UNUSED = nullptr) const + { return reinterpret_cast (this->head); } + template + Type *start_embed (const Type &obj) const + { return start_embed (hb_addressof (obj)); } + + /* Following two functions exist to allow setting breakpoint on. */ + void err_ran_out_of_room () { this->ran_out_of_room = true; } + void err_other_error () { this->successful = false; } + + template + Type *allocate_size (unsigned int size) + { + if (unlikely (!this->successful)) return nullptr; + + if (this->tail - this->head < ptrdiff_t (size)) + { + err_ran_out_of_room (); + this->successful = false; + return nullptr; + } + memset (this->head, 0, size); + char *ret = this->head; + this->head += size; + return reinterpret_cast (ret); + } + + template + Type *allocate_min () + { return this->allocate_size (Type::min_size); } + + template + Type *embed (const Type *obj) + { + unsigned int size = obj->get_size (); + Type *ret = this->allocate_size (size); + if (unlikely (!ret)) return nullptr; + memcpy (ret, obj, size); + return ret; + } + template + Type *embed (const Type &obj) + { return embed (hb_addressof (obj)); } + + template auto + _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN + (Type *, src.copy (this, hb_forward (ds)...)) + + template auto + _copy (const Type &src, hb_priority<0>) -> decltype (&(hb_declval () = src)) + { + Type *ret = this->allocate_size (sizeof (Type)); + if (unlikely (!ret)) return nullptr; + *ret = src; + return ret; + } + + /* Like embed, but active: calls obj.operator=() or obj.copy() to transfer data + * instead of memcpy(). */ + template + Type *copy (const Type &src, Ts&&... ds) + { return _copy (src, hb_prioritize, hb_forward (ds)...); } + template + Type *copy (const Type *src, Ts&&... ds) + { return copy (*src, hb_forward (ds)...); } + + template + void copy_all (Iterator it, Ts&&... ds) + { for (decltype (*it) _ : it) copy (_, hb_forward (ds)...); } + + template + hb_serialize_context_t& operator << (const Type &obj) & { embed (obj); return *this; } + + template + Type *extend_size (Type *obj, unsigned int size) + { + if (unlikely (in_error ())) return nullptr; + + assert (this->start <= (char *) obj); + assert ((char *) obj <= this->head); + assert ((char *) obj + size >= this->head); + if (unlikely (!this->allocate_size (((char *) obj) + size - this->head))) return nullptr; + return reinterpret_cast (obj); + } + template + Type *extend_size (Type &obj, unsigned int size) + { return extend_size (hb_addressof (obj), size); } + + template + Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); } + template + Type *extend_min (Type &obj) { return extend_min (hb_addressof (obj)); } + + template + Type *extend (Type *obj, Ts&&... ds) + { return extend_size (obj, obj->get_size (hb_forward (ds)...)); } + template + Type *extend (Type &obj, Ts&&... ds) + { return extend (hb_addressof (obj), hb_forward (ds)...); } + + /* Output routines. */ + hb_bytes_t copy_bytes () const + { + assert (this->successful); + /* Copy both items from head side and tail side... */ + unsigned int len = (this->head - this->start) + + (this->end - this->tail); + + char *p = (char *) malloc (len); + if (unlikely (!p)) return hb_bytes_t (); + + memcpy (p, this->start, this->head - this->start); + memcpy (p + (this->head - this->start), this->tail, this->end - this->tail); + return hb_bytes_t (p, len); + } + template + Type *copy () const + { return reinterpret_cast ((char *) copy_bytes ().arrayZ); } + hb_blob_t *copy_blob () const + { + hb_bytes_t b = copy_bytes (); + return hb_blob_create (b.arrayZ, b.length, + HB_MEMORY_MODE_WRITABLE, + (char *) b.arrayZ, free); + } + + private: + template + void assign_offset (const object_t* parent, const object_t::link_t &link, unsigned offset) + { + auto &off = * ((BEInt *) (parent->head + link.position)); + assert (0 == off); + check_assign (off, offset); + } + + public: /* TODO Make private. */ + char *start, *head, *tail, *end; + unsigned int debug_depth; + bool successful; + bool ran_out_of_room; + + private: + + /* Object memory pool. */ + hb_pool_t object_pool; + + /* Stack of currently under construction objects. */ + object_t *current; + + /* Stack of packed objects. Object 0 is always nil object. */ + hb_vector_t packed; + + /* Map view of packed objects. */ + hb_hashmap_t packed_map; +}; + + +#endif /* HB_SERIALIZE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-set.cc b/src/java.desktop/share/native/libharfbuzz/hb-set.cc index 7dff3319963..fb40368965e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-set.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-set.cc @@ -69,7 +69,7 @@ hb_set_create () hb_set_t * hb_set_get_empty () { - return const_cast (&Null(hb_set_t)); + return const_cast (&Null (hb_set_t)); } /** @@ -389,6 +389,7 @@ hb_set_symmetric_difference (hb_set_t *set, set->symmetric_difference (other); } +#ifndef HB_DISABLE_DEPRECATED /** * hb_set_invert: * @set: a set. @@ -403,6 +404,7 @@ void hb_set_invert (hb_set_t *set HB_UNUSED) { } +#endif /** * hb_set_get_population: @@ -477,7 +479,7 @@ hb_set_next (const hb_set_t *set, * @set: a set. * @codepoint: (inout): * - * Gets the previous number in @set that is slower than current value of @codepoint. + * Gets the previous number in @set that is lower than current value of @codepoint. * * Set @codepoint to %HB_SET_VALUE_INVALID to get started. * @@ -522,7 +524,7 @@ hb_set_next_range (const hb_set_t *set, * @last: (out): output last codepoint in the range. * * Gets the previous consecutive range of numbers in @set that - * are greater than current value of @last. + * are less than current value of @first. * * Set @first to %HB_SET_VALUE_INVALID to get started. * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-set.hh b/src/java.desktop/share/native/libharfbuzz/hb-set.hh index 6b426949eb1..93ba0d0aa74 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-set.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-set.hh @@ -28,6 +28,7 @@ #define HB_SET_HH #include "hb.hh" +#include "hb-machinery.hh" /* @@ -39,7 +40,7 @@ struct hb_set_t { - HB_NO_COPY_ASSIGN (hb_set_t); + HB_DELETE_COPY_ASSIGN (hb_set_t); hb_set_t () { init (); } ~hb_set_t () { fini (); } @@ -69,7 +70,7 @@ struct hb_set_t void add (hb_codepoint_t g) { elt (g) |= mask (g); } void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } - bool has (hb_codepoint_t g) const { return !!(elt (g) & mask (g)); } + bool get (hb_codepoint_t g) const { return elt (g) & mask (g); } void add_range (hb_codepoint_t a, hb_codepoint_t b) { @@ -88,6 +89,23 @@ struct hb_set_t } } + void del_range (hb_codepoint_t a, hb_codepoint_t b) + { + elt_t *la = &elt (a); + elt_t *lb = &elt (b); + if (la == lb) + *la &= ~((mask (b) << 1) - mask(a)); + else + { + *la &= mask (a) - 1; + la++; + + memset (la, 0, (char *) lb - (char *) la); + + *lb &= ~((mask (b) << 1) - 1); + } + } + bool is_equal (const page_t *other) const { return 0 == hb_memcmp (&v, &other->v, sizeof (v)); @@ -134,13 +152,22 @@ struct hb_set_t unsigned int i = m / ELT_BITS; unsigned int j = m & ELT_MASK; - const elt_t vv = v[i] & ((elt_t (1) << (j + 1)) - 1); - for (const elt_t *p = &vv; (int) i >= 0; p = &v[--i]) + /* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */ + const elt_t mask = j < 8 * sizeof (elt_t) - 1 ? + ((elt_t (1) << (j + 1)) - 1) : + (elt_t) -1; + const elt_t vv = v[i] & mask; + const elt_t *p = &vv; + while (true) + { if (*p) { *codepoint = i * ELT_BITS + elt_get_max (*p); return true; } + if ((int) i <= 0) break; + p = &v[--i]; + } *codepoint = INVALID; return false; @@ -186,7 +213,7 @@ struct hb_set_t hb_object_header_t header; bool successful; /* Allocations successful */ mutable unsigned int population; - hb_vector_t page_map; + hb_sorted_vector_t page_map; hb_vector_t pages; void init_shallow () @@ -227,11 +254,18 @@ struct hb_set_t return true; } - void clear () + void reset () { if (unlikely (hb_object_is_immutable (this))) return; + clear (); successful = true; + } + + void clear () + { + if (unlikely (hb_object_is_immutable (this))) + return; population = 0; page_map.resize (0); pages.resize (0); @@ -245,7 +279,7 @@ struct hb_set_t return true; } - void dirty () { population = (unsigned int) -1; } + void dirty () { population = UINT_MAX; } void add (hb_codepoint_t g) { @@ -301,7 +335,7 @@ struct hb_set_t { page->add (g); - array = (const T *) ((const char *) array + stride); + array = &StructAtOffsetUnaligned (array, stride); count--; } while (count && (g = *array, start <= g && g < end)); @@ -349,23 +383,79 @@ struct hb_set_t dirty (); page->del (g); } + + private: + void del_pages (int ds, int de) + { + if (ds <= de) + { + unsigned int write_index = 0; + for (unsigned int i = 0; i < page_map.length; i++) + { + int m = (int) page_map[i].major; + if (m < ds || de < m) + page_map[write_index++] = page_map[i]; + } + compact (write_index); + resize (write_index); + } + } + + public: void del_range (hb_codepoint_t a, hb_codepoint_t b) { /* TODO perform op even if !successful. */ - /* TODO Optimize, like add_range(). */ if (unlikely (!successful)) return; - for (unsigned int i = a; i < b + 1; i++) - del (i); + if (unlikely (a > b || a == INVALID || b == INVALID)) return; + dirty (); + unsigned int ma = get_major (a); + unsigned int mb = get_major (b); + /* Delete pages from ds through de if ds <= de. */ + int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1); + int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1); + if (ds > de || (int) ma < ds) + { + page_t *page = page_for (a); + if (page) + { + if (ma == mb) + page->del_range (a, b); + else + page->del_range (a, major_start (ma + 1) - 1); + } + } + if (de < (int) mb && ma != mb) + { + page_t *page = page_for (b); + if (page) + page->del_range (major_start (mb), b); + } + del_pages (ds, de); } - bool has (hb_codepoint_t g) const + + bool get (hb_codepoint_t g) const { const page_t *page = page_for (g); if (!page) return false; - return page->has (g); + return page->get (g); } - bool intersects (hb_codepoint_t first, - hb_codepoint_t last) const + + /* Has interface. */ + static constexpr bool SENTINEL = false; + typedef bool value_t; + value_t operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + /* Predicate. */ + bool operator () (hb_codepoint_t k) const { return has (k); } + + /* Sink interface. */ + hb_set_t& operator << (hb_codepoint_t v) + { add (v); return *this; } + hb_set_t& operator << (const hb_pair_t& range) + { add_range (range.first, range.second); return *this; } + + bool intersects (hb_codepoint_t first, hb_codepoint_t last) const { hb_codepoint_t c = first - 1; return next (&c) && c <= last; @@ -422,8 +512,36 @@ struct hb_set_t return true; } - template - void process (const hb_set_t *other) + void compact (unsigned int length) + { + hb_vector_t old_index_to_page_map_index; + old_index_to_page_map_index.resize(pages.length); + for (uint32_t i = 0; i < old_index_to_page_map_index.length; i++) + old_index_to_page_map_index[i] = 0xFFFFFFFF; + + for (uint32_t i = 0; i < length; i++) + old_index_to_page_map_index[page_map[i].index] = i; + + compact_pages (old_index_to_page_map_index); + } + + void compact_pages (const hb_vector_t& old_index_to_page_map_index) + { + unsigned int write_index = 0; + for (unsigned int i = 0; i < pages.length; i++) + { + if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue; + + if (write_index < i) + pages[write_index] = pages[i]; + + page_map[old_index_to_page_map_index[i]].index = write_index; + write_index++; + } + } + + template + void process (const Op& op, const hb_set_t *other) { if (unlikely (!successful)) return; @@ -435,10 +553,22 @@ struct hb_set_t unsigned int count = 0, newCount = 0; unsigned int a = 0, b = 0; + unsigned int write_index = 0; for (; a < na && b < nb; ) { if (page_map[a].major == other->page_map[b].major) { + if (!Op::passthru_left) + { + // Move page_map entries that we're keeping from the left side set + // to the front of the page_map vector. This isn't necessary if + // passthru_left is set since no left side pages will be removed + // in that case. + if (write_index < a) + page_map[write_index] = page_map[a]; + write_index++; + } + count++; a++; b++; @@ -461,9 +591,16 @@ struct hb_set_t if (Op::passthru_right) count += nb - b; - if (count > pages.length) - if (!resize (count)) - return; + if (!Op::passthru_left) + { + na = write_index; + next_page = write_index; + compact (write_index); + } + + if (!resize (count)) + return; + newCount = count; /* Process in-place backward. */ @@ -477,7 +614,7 @@ struct hb_set_t b--; count--; page_map[count] = page_map[a]; - Op::process (page_at (count).v, page_at (a).v, other->page_at (b).v); + page_at (count).v = op (page_at (a).v, other->page_at (b).v); } else if (page_map[a - 1].major > other->page_map[b - 1].major) { @@ -523,19 +660,19 @@ struct hb_set_t void union_ (const hb_set_t *other) { - process (other); + process (hb_bitwise_or, other); } void intersect (const hb_set_t *other) { - process (other); + process (hb_bitwise_and, other); } void subtract (const hb_set_t *other) { - process (other); + process (hb_bitwise_sub, other); } void symmetric_difference (const hb_set_t *other) { - process (other); + process (hb_bitwise_xor, other); } bool next (hb_codepoint_t *codepoint) const { @@ -638,7 +775,7 @@ struct hb_set_t unsigned int get_population () const { - if (population != (unsigned int) -1) + if (population != UINT_MAX) return population; unsigned int pop = 0; @@ -671,27 +808,36 @@ struct hb_set_t /* * Iterator implementation. */ - struct const_iter_t : hb_sorted_iter_t + struct iter_t : hb_iter_with_fallback_t { - const_iter_t (const hb_set_t &s_) : - s (s_), v (INVALID), l (s.get_population () + 1) { __next__ (); } + static constexpr bool is_sorted_iterator = true; + iter_t (const hb_set_t &s_ = Null (hb_set_t), + bool init = true) : s (&s_), v (INVALID), l(0) + { + if (init) + { + l = s->get_population () + 1; + __next__ (); + } + } - typedef hb_codepoint_t __item_type__; + typedef hb_codepoint_t __item_t__; hb_codepoint_t __item__ () const { return v; } bool __more__ () const { return v != INVALID; } - void __next__ () { s.next (&v); if (l) l--; } - void __prev__ () { s.previous (&v); } - unsigned __len__ () { return l; } + void __next__ () { s->next (&v); if (l) l--; } + void __prev__ () { s->previous (&v); } + unsigned __len__ () const { return l; } + iter_t end () const { return iter_t (*s, false); } + bool operator != (const iter_t& o) const + { return s != o.s || v != o.v; } protected: - const hb_set_t &s; + const hb_set_t *s; hb_codepoint_t v; unsigned l; }; - const_iter_t const_iter () const { return const_iter_t (*this); } - operator const_iter_t () const { return const_iter (); } - typedef const_iter_t iter_t; - iter_t iter () const { return const_iter (); } + iter_t iter () const { return iter_t (*this); } + operator iter_t () const { return iter (); } protected: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc index 800cf0a12f5..3243effb3a5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.cc @@ -79,7 +79,9 @@ hb_shape_plan_key_t::init (bool copy, } this->shaper_func = nullptr; this->shaper_name = nullptr; +#ifndef HB_NO_OT_SHAPE this->ot.init (face, coords, num_coords); +#endif /* * Choose shaper. @@ -148,7 +150,9 @@ hb_shape_plan_key_t::equal (const hb_shape_plan_key_t *other) { return hb_segment_properties_equal (&this->props, &other->props) && this->user_features_match (other) && +#ifndef HB_NO_OT_SHAPE this->ot.equal (&other->ot) && +#endif this->shaper_func == other->shaper_func; } @@ -224,12 +228,16 @@ hb_shape_plan_create2 (hb_face_t *face, num_coords, shaper_list))) goto bail2; +#ifndef HB_NO_OT_SHAPE if (unlikely (!shape_plan->ot.init0 (face, &shape_plan->key))) goto bail3; +#endif return shape_plan; +#ifndef HB_NO_OT_SHAPE bail3: +#endif shape_plan->key.free (); bail2: free (shape_plan); @@ -249,7 +257,7 @@ hb_shape_plan_create2 (hb_face_t *face, hb_shape_plan_t * hb_shape_plan_get_empty () { - return const_cast (&Null(hb_shape_plan_t)); + return const_cast (&Null (hb_shape_plan_t)); } /** @@ -281,7 +289,9 @@ hb_shape_plan_destroy (hb_shape_plan_t *shape_plan) { if (!hb_object_destroy (shape_plan)) return; +#ifndef HB_NO_OT_SHAPE shape_plan->ot.fini (); +#endif shape_plan->key.free (); free (shape_plan); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh index a99cfc3eea7..debe6596330 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-shape-plan.hh @@ -39,21 +39,23 @@ struct hb_shape_plan_key_t const hb_feature_t *user_features; unsigned int num_user_features; +#ifndef HB_NO_OT_SHAPE hb_ot_shape_plan_key_t ot; +#endif hb_shape_func_t *shaper_func; const char *shaper_name; - HB_INTERNAL inline bool init (bool copy, - hb_face_t *face, - const hb_segment_properties_t *props, - const hb_feature_t *user_features, - unsigned int num_user_features, - const int *coords, - unsigned int num_coords, - const char * const *shaper_list); + HB_INTERNAL bool init (bool copy, + hb_face_t *face, + const hb_segment_properties_t *props, + const hb_feature_t *user_features, + unsigned int num_user_features, + const int *coords, + unsigned int num_coords, + const char * const *shaper_list); - HB_INTERNAL inline void free () { ::free ((void *) user_features); } + HB_INTERNAL void free () { ::free ((void *) user_features); } HB_INTERNAL bool user_features_match (const hb_shape_plan_key_t *other); @@ -65,7 +67,9 @@ struct hb_shape_plan_t hb_object_header_t header; hb_face_t *face_unsafe; /* We don't carry a reference to face. */ hb_shape_plan_key_t key; +#ifndef HB_NO_OT_SHAPE hb_ot_shape_plan_t ot; +#endif }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc index 90876d658bd..5dc55febb02 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shape.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-shape.cc @@ -132,6 +132,8 @@ hb_shape_full (hb_font_t *font, unsigned int num_features, const char * const *shaper_list) { + if (unlikely (hb_object_is_immutable (buffer))) return false; + hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props, features, num_features, font->coords, font->num_coords, @@ -154,7 +156,9 @@ hb_shape_full (hb_font_t *font, * * Shapes @buffer using @font turning its Unicode characters content to * positioned glyphs. If @features is not %NULL, it will be used to control the - * features applied during shaping. + * features applied during shaping. If two @features have the same tag but + * overlapping ranges the value of the feature with the higher index takes + * precedence. * * Since: 0.9.2 **/ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh index 36d8fc7f660..0d63933a766 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-shaper-list.hh @@ -28,6 +28,9 @@ #define HB_SHAPER_LIST_HH #endif /* HB_SHAPER_LIST_HH */ /* Dummy header guards */ +#ifndef HB_NO_SHAPER + + /* v--- Add new shapers in the right place here. */ #ifdef HAVE_GRAPHITE2 @@ -35,7 +38,9 @@ HB_SHAPER_IMPLEMENT (graphite2) #endif +#ifndef HB_NO_OT_SHAPE HB_SHAPER_IMPLEMENT (ot) /* <--- This is our main OpenType shaper. */ +#endif #ifdef HAVE_UNISCRIBE HB_SHAPER_IMPLEMENT (uniscribe) @@ -45,12 +50,11 @@ HB_SHAPER_IMPLEMENT (directwrite) #endif #ifdef HAVE_CORETEXT HB_SHAPER_IMPLEMENT (coretext) - -/* Only picks up fonts that have a "mort" or "morx" table. - Probably going to be removed https://github.com/harfbuzz/harfbuzz/issues/1478 */ -HB_SHAPER_IMPLEMENT (coretext_aat) #endif -#ifdef HAVE_FALLBACK +#ifndef HB_NO_FALLBACK_SHAPE HB_SHAPER_IMPLEMENT (fallback) /* <--- This should be last. */ #endif + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shaper.cc b/src/java.desktop/share/native/libharfbuzz/hb-shaper.cc index 158b454bf1d..b1d76dcc4ee 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shaper.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-shaper.cc @@ -34,6 +34,9 @@ static const hb_shaper_entry_t all_shapers[] = { #include "hb-shaper-list.hh" #undef HB_SHAPER_IMPLEMENT }; +#ifndef HB_NO_SHAPER +static_assert (0 != ARRAY_LENGTH_CONST (all_shapers), "No shaper enabled."); +#endif #if HB_USE_ATEXIT static void free_static_shapers (); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-shaper.hh b/src/java.desktop/share/native/libharfbuzz/hb-shaper.hh index 37ca9ffb665..0c9b681519d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-shaper.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-shaper.hh @@ -102,7 +102,7 @@ template struct hb_shaper_object static void destroy (Type *p) { HB_SHAPER_DATA_DESTROY_FUNC (shaper, object) (p); } \ }; \ \ - static_assert (true, "") /* Require semicolon. */ + static_assert (true, "") /* Require semicolon after. */ template diff --git a/src/java.desktop/share/native/libharfbuzz/hb-static.cc b/src/java.desktop/share/native/libharfbuzz/hb-static.cc index 4c515886024..b213c57c7e5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-static.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-static.cc @@ -37,9 +37,10 @@ #include "hb-ot-maxp-table.hh" #ifndef HB_NO_VISIBILITY +#include "hb-ot-name-language-static.hh" -hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {}; -/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)] = {}; +uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {}; +/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)] = {}; DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF}; DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00}; @@ -50,6 +51,9 @@ DEFINE_NULL_NAMESPACE_BYTES (AAT, SettingName) = {0xFF,0xFF, 0xFF,0xFF}; const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF}; + +/* hb_face_t */ + unsigned int hb_face_t::load_num_glyphs () const { @@ -72,4 +76,37 @@ hb_face_t::load_upem () const return ret; } + +/* hb_user_data_array_t */ + +bool +hb_user_data_array_t::set (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + if (!key) + return false; + + if (replace) { + if (!data && !destroy) { + items.remove (key, lock); + return true; + } + } + hb_user_data_item_t item = {key, data, destroy}; + bool ret = !!items.replace_or_insert (item, lock, (bool) replace); + + return ret; +} + +void * +hb_user_data_array_t::get (hb_user_data_key_t *key) +{ + hb_user_data_item_t item = {nullptr, nullptr, nullptr}; + + return items.find (key, &item, lock) ? item.data : nullptr; +} + + #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh index dffa9f3beba..9d00cae6c32 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-string-array.hh @@ -37,6 +37,7 @@ #define HB_STRING_ARRAY_TYPE_NAME HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr_t) #define HB_STRING_ARRAY_POOL_NAME HB_PASTE(HB_STRING_ARRAY_NAME, _msgstr) #define HB_STRING_ARRAY_OFFS_NAME HB_PASTE(HB_STRING_ARRAY_NAME, _msgidx) +#define HB_STRING_ARRAY_LENG_NAME HB_PASTE(HB_STRING_ARRAY_NAME, _length) static const union HB_STRING_ARRAY_TYPE_NAME { struct { @@ -48,7 +49,7 @@ static const union HB_STRING_ARRAY_TYPE_NAME { #include HB_STRING_ARRAY_LIST #undef _S } st; - char str[VAR]; + char str[HB_VAR_ARRAY]; } HB_STRING_ARRAY_POOL_NAME = { @@ -66,6 +67,8 @@ static const unsigned int HB_STRING_ARRAY_OFFS_NAME[] = sizeof (HB_STRING_ARRAY_TYPE_NAME) }; +static const unsigned int HB_STRING_ARRAY_LENG_NAME = ARRAY_LENGTH_CONST (HB_STRING_ARRAY_OFFS_NAME) - 1; + static inline hb_bytes_t HB_STRING_ARRAY_NAME (unsigned int i) { @@ -77,5 +80,6 @@ HB_STRING_ARRAY_NAME (unsigned int i) #undef HB_STRING_ARRAY_TYPE_NAME #undef HB_STRING_ARRAY_POOL_NAME #undef HB_STRING_ARRAY_OFFS_NAME +#undef HB_STRING_ARRAY_LENG_NAME #endif /* HB_STRING_ARRAY_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-style.cc b/src/java.desktop/share/native/libharfbuzz/hb-style.cc new file mode 100644 index 00000000000..50f9df9a282 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-style.cc @@ -0,0 +1,135 @@ +/* + * Copyright © 2019 Ebrahim Byagowi + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "hb.hh" + +#ifndef HB_NO_STYLE +#ifdef HB_EXPERIMENTAL_API + +#include "hb-ot-var-avar-table.hh" +#include "hb-ot-var-fvar-table.hh" +#include "hb-ot-stat-table.hh" +#include "hb-ot-os2-table.hh" +#include "hb-ot-head-table.hh" +#include "hb-ot-post-table.hh" +#include "hb-ot-face.hh" + +/** + * hb_style_tag_t: + * @HB_STYLE_TAG_ITALIC: Used to vary between non-italic and italic. + * A value of 0 can be interpreted as "Roman" (non-italic); a value of 1 can + * be interpreted as (fully) italic. + * @HB_STYLE_TAG_OPTICAL_SIZE: Used to vary design to suit different text sizes. + * Non-zero. Values can be interpreted as text size, in points. + * @HB_STYLE_TAG_SLANT: Used to vary between upright and slanted text. Values + * must be greater than -90 and less than +90. Values can be interpreted as + * the angle, in counter-clockwise degrees, of oblique slant from whatever the + * designer considers to be upright for that font design. + * @HB_STYLE_TAG_WIDTH: Used to vary width of text from narrower to wider. + * Non-zero. Values can be interpreted as a percentage of whatever the font + * designer considers “normal width” for that font design. + * @HB_STYLE_TAG_WEIGHT: Used to vary stroke thicknesses or other design details + * to give variation from lighter to blacker. Values can be interpreted in direct + * comparison to values for usWeightClass in the OS/2 table, + * or the CSS font-weight property. + * + * Defined by https://docs.microsoft.com/en-us/typography/opentype/spec/dvaraxisreg + * + * Since: EXPERIMENTAL + **/ +typedef enum { + HB_STYLE_TAG_ITALIC = HB_TAG ('i','t','a','l'), + HB_STYLE_TAG_OPTICAL_SIZE = HB_TAG ('o','p','s','z'), + HB_STYLE_TAG_SLANT = HB_TAG ('s','l','n','t'), + HB_STYLE_TAG_WIDTH = HB_TAG ('w','d','t','h'), + HB_STYLE_TAG_WEIGHT = HB_TAG ('w','g','h','t'), + + _HB_STYLE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ +} hb_style_tag_t; + +/** + * hb_style_get_value: + * @font: a #hb_font_t object. + * @style_tag: a style tag. + * + * Searches variation axes of a hb_font_t object for a specific axis first, + * if not set, then tries to get default style values from different + * tables of the font. + * + * Returns: Corresponding axis or default value to a style tag. + * + * Since: EXPERIMENTAL + **/ +float +hb_style_get_value (hb_font_t *font, hb_tag_t tag) +{ + hb_style_tag_t style_tag = (hb_style_tag_t) tag; + hb_face_t *face = font->face; + +#ifndef HB_NO_VAR + hb_ot_var_axis_info_t axis; + if (hb_ot_var_find_axis_info (face, style_tag, &axis)) + { + if (axis.axis_index < font->num_coords) return font->design_coords[axis.axis_index]; + /* If a face is variable, fvar's default_value is better than STAT records */ + return axis.default_value; + } +#endif + + if (style_tag == HB_STYLE_TAG_OPTICAL_SIZE && font->ptem) + return font->ptem; + + /* STAT */ + float value; + if (face->table.STAT->get_value (style_tag, &value)) + return value; + + switch ((unsigned) style_tag) + { + case HB_STYLE_TAG_ITALIC: + return face->table.OS2->is_italic () || face->table.head->is_italic () ? 1 : 0; + case HB_STYLE_TAG_OPTICAL_SIZE: + { + unsigned int lower, upper; + return face->table.OS2->v5 ().get_optical_size (&lower, &upper) + ? (float) (lower + upper) / 2.f + : 12.f; + } + case HB_STYLE_TAG_SLANT: + return face->table.post->table->italicAngle.to_float (); + case HB_STYLE_TAG_WIDTH: + return face->table.OS2->has_data () + ? face->table.OS2->get_width () + : (face->table.head->is_condensed () ? 75 : 100); + case HB_STYLE_TAG_WEIGHT: + return face->table.OS2->has_data () + ? face->table.OS2->usWeightClass + : (face->table.head->is_bold () ? 700 : 400); + default: + return 0; + } +} + +#endif +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-warning.cc b/src/java.desktop/share/native/libharfbuzz/hb-style.h similarity index 70% rename from src/java.desktop/share/native/libharfbuzz/hb-warning.cc rename to src/java.desktop/share/native/libharfbuzz/hb-style.h index 9fb41003808..1209c79e945 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-warning.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-style.h @@ -1,5 +1,5 @@ /* - * Copyright © 2012 Google, Inc. + * Copyright © 2019 Ebrahim Byagowi * * This is part of HarfBuzz, a text shaping library. * @@ -20,18 +20,24 @@ * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod */ -#include "hb.hh" - -#if defined(HB_ATOMIC_INT_NIL) -#error "Could not find any system to define atomic_int macros, library WILL NOT be thread-safe" -#error "Check hb-atomic.hh for possible resolutions." +#ifndef HB_H_IN +#error "Include instead." #endif -#if defined(HB_MUTEX_IMPL_NIL) -#error "Could not find any system to define mutex macros, library WILL NOT be thread-safe" -#error "Check hb-mutex.hh for possible resolutions." +#ifndef HB_STYLE_H +#define HB_STYLE_H + +#include "hb.h" + +HB_BEGIN_DECLS + +#ifdef HB_EXPERIMENTAL_API +HB_EXTERN float +hb_style_get_value (hb_font_t *font, hb_tag_t style_tag); #endif + +HB_END_DECLS + +#endif /* HB_STYLE_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc index 75004fe77ff..e17433152b0 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.cc @@ -24,6 +24,10 @@ * Adobe Author(s): Michiharu Ariza */ +#include "hb.hh" + +#ifndef HB_NO_SUBSET_CFF + #include "hb-ot-cff-common.hh" #include "hb-ot-cff2-table.hh" #include "hb-subset-cff-common.hh" @@ -43,33 +47,39 @@ using namespace CFF; **/ bool -hb_plan_subset_cff_fdselect (const hb_vector_t &glyphs, - unsigned int fdCount, - const FDSelect &src, /* IN */ - unsigned int &subset_fd_count /* OUT */, - unsigned int &subset_fdselect_size /* OUT */, - unsigned int &subset_fdselect_format /* OUT */, - hb_vector_t &fdselect_ranges /* OUT */, - remap_t &fdmap /* OUT */) +hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, + unsigned int fdCount, + const FDSelect &src, /* IN */ + unsigned int &subset_fd_count /* OUT */, + unsigned int &subset_fdselect_size /* OUT */, + unsigned int &subset_fdselect_format /* OUT */, + hb_vector_t &fdselect_ranges /* OUT */, + hb_inc_bimap_t &fdmap /* OUT */) { subset_fd_count = 0; subset_fdselect_size = 0; subset_fdselect_format = 0; - unsigned int num_ranges = 0; + unsigned int num_ranges = 0; - unsigned int subset_num_glyphs = glyphs.length; + unsigned int subset_num_glyphs = plan->num_output_glyphs (); if (subset_num_glyphs == 0) return true; { /* use hb_set to determine the subset of font dicts */ - hb_set_t *set = hb_set_create (); - if (set == &Null (hb_set_t)) - return false; - hb_codepoint_t prev_fd = CFF_UNDEF_CODE; + hb_set_t *set = hb_set_create (); + if (unlikely (set == &Null (hb_set_t))) return false; + hb_codepoint_t prev_fd = CFF_UNDEF_CODE; for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++) { - hb_codepoint_t fd = src.get_fd (glyphs[i]); + hb_codepoint_t glyph; + hb_codepoint_t fd; + if (!plan->old_gid_for_new_gid (i, &glyph)) + { + /* fonttools retains FDSelect & font dicts for missing glyphs. do the same */ + glyph = i; + } + fd = src.get_fd (glyph); set->add (fd); if (fd != prev_fd) @@ -91,17 +101,13 @@ hb_plan_subset_cff_fdselect (const hb_vector_t &glyphs, else { /* create a fdmap */ - if (!fdmap.reset (fdCount)) - { - hb_set_destroy (set); - return false; - } + fdmap.reset (); - hb_codepoint_t fd = CFF_UNDEF_CODE; + hb_codepoint_t fd = CFF_UNDEF_CODE; while (set->next (&fd)) fdmap.add (fd); hb_set_destroy (set); - if (unlikely (fdmap.get_count () != subset_fd_count)) + if (unlikely (fdmap.get_population () != subset_fd_count)) return false; } @@ -145,21 +151,21 @@ hb_plan_subset_cff_fdselect (const hb_vector_t &glyphs, template static inline bool serialize_fdselect_3_4 (hb_serialize_context_t *c, - const unsigned int num_glyphs, - const FDSelect &src, - unsigned int size, - const hb_vector_t &fdselect_ranges) + const unsigned int num_glyphs, + const FDSelect &src, + unsigned int size, + const hb_vector_t &fdselect_ranges) { TRACE_SERIALIZE (this); FDSELECT3_4 *p = c->allocate_size (size); - if (unlikely (p == nullptr)) return_trace (false); - p->nRanges ().set (fdselect_ranges.length); + if (unlikely (!p)) return_trace (false); + p->nRanges () = fdselect_ranges.length; for (unsigned int i = 0; i < fdselect_ranges.length; i++) { - p->ranges[i].first.set (fdselect_ranges[i].glyph); - p->ranges[i].fd.set (fdselect_ranges[i].code); + p->ranges[i].first = fdselect_ranges[i].glyph; + p->ranges[i].fd = fdselect_ranges[i].code; } - p->sentinel().set (num_glyphs); + p->sentinel () = num_glyphs; return_trace (true); } @@ -169,58 +175,53 @@ serialize_fdselect_3_4 (hb_serialize_context_t *c, **/ bool hb_serialize_cff_fdselect (hb_serialize_context_t *c, - const unsigned int num_glyphs, - const FDSelect &src, - unsigned int fd_count, - unsigned int fdselect_format, - unsigned int size, - const hb_vector_t &fdselect_ranges) + const unsigned int num_glyphs, + const FDSelect &src, + unsigned int fd_count, + unsigned int fdselect_format, + unsigned int size, + const hb_vector_t &fdselect_ranges) { TRACE_SERIALIZE (this); - FDSelect *p = c->allocate_min (); - if (unlikely (p == nullptr)) return_trace (false); - p->format.set (fdselect_format); + FDSelect *p = c->allocate_min (); + if (unlikely (!p)) return_trace (false); + p->format = fdselect_format; size -= FDSelect::min_size; switch (fdselect_format) { #if CFF_SERIALIZE_FDSELECT_0 - case 0: + case 0: + { + FDSelect0 *p = c->allocate_size (size); + if (unlikely (!p)) return_trace (false); + unsigned int range_index = 0; + unsigned int fd = fdselect_ranges[range_index++].code; + for (unsigned int i = 0; i < num_glyphs; i++) { - FDSelect0 *p = c->allocate_size (size); - if (unlikely (p == nullptr)) return_trace (false); - unsigned int range_index = 0; - unsigned int fd = fdselect_ranges[range_index++].code; - for (unsigned int i = 0; i < num_glyphs; i++) + if ((range_index < fdselect_ranges.len) && + (i >= fdselect_ranges[range_index].glyph)) { - if ((range_index < fdselect_ranges.len) && - (i >= fdselect_ranges[range_index].glyph)) - { - fd = fdselect_ranges[range_index++].code; - } - p->fds[i].set (fd); + fd = fdselect_ranges[range_index++].code; } - break; + p->fds[i] = fd; } + return_trace (true); + } #endif /* CFF_SERIALIZE_FDSELECT_0 */ - case 3: - return serialize_fdselect_3_4 (c, - num_glyphs, - src, - size, - fdselect_ranges); - - case 4: - return serialize_fdselect_3_4 (c, - num_glyphs, - src, - size, - fdselect_ranges); - - default: - assert(false); - } + case 3: + return serialize_fdselect_3_4 (c, num_glyphs, src, + size, fdselect_ranges); - return_trace (true); + case 4: + return serialize_fdselect_3_4 (c, num_glyphs, src, + size, fdselect_ranges); + + default: + return_trace (false); + } } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh index a3492545ec9..b81864164a9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff-common.hh @@ -44,7 +44,7 @@ struct str_encoder_t void encode_byte (unsigned char b) { - if (unlikely (buff.push (b) == &Crap(unsigned char))) + if (unlikely (buff.push (b) == &Crap (unsigned char))) set_error (); } @@ -110,7 +110,11 @@ struct str_encoder_t void copy_str (const byte_str_t &str) { unsigned int offset = buff.length; - buff.resize (offset + str.length); + if (unlikely (!buff.resize (offset + str.length))) + { + set_error (); + return; + } if (unlikely (buff.length < offset + str.length)) { set_error (); @@ -128,26 +132,17 @@ struct str_encoder_t bool error; }; -struct cff_sub_table_offsets_t { - cff_sub_table_offsets_t () : privateDictsOffset (0) +struct cff_sub_table_info_t { + cff_sub_table_info_t () + : fd_array_link (0), + char_strings_link (0) { - topDictInfo.init (); - FDSelectInfo.init (); - FDArrayInfo.init (); - charStringsInfo.init (); - globalSubrsInfo.init (); - localSubrsInfos.init (); + fd_select.init (); } - ~cff_sub_table_offsets_t () { localSubrsInfos.fini (); } - - table_info_t topDictInfo; - table_info_t FDSelectInfo; - table_info_t FDArrayInfo; - table_info_t charStringsInfo; - unsigned int privateDictsOffset; - table_info_t globalSubrsInfo; - hb_vector_t localSubrsInfos; + table_info_t fd_select; + objidx_t fd_array_link; + objidx_t char_strings_link; }; template @@ -155,40 +150,26 @@ struct cff_top_dict_op_serializer_t : op_serializer_t { bool serialize (hb_serialize_context_t *c, const OPSTR &opstr, - const cff_sub_table_offsets_t &offsets) const + const cff_sub_table_info_t &info) const { TRACE_SERIALIZE (this); switch (opstr.op) { case OpCode_CharStrings: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsInfo.offset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.char_strings_link, whence_t::Absolute)); case OpCode_FDArray: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayInfo.offset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_array_link, whence_t::Absolute)); case OpCode_FDSelect: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.fd_select.link, whence_t::Absolute)); default: return_trace (copy_opstr (c, opstr)); } return_trace (true); } - - unsigned int calculate_serialized_size (const OPSTR &opstr) const - { - switch (opstr.op) - { - case OpCode_CharStrings: - case OpCode_FDArray: - case OpCode_FDSelect: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); - - default: - return opstr.str.length; - } - } }; struct cff_font_dict_op_serializer_t : op_serializer_t @@ -202,33 +183,17 @@ struct cff_font_dict_op_serializer_t : op_serializer_t if (opstr.op == OpCode_Private) { /* serialize the private dict size & offset as 2-byte & 4-byte integers */ - if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) || - !UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset))) - return_trace (false); - - /* serialize the opcode */ - HBUINT8 *p = c->allocate_size (1); - if (unlikely (p == nullptr)) return_trace (false); - p->set (OpCode_Private); - - return_trace (true); + return_trace (UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) && + Dict::serialize_link4_op (c, opstr.op, privateDictInfo.link, whence_t::Absolute)); } else { HBUINT8 *d = c->allocate_size (opstr.str.length); - if (unlikely (d == nullptr)) return_trace (false); + if (unlikely (!d)) return_trace (false); memcpy (d, &opstr.str[0], opstr.str.length); } return_trace (true); } - - unsigned int calculate_serialized_size (const op_str_t &opstr) const - { - if (opstr.op == OpCode_Private) - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); - else - return opstr.str.length; - } }; struct cff_private_dict_op_serializer_t : op_serializer_t @@ -238,7 +203,7 @@ struct cff_private_dict_op_serializer_t : op_serializer_t bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, - const unsigned int subrsOffset) const + objidx_t subrs_link) const { TRACE_SERIALIZE (this); @@ -246,31 +211,15 @@ struct cff_private_dict_op_serializer_t : op_serializer_t return true; if (opstr.op == OpCode_Subrs) { - if (desubroutinize || (subrsOffset == 0)) + if (desubroutinize || !subrs_link) return_trace (true); else - return_trace (FontDict::serialize_offset2_op (c, opstr.op, subrsOffset)); + return_trace (FontDict::serialize_link2_op (c, opstr.op, subrs_link)); } else return_trace (copy_opstr (c, opstr)); } - unsigned int calculate_serialized_size (const op_str_t &opstr, - bool has_localsubr=true) const - { - if (drop_hints && dict_opset_t::is_hint_op (opstr.op)) - return 0; - if (opstr.op == OpCode_Subrs) - { - if (desubroutinize || !has_localsubr) - return 0; - else - return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (opstr.op); - } - else - return opstr.str.length; - } - protected: const bool desubroutinize; const bool drop_hints; @@ -282,30 +231,35 @@ struct flatten_param_t bool drop_hints; }; -template +template struct subr_flattener_t { subr_flattener_t (const ACC &acc_, - const hb_vector_t &glyphs_, - bool drop_hints_) : acc (acc_), glyphs (glyphs_), - drop_hints (drop_hints_) {} + const hb_subset_plan_t *plan_) + : acc (acc_), plan (plan_) {} bool flatten (str_buff_vec_t &flat_charstrings) { - if (!flat_charstrings.resize (glyphs.length)) + if (!flat_charstrings.resize (plan->num_output_glyphs ())) return false; - for (unsigned int i = 0; i < glyphs.length; i++) + for (unsigned int i = 0; i < plan->num_output_glyphs (); i++) flat_charstrings[i].init (); - for (unsigned int i = 0; i < glyphs.length; i++) + for (unsigned int i = 0; i < plan->num_output_glyphs (); i++) { - hb_codepoint_t glyph = glyphs[i]; + hb_codepoint_t glyph; + if (!plan->old_gid_for_new_gid (i, &glyph)) + { + /* add an endchar only charstring for a missing glyph if CFF1 */ + if (endchar_op != OpCode_Invalid) flat_charstrings[i].push (endchar_op); + continue; + } const byte_str_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; cs_interpreter_t interp; interp.env.init (str, acc, fd); - flatten_param_t param = { flat_charstrings[i], drop_hints }; + flatten_param_t param = { flat_charstrings[i], plan->drop_hints }; if (unlikely (!interp.interpret (param))) return false; } @@ -313,8 +267,7 @@ struct subr_flattener_t } const ACC &acc; - const hb_vector_t &glyphs; - bool drop_hints; + const hb_subset_plan_t *plan; }; struct subr_closures_t @@ -463,7 +416,8 @@ struct parsed_cs_str_vec_t : hb_vector_t void init (unsigned int len_ = 0) { SUPER::init (); - resize (len_); + if (unlikely (!resize (len_))) + return; for (unsigned int i = 0; i < length; i++) (*this)[i].init (); } @@ -512,19 +466,19 @@ struct subr_subset_param_t template void set_current_str (ENV &env, bool calling) { - parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); - if (likely (parsed_str != nullptr)) + parsed_cs_str_t *parsed_str = get_parsed_str_for_context (env.context); + if (unlikely (!parsed_str)) { - /* If the called subroutine is parsed partially but not completely yet, - * it must be because we are calling it recursively. - * Handle it as an error. */ - if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0))) - env.set_error (); - else - current_parsed_str = parsed_str; + env.set_error (); + return; } - else + /* If the called subroutine is parsed partially but not completely yet, + * it must be because we are calling it recursively. + * Handle it as an error. */ + if (unlikely (calling && !parsed_str->is_parsed () && (parsed_str->values.length > 0))) env.set_error (); + else + current_parsed_str = parsed_str; } parsed_cs_str_t *current_parsed_str; @@ -537,39 +491,29 @@ struct subr_subset_param_t bool drop_hints; }; -struct subr_remap_t : remap_t +struct subr_remap_t : hb_inc_bimap_t { void create (hb_set_t *closure) { /* create a remapping of subroutine numbers from old to new. * no optimization based on usage counts. fonttools doesn't appear doing that either. */ - reset (closure->get_max () + 1); - for (hb_codepoint_t old_num = 0; old_num < length; old_num++) - { - if (hb_set_has (closure, old_num)) - add (old_num); - } - if (get_count () < 1240) + hb_codepoint_t old_num = HB_SET_VALUE_INVALID; + while (hb_set_next (closure, &old_num)) + add (old_num); + + if (get_population () < 1240) bias = 107; - else if (get_count () < 33900) + else if (get_population () < 33900) bias = 1131; else bias = 32768; } - hb_codepoint_t operator[] (unsigned int old_num) const - { - if (old_num >= length) - return CFF_UNDEF_CODE; - else - return remap_t::operator[] (old_num); - } - int biased_num (unsigned int old_num) const { - hb_codepoint_t new_num = (*this)[old_num]; + hb_codepoint_t new_num = get (old_num); return (int)new_num - bias; } @@ -577,23 +521,28 @@ struct subr_remap_t : remap_t int bias; }; -struct subr_remap_ts +struct subr_remaps_t { - subr_remap_ts () + subr_remaps_t () { global_remap.init (); local_remaps.init (); } - ~subr_remap_ts () { fini (); } + ~subr_remaps_t () { fini (); } void init (unsigned int fdCount) { - local_remaps.resize (fdCount); + if (unlikely (!local_remaps.resize (fdCount))) return; for (unsigned int i = 0; i < fdCount; i++) local_remaps[i].init (); } + bool in_error() + { + return local_remaps.in_error (); + } + void create (subr_closures_t& closures) { global_remap.create (closures.global_closure); @@ -611,10 +560,11 @@ struct subr_remap_ts hb_vector_t local_remaps; }; -template +template struct subr_subsetter_t { - subr_subsetter_t () + subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_) + : acc (acc_), plan (plan_) { parsed_charstrings.init (); parsed_global_subrs.init (); @@ -644,25 +594,36 @@ struct subr_subsetter_t * Assumption: a callsubr/callgsubr operator must immediately follow a (biased) subroutine number * within the same charstring/subroutine, e.g., not split across a charstring and a subroutine. */ - bool subset (ACC &acc, const hb_vector_t &glyphs, bool drop_hints) + bool subset (void) { closures.init (acc.fdCount); remaps.init (acc.fdCount); - parsed_charstrings.init (glyphs.length); + parsed_charstrings.init (plan->num_output_glyphs ()); parsed_global_subrs.init (acc.globalSubrs->count); - parsed_local_subrs.resize (acc.fdCount); + + if (unlikely (remaps.in_error() + || parsed_charstrings.in_error () + || parsed_global_subrs.in_error ())) { + return false; + } + + if (unlikely (!parsed_local_subrs.resize (acc.fdCount))) return false; + for (unsigned int i = 0; i < acc.fdCount; i++) { parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count); + if (unlikely (parsed_local_subrs[i].in_error ())) return false; } if (unlikely (!closures.valid)) return false; /* phase 1 & 2 */ - for (unsigned int i = 0; i < glyphs.length; i++) + for (unsigned int i = 0; i < plan->num_output_glyphs (); i++) { - hb_codepoint_t glyph = glyphs[i]; + hb_codepoint_t glyph; + if (!plan->old_gid_for_new_gid (i, &glyph)) + continue; const byte_str_t str = (*acc.charStrings)[glyph]; unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) @@ -675,28 +636,31 @@ struct subr_subsetter_t param.init (&parsed_charstrings[i], &parsed_global_subrs, &parsed_local_subrs[fd], closures.global_closure, closures.local_closures[fd], - drop_hints); + plan->drop_hints); if (unlikely (!interp.interpret (param))) return false; - /* finalize parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ - SUBSETTER::finalize_parsed_str (interp.env, param, parsed_charstrings[i]); + /* complete parsed string esp. copy CFF1 width or CFF2 vsindex to the parsed charstring for encoding */ + SUBSETTER::complete_parsed_str (interp.env, param, parsed_charstrings[i]); } - if (drop_hints) + if (plan->drop_hints) { /* mark hint ops and arguments for drop */ - for (unsigned int i = 0; i < glyphs.length; i++) + for (unsigned int i = 0; i < plan->num_output_glyphs (); i++) { - unsigned int fd = acc.fdSelect->get_fd (glyphs[i]); + hb_codepoint_t glyph; + if (!plan->old_gid_for_new_gid (i, &glyph)) + continue; + unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; subr_subset_param_t param; param.init (&parsed_charstrings[i], &parsed_global_subrs, &parsed_local_subrs[fd], closures.global_closure, closures.local_closures[fd], - drop_hints); + plan->drop_hints); drop_hints_param_t drop; if (drop_hints_in_str (parsed_charstrings[i], param, drop)) @@ -709,16 +673,19 @@ struct subr_subsetter_t /* after dropping hints recreate closures of actually used subrs */ closures.reset (); - for (unsigned int i = 0; i < glyphs.length; i++) + for (unsigned int i = 0; i < plan->num_output_glyphs (); i++) { - unsigned int fd = acc.fdSelect->get_fd (glyphs[i]); + hb_codepoint_t glyph; + if (!plan->old_gid_for_new_gid (i, &glyph)) + continue; + unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; subr_subset_param_t param; param.init (&parsed_charstrings[i], &parsed_global_subrs, &parsed_local_subrs[fd], closures.global_closure, closures.local_closures[fd], - drop_hints); + plan->drop_hints); collect_subr_refs_in_str (parsed_charstrings[i], param); } } @@ -728,13 +695,20 @@ struct subr_subsetter_t return true; } - bool encode_charstrings (ACC &acc, const hb_vector_t &glyphs, str_buff_vec_t &buffArray) const + bool encode_charstrings (str_buff_vec_t &buffArray) const { - if (unlikely (!buffArray.resize (glyphs.length))) + if (unlikely (!buffArray.resize (plan->num_output_glyphs ()))) return false; - for (unsigned int i = 0; i < glyphs.length; i++) + for (unsigned int i = 0; i < plan->num_output_glyphs (); i++) { - unsigned int fd = acc.fdSelect->get_fd (glyphs[i]); + hb_codepoint_t glyph; + if (!plan->old_gid_for_new_gid (i, &glyph)) + { + /* add an endchar only charstring for a missing glyph if CFF1 */ + if (endchar_op != OpCode_Invalid) buffArray[i].push (endchar_op); + continue; + } + unsigned int fd = acc.fdSelect->get_fd (glyph); if (unlikely (fd >= acc.fdCount)) return false; if (unlikely (!encode_str (parsed_charstrings[i], fd, buffArray[i]))) @@ -745,7 +719,7 @@ struct subr_subsetter_t bool encode_subrs (const parsed_cs_str_vec_t &subrs, const subr_remap_t& remap, unsigned int fd, str_buff_vec_t &buffArray) const { - unsigned int count = remap.get_count (); + unsigned int count = remap.get_population (); if (unlikely (!buffArray.resize (count))) return false; @@ -777,10 +751,12 @@ struct subr_subsetter_t drop_hints_param_t () : seen_moveto (false), ends_in_hint (false), + all_dropped (false), vsindex_dropped (false) {} bool seen_moveto; bool ends_in_hint; + bool all_dropped; bool vsindex_dropped; }; @@ -791,7 +767,7 @@ struct subr_subsetter_t drop.ends_in_hint = false; bool has_hint = drop_hints_in_str (subrs[subr_num], param, drop); - /* if this subr ends with a stem hint (i.e., not a number a potential argument for moveto), + /* if this subr ends with a stem hint (i.e., not a number; potential argument for moveto), * then this entire subroutine must be a hint. drop its call. */ if (drop.ends_in_hint) { @@ -801,6 +777,10 @@ struct subr_subsetter_t if (!str.at_end (pos)) drop.ends_in_hint = false; } + else if (drop.all_dropped) + { + str.values[pos].set_drop (); + } return has_hint; } @@ -819,7 +799,6 @@ struct subr_subsetter_t has_hint = drop_hints_in_subr (str, pos, *param.parsed_local_subrs, str.values[pos].subr_num, param, drop); - break; case OpCode_callgsubr: @@ -876,6 +855,23 @@ struct subr_subsetter_t } } + /* Raise all_dropped flag if all operators except return are dropped from a subr. + * It may happen even after seeing the first moveto if a subr contains + * only (usually one) hintmask operator, then calls to this subr can be dropped. + */ + drop.all_dropped = true; + for (unsigned int pos = 0; pos < str.values.length; pos++) + { + parsed_cs_op_t &csop = str.values[pos]; + if (csop.op == OpCode_return) + break; + if (!csop.for_drop ()) + { + drop.all_dropped = false; + break; + } + } + return seen_hint; } @@ -884,7 +880,7 @@ struct subr_subsetter_t hb_set_t *closure, const subr_subset_param_t ¶m) { - hb_set_add (closure, subr_num); + closure->add (subr_num); collect_subr_refs_in_str (subrs[subr_num], param); } @@ -954,13 +950,16 @@ struct subr_subsetter_t } protected: - subr_closures_t closures; + const ACC &acc; + const hb_subset_plan_t *plan; + + subr_closures_t closures; - parsed_cs_str_vec_t parsed_charstrings; - parsed_cs_str_vec_t parsed_global_subrs; + parsed_cs_str_vec_t parsed_charstrings; + parsed_cs_str_vec_t parsed_global_subrs; hb_vector_t parsed_local_subrs; - subr_remap_ts remaps; + subr_remaps_t remaps; private: typedef typename SUBRS::count_type subr_count_type; @@ -969,14 +968,14 @@ struct subr_subsetter_t } /* namespace CFF */ HB_INTERNAL bool -hb_plan_subset_cff_fdselect (const hb_vector_t &glyphs, +hb_plan_subset_cff_fdselect (const hb_subset_plan_t *plan, unsigned int fdCount, const CFF::FDSelect &src, /* IN */ unsigned int &subset_fd_count /* OUT */, unsigned int &subset_fdselect_size /* OUT */, unsigned int &subset_fdselect_format /* OUT */, hb_vector_t &fdselect_ranges /* OUT */, - CFF::remap_t &fdmap /* OUT */); + hb_inc_bimap_t &fdmap /* OUT */); HB_INTERNAL bool hb_serialize_cff_fdselect (hb_serialize_context_t *c, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc index 7f35e5ecfef..650c3aeec9b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.cc @@ -24,9 +24,14 @@ * Adobe Author(s): Michiharu Ariza */ +#include "hb.hh" + +#ifndef HB_NO_SUBSET_CFF + #include "hb-open-type.hh" #include "hb-ot-cff1-table.hh" #include "hb-set.h" +#include "hb-bimap.hh" #include "hb-subset-cff1.hh" #include "hb-subset-plan.hh" #include "hb-subset-cff-common.hh" @@ -34,12 +39,12 @@ using namespace CFF; -struct remap_sid_t : remap_t +struct remap_sid_t : hb_inc_bimap_t { unsigned int add (unsigned int sid) { if ((sid != CFF_UNDEF_SID) && !is_std_std (sid)) - return offset_sid (remap_t::add (unoffset_sid (sid))); + return offset_sid (hb_inc_bimap_t::add (unoffset_sid (sid))); else return sid; } @@ -49,7 +54,7 @@ struct remap_sid_t : remap_t if (is_std_std (sid) || (sid == CFF_UNDEF_SID)) return sid; else - return offset_sid (remap_t::operator [] (unoffset_sid (sid))); + return offset_sid (get (unoffset_sid (sid))); } static const unsigned int num_std_strings = 391; @@ -59,29 +64,25 @@ struct remap_sid_t : remap_t static unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; } }; -struct cff1_sub_table_offsets_t : cff_sub_table_offsets_t +struct cff1_sub_table_info_t : cff_sub_table_info_t { - cff1_sub_table_offsets_t () - : cff_sub_table_offsets_t (), - nameIndexOffset (0), - encodingOffset (0) - { - stringIndexInfo.init (); - charsetInfo.init (); + cff1_sub_table_info_t () + : cff_sub_table_info_t (), + encoding_link (0), + charset_link (0) + { privateDictInfo.init (); } - unsigned int nameIndexOffset; - table_info_t stringIndexInfo; - unsigned int encodingOffset; - table_info_t charsetInfo; + objidx_t encoding_link; + objidx_t charset_link; table_info_t privateDictInfo; }; /* a copy of a parsed out cff1_top_dict_values_t augmented with additional operators */ struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t { - void init (const cff1_top_dict_values_t *base_= &Null(cff1_top_dict_values_t)) + void init (const cff1_top_dict_values_t *base_= &Null (cff1_top_dict_values_t)) { SUPER::init (); base = base_; @@ -112,13 +113,13 @@ struct cff1_top_dict_values_mod_t : cff1_top_dict_values_t struct top_dict_modifiers_t { - top_dict_modifiers_t (const cff1_sub_table_offsets_t &offsets_, - const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount]) - : offsets (offsets_), + top_dict_modifiers_t (const cff1_sub_table_info_t &info_, + const unsigned int (&nameSIDs_)[name_dict_values_t::ValCount]) + : info (info_), nameSIDs (nameSIDs_) {} - const cff1_sub_table_offsets_t &offsets; + const cff1_sub_table_info_t &info; const unsigned int (&nameSIDs)[name_dict_values_t::ValCount]; }; @@ -134,22 +135,20 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_tallocate_size (1); - if (unlikely (p == nullptr)) return_trace (false); - p->set (OpCode_Private); - } - break; + return_trace (UnsizedByteStr::serialize_int2 (c, mod.info.privateDictInfo.size) && + Dict::serialize_link4_op (c, op, mod.info.privateDictInfo.link, whence_t::Absolute)); case OpCode_version: case OpCode_Notice: @@ -160,7 +159,7 @@ struct cff1_top_dict_op_serializer_t : cff_top_dict_op_serializer_t::serialize (c, opstr, mod.offsets)); + return_trace (cff_top_dict_op_serializer_t::serialize (c, opstr, mod.info)); } return_trace (true); } - unsigned int calculate_serialized_size (const cff1_top_dict_val_t &opstr) const - { - op_code_t op = opstr.op; - switch (op) - { - case OpCode_charset: - case OpCode_Encoding: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); - - case OpCode_Private: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); - - case OpCode_version: - case OpCode_Notice: - case OpCode_Copyright: - case OpCode_FullName: - case OpCode_FamilyName: - case OpCode_Weight: - case OpCode_PostScript: - case OpCode_BaseFontName: - case OpCode_FontName: - return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op); - - case OpCode_ROS: - return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.length - opstr.last_arg_offset)/* supplement + op */; - - default: - return cff_top_dict_op_serializer_t::calculate_serialized_size (opstr); - } - } -}; - -struct font_dict_values_mod_t -{ - void init (const cff1_font_dict_values_t *base_, - unsigned int fontName_, - const table_info_t &privateDictInfo_) - { - base = base_; - fontName = fontName_; - privateDictInfo = privateDictInfo_; - } - - unsigned get_count () const { return base->get_count (); } - - const op_str_t &operator [] (unsigned int i) const { return (*base)[i]; } - - const cff1_font_dict_values_t *base; - table_info_t privateDictInfo; - unsigned int fontName; }; struct cff1_font_dict_op_serializer_t : cff_font_dict_op_serializer_t { bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, - const font_dict_values_mod_t &mod) const + const cff1_font_dict_values_mod_t &mod) const { TRACE_SERIALIZE (this); if (opstr.op == OpCode_FontName) - return_trace (FontDict::serialize_uint2_op (c, opstr.op, mod.fontName)); + return_trace (FontDict::serialize_int2_op (c, opstr.op, mod.fontName)); else return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo)); } - unsigned int calculate_serialized_size (const op_str_t &opstr) const - { - if (opstr.op == OpCode_FontName) - return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName); - else - return SUPER::calculate_serialized_size (opstr); - } - private: typedef cff_font_dict_op_serializer_t SUPER; }; @@ -326,7 +268,7 @@ struct cff1_cs_opset_flatten_t : cff1_cs_opset_t { /* replace the first glyph ID in the "glyph" field each range with a nLeft value */ - bool finalize (unsigned int last_glyph) + bool complete (unsigned int last_glyph) { bool two_byte = false; for (unsigned int i = (*this).length; i > 0; i--) @@ -351,7 +293,7 @@ struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_tadd_op (op, env.str_ref); param.current_parsed_str->set_parsed (); - env.returnFromSubr (); + env.return_from_subr (); param.set_current_str (env, false); break; @@ -382,9 +324,9 @@ struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_tadd_call_op (op, str_ref, env.context.subr_num); - hb_set_add (closure, env.context.subr_num); + closure->add (env.context.subr_num); param.set_current_str (env, true); } @@ -392,9 +334,12 @@ struct cff1_cs_opset_subr_subset_t : cff1_cs_opset_t SUPER; }; -struct cff1_subr_subsetter_t : subr_subsetter_t +struct cff1_subr_subsetter_t : subr_subsetter_t { - static void finalize_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) + cff1_subr_subsetter_t (const OT::cff1::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_) + : subr_subsetter_t (acc_, plan_) {} + + static void complete_parsed_str (cff1_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) { /* insert width at the beginning of the charstring as necessary */ if (env.has_width) @@ -406,8 +351,8 @@ struct cff1_subr_subsetter_t : subr_subsetter_tset_parsed (); for (unsigned int i = 0; i < env.callStack.get_count (); i++) { - parsed_cs_str_t *parsed_str = param.get_parsed_str_for_context (env.callStack[i]); - if (likely (parsed_str != nullptr)) + parsed_cs_str_t *parsed_str = param.get_parsed_str_for_context (env.callStack[i]); + if (likely (parsed_str)) parsed_str->set_parsed (); else env.set_error (); @@ -417,16 +362,13 @@ struct cff1_subr_subsetter_t : subr_subsetter_t supp_codes; - subset_enc_code_ranges.resize (0); + if (unlikely (!subset_enc_code_ranges.resize (0))) + { + plan->check_success (false); + return; + } + supp_size = 0; supp_codes.init (); - subset_enc_num_codes = plan->glyphs.length - 1; + subset_enc_num_codes = plan->num_output_glyphs () - 1; unsigned int glyph; - for (glyph = 1; glyph < plan->glyphs.length; glyph++) + for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++) { - hb_codepoint_t orig_glyph = plan->glyphs[glyph]; - code = acc.glyph_to_code (orig_glyph); + hb_codepoint_t old_glyph; + if (!plan->old_gid_for_new_gid (glyph, &old_glyph)) + { + /* Retain the code for the old missing glyph ID */ + old_glyph = glyph; + } + code = acc.glyph_to_code (old_glyph); if (code == CFF_UNDEF_CODE) { subset_enc_num_codes = glyph - 1; break; } - if (code != last_code + 1) + if ((last_code == CFF_UNDEF_CODE) || (code != last_code + 1)) { code_pair_t pair = { code, glyph }; subset_enc_code_ranges.push (pair); } last_code = code; - if (encoding != &Null(Encoding)) + if (encoding != &Null (Encoding)) { - hb_codepoint_t sid = acc.glyph_to_sid (orig_glyph); + hb_codepoint_t sid = acc.glyph_to_sid (old_glyph); encoding->get_supplement_codes (sid, supp_codes); for (unsigned int i = 0; i < supp_codes.length; i++) { @@ -502,7 +453,7 @@ struct cff_subset_plan { } supp_codes.fini (); - subset_enc_code_ranges.finalize (glyph); + subset_enc_code_ranges.complete (glyph); assert (subset_enc_num_codes <= 0xFF); size0 = Encoding0::min_size + HBUINT8::static_size * subset_enc_num_codes; @@ -512,29 +463,34 @@ struct cff_subset_plan { subset_enc_format = 0; else subset_enc_format = 1; - - return Encoding::calculate_serialized_size ( - subset_enc_format, - subset_enc_format? subset_enc_code_ranges.length: subset_enc_num_codes, - subset_enc_supp_codes.length); } - unsigned int plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) + void plan_subset_charset (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) { unsigned int size0, size_ranges; hb_codepoint_t sid, last_sid = CFF_UNDEF_CODE; - subset_charset_ranges.resize (0); + if (unlikely (!subset_charset_ranges.resize (0))) + { + plan->check_success (false); + return; + } + unsigned int glyph; - for (glyph = 1; glyph < plan->glyphs.length; glyph++) + for (glyph = 1; glyph < plan->num_output_glyphs (); glyph++) { - hb_codepoint_t orig_glyph = plan->glyphs[glyph]; - sid = acc.glyph_to_sid (orig_glyph); + hb_codepoint_t old_glyph; + if (!plan->old_gid_for_new_gid (glyph, &old_glyph)) + { + /* Retain the SID for the old missing glyph ID */ + old_glyph = glyph; + } + sid = acc.glyph_to_sid (old_glyph); if (!acc.is_CID ()) sid = sidmap.add (sid); - if (sid != last_sid + 1) + if ((last_sid == CFF_UNDEF_CODE) || (sid != last_sid + 1)) { code_pair_t pair = { sid, glyph }; subset_charset_ranges.push (pair); @@ -542,9 +498,9 @@ struct cff_subset_plan { last_sid = sid; } - bool two_byte = subset_charset_ranges.finalize (glyph); + bool two_byte = subset_charset_ranges.complete (glyph); - size0 = Charset0::min_size + HBUINT16::static_size * (plan->glyphs.length - 1); + size0 = Charset0::min_size + HBUINT16::static_size * (plan->num_output_glyphs () - 1); if (!two_byte) size_ranges = Charset1::min_size + Charset1_Range::static_size * subset_charset_ranges.length; else @@ -556,16 +512,11 @@ struct cff_subset_plan { subset_charset_format = 1; else subset_charset_format = 2; - - return Charset::calculate_serialized_size ( - subset_charset_format, - subset_charset_format? subset_charset_ranges.length: plan->glyphs.length); } bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc) { - if (unlikely (!sidmap.reset (acc.stringIndex->count))) - return false; + sidmap.reset (); for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) { @@ -577,31 +528,33 @@ struct cff_subset_plan { } } - if (acc.fdArray != &Null(CFF1FDArray)) + if (acc.fdArray != &Null (CFF1FDArray)) for (unsigned int i = 0; i < orig_fdcount; i++) - if (fdmap.includes (i)) + if (fdmap.has (i)) (void)sidmap.add (acc.fontDicts[i].fontName); return true; } bool create (const OT::cff1::accelerator_subset_t &acc, - hb_subset_plan_t *plan) + hb_subset_plan_t *plan) { - /* make sure notdef is first */ - if ((plan->glyphs.length == 0) || (plan->glyphs[0] != 0)) return false; + /* make sure notdef is first */ + hb_codepoint_t old_glyph; + if (!plan->old_gid_for_new_gid (0, &old_glyph) || (old_glyph != 0)) return false; - final_size = 0; - num_glyphs = plan->glyphs.length; + num_glyphs = plan->num_output_glyphs (); orig_fdcount = acc.fdCount; drop_hints = plan->drop_hints; desubroutinize = plan->desubroutinize; /* check whether the subset renumbers any glyph IDs */ gid_renum = false; - for (unsigned int glyph = 0; glyph < plan->glyphs.length; glyph++) + for (hb_codepoint_t new_glyph = 0; new_glyph < plan->num_output_glyphs (); new_glyph++) { - if (plan->glyphs[glyph] != glyph) { + if (!plan->old_gid_for_new_gid(new_glyph, &old_glyph)) + continue; + if (new_glyph != old_glyph) { gid_renum = true; break; } @@ -610,13 +563,6 @@ struct cff_subset_plan { subset_charset = gid_renum || !acc.is_predef_charset (); subset_encoding = !acc.is_CID() && !acc.is_predef_encoding (); - /* CFF header */ - final_size += OT::cff1::static_size; - - /* Name INDEX */ - offsets.nameIndexOffset = final_size; - final_size += acc.nameIndex->get_size (); - /* top dict INDEX */ { /* Add encoding/charset to a (copy of) top dict as necessary */ @@ -630,25 +576,16 @@ struct cff_subset_plan { if (need_to_add_set) topdict_mod.add_op (OpCode_charset); } - offsets.topDictInfo.offset = final_size; - cff1_top_dict_op_serializer_t topSzr; - unsigned int topDictSize = TopDict::calculate_serialized_size (topdict_mod, topSzr); - offsets.topDictInfo.offSize = calcOffSize(topDictSize); - if (unlikely (offsets.topDictInfo.offSize > 4)) - return false; - final_size += CFF1IndexOf::calculate_serialized_size - (offsets.topDictInfo.offSize, - &topdict_mod, 1, topdict_sizes, topSzr); } /* Determine re-mapping of font index as fdmap among other info */ - if (acc.fdSelect != &Null(CFF1FDSelect)) + if (acc.fdSelect != &Null (CFF1FDSelect)) { - if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, + if (unlikely (!hb_plan_subset_cff_fdselect (plan, orig_fdcount, *acc.fdSelect, subset_fdcount, - offsets.FDSelectInfo.size, + info.fd_select.size, subset_fdselect_format, subset_fdselect_ranges, fdmap))) @@ -662,170 +599,79 @@ struct cff_subset_plan { /* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */ if (unlikely (!collect_sids_in_dicts (acc))) return false; - if (unlikely (sidmap.get_count () > 0x8000)) /* assumption: a dict won't reference that many strings */ + if (unlikely (sidmap.get_population () > 0x8000)) /* assumption: a dict won't reference that many strings */ return false; - if (subset_charset) - offsets.charsetInfo.size = plan_subset_charset (acc, plan); - topdict_mod.reassignSIDs (sidmap); - } + if (subset_charset) plan_subset_charset (acc, plan); - /* String INDEX */ - { - offsets.stringIndexInfo.offset = final_size; - offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap); - final_size += offsets.stringIndexInfo.size; + topdict_mod.reassignSIDs (sidmap); } if (desubroutinize) { /* Flatten global & local subrs */ - subr_flattener_t - flattener(acc, plan->glyphs, plan->drop_hints); + subr_flattener_t + flattener(acc, plan); if (!flattener.flatten (subset_charstrings)) return false; - - /* no global/local subroutines */ - offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (1, 0, 0); } else { + cff1_subr_subsetter_t subr_subsetter (acc, plan); + /* Subset subrs: collect used subroutines, leaving all unused ones behind */ - if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints)) + if (!subr_subsetter.subset ()) return false; /* encode charstrings, global subrs, local subrs with new subroutine numbers */ - if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings)) + if (!subr_subsetter.encode_charstrings (subset_charstrings)) return false; if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) return false; - /* global subrs */ - unsigned int dataSize = subset_globalsubrs.total_size (); - offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); - if (unlikely (offsets.globalSubrsInfo.offSize > 4)) - return false; - offsets.globalSubrsInfo.size = CFF1Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); - /* local subrs */ - if (!offsets.localSubrsInfos.resize (orig_fdcount)) - return false; if (!subset_localsubrs.resize (orig_fdcount)) return false; for (unsigned int fd = 0; fd < orig_fdcount; fd++) { subset_localsubrs[fd].init (); - offsets.localSubrsInfos[fd].init (); - if (fdmap.includes (fd)) + if (fdmap.has (fd)) { if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) return false; - - unsigned int dataSize = subset_localsubrs[fd].total_size (); - if (dataSize > 0) - { - offsets.localSubrsInfos[fd].offset = final_size; - offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); - if (unlikely (offsets.localSubrsInfos[fd].offSize > 4)) - return false; - offsets.localSubrsInfos[fd].size = CFF1Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); - } } } } - /* global subrs */ - offsets.globalSubrsInfo.offset = final_size; - final_size += offsets.globalSubrsInfo.size; - /* Encoding */ - if (!subset_encoding) - offsets.encodingOffset = acc.topDict.EncodingOffset; - else - { - offsets.encodingOffset = final_size; - final_size += plan_subset_encoding (acc, plan); - } - - /* Charset */ - if (!subset_charset && acc.is_predef_charset ()) - offsets.charsetInfo.offset = acc.topDict.CharsetOffset; - else - offsets.charsetInfo.offset = final_size; - final_size += offsets.charsetInfo.size; - - /* FDSelect */ - if (acc.fdSelect != &Null(CFF1FDSelect)) - { - offsets.FDSelectInfo.offset = final_size; - final_size += offsets.FDSelectInfo.size; - } - - /* FDArray (FDIndex) */ - if (acc.fdArray != &Null(CFF1FDArray)) { - offsets.FDArrayInfo.offset = final_size; - cff1_font_dict_op_serializer_t fontSzr; - unsigned int dictsSize = 0; - for (unsigned int i = 0; i < acc.fontDicts.length; i++) - if (fdmap.includes (i)) - dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); - - offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); - if (unlikely (offsets.FDArrayInfo.offSize > 4)) - return false; - final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); - } - - /* CharStrings */ - { - offsets.charStringsInfo.offset = final_size; - unsigned int dataSize = subset_charstrings.total_size (); - offsets.charStringsInfo.offSize = calcOffSize (dataSize); - if (unlikely (offsets.charStringsInfo.offSize > 4)) - return false; - final_size += CFF1CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize); - } + if (subset_encoding) + plan_subset_encoding (acc, plan); /* private dicts & local subrs */ - offsets.privateDictInfo.offset = final_size; - for (unsigned int i = 0; i < orig_fdcount; i++) + if (!acc.is_CID ()) + fontdicts_mod.push (cff1_font_dict_values_mod_t ()); + else { - if (fdmap.includes (i)) - { - bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; - cff_private_dict_op_serializer_t privSzr (desubroutinize, plan->drop_hints); - unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); - table_info_t privInfo = { final_size, priv_size, 0 }; - font_dict_values_mod_t fontdict_mod; - if (!acc.is_CID ()) - fontdict_mod.init ( &Null(cff1_font_dict_values_t), CFF_UNDEF_SID, privInfo ); - else - fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo ); - fontdicts_mod.push (fontdict_mod); - final_size += privInfo.size; - - if (!plan->desubroutinize && has_localsubrs) + + hb_iter (acc.fontDicts) + | hb_filter ([&] (const cff1_font_dict_values_t &_) + { return fdmap.has (&_ - &acc.fontDicts[0]); } ) + | hb_map ([&] (const cff1_font_dict_values_t &_) { - offsets.localSubrsInfos[i].offset = final_size; - final_size += offsets.localSubrsInfos[i].size; - } - } + cff1_font_dict_values_mod_t mod; + mod.init (&_, sidmap[_.fontName]); + return mod; + }) + | hb_sink (fontdicts_mod) + ; } - if (!acc.is_CID ()) - offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo; - - return ((subset_charstrings.length == plan->glyphs.length) + return ((subset_charstrings.length == plan->num_output_glyphs ()) && (fontdicts_mod.length == subset_fdcount)); } - unsigned int get_final_size () const { return final_size; } - - unsigned int final_size; - hb_vector_t topdict_sizes; cff1_top_dict_values_mod_t topdict_mod; - cff1_sub_table_offsets_t offsets; + cff1_sub_table_info_t info; unsigned int num_glyphs; unsigned int orig_fdcount; @@ -835,12 +681,12 @@ struct cff_subset_plan { /* font dict index remap table from fullset FDArray to subset FDArray. * set to CFF_UNDEF_CODE if excluded from subset */ - remap_t fdmap; + hb_inc_bimap_t fdmap; str_buff_vec_t subset_charstrings; str_buff_vec_t subset_globalsubrs; hb_vector_t subset_localsubrs; - hb_vector_t fontdicts_mod; + hb_vector_t fontdicts_mod; bool drop_hints; @@ -859,94 +705,97 @@ struct cff_subset_plan { unsigned int topDictModSIDs[name_dict_values_t::ValCount]; bool desubroutinize; - cff1_subr_subsetter_t subr_subsetter; }; -static inline bool _write_cff1 (const cff_subset_plan &plan, - const OT::cff1::accelerator_subset_t &acc, - const hb_vector_t& glyphs, - unsigned int dest_sz, - void *dest) +static bool _serialize_cff1 (hb_serialize_context_t *c, + cff_subset_plan &plan, + const OT::cff1::accelerator_subset_t &acc, + unsigned int num_glyphs) { - hb_serialize_context_t c (dest, dest_sz); - - OT::cff1 *cff = c.start_serialize (); - if (unlikely (!c.extend_min (*cff))) - return false; - - /* header */ - cff->version.major.set (0x01); - cff->version.minor.set (0x00); - cff->nameIndex.set (cff->min_size); - cff->offSize.set (4); /* unused? */ - - /* name INDEX */ + /* private dicts & local subrs */ + for (int i = (int)acc.privateDicts.length; --i >= 0 ;) { - assert (cff->nameIndex == (unsigned) (c.head - c.start)); - CFF1NameIndex *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, *acc.nameIndex))) + if (plan.fdmap.has (i)) { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX"); - return false; - } - } + objidx_t subrs_link = 0; + if (plan.subset_localsubrs[i].length > 0) + { + CFF1Subrs *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest && dest->serialize (c, plan.subset_localsubrs[i]))) + subrs_link = c->pop_pack (); + else + { + c->pop_discard (); + return false; + } + } - /* top dict INDEX */ - { - assert (plan.offsets.topDictInfo.offset == (unsigned) (c.head - c.start)); - CFF1IndexOf *dest = c.start_embed< CFF1IndexOf > (); - if (dest == nullptr) return false; - cff1_top_dict_op_serializer_t topSzr; - top_dict_modifiers_t modifier (plan.offsets, plan.topDictModSIDs); - if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize, - &plan.topdict_mod, 1, - plan.topdict_sizes, topSzr, modifier))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict"); - return false; + PrivateDict *pd = c->start_embed (); + if (unlikely (!pd)) return false; + c->push (); + cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); + /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ + if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link))) + { + unsigned fd = plan.fdmap[i]; + plan.fontdicts_mod[fd].privateDictInfo.size = c->length (); + plan.fontdicts_mod[fd].privateDictInfo.link = c->pop_pack (); + } + else + { + c->pop_discard (); + return false; + } } } - /* String INDEX */ + if (!acc.is_CID ()) + plan.info.privateDictInfo = plan.fontdicts_mod[0].privateDictInfo; + + /* CharStrings */ { - assert (plan.offsets.stringIndexInfo.offset == (unsigned) (c.head - c.start)); - CFF1StringIndex *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap))) + CFF1CharStrings *cs = c->start_embed (); + if (unlikely (!cs)) return false; + c->push (); + if (likely (cs->serialize (c, plan.subset_charstrings))) + plan.info.char_strings_link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX"); + c->pop_discard (); return false; } } - /* global subrs */ + /* FDArray (FD Index) */ + if (acc.fdArray != &Null (CFF1FDArray)) { - assert (plan.offsets.globalSubrsInfo.offset != 0); - assert (plan.offsets.globalSubrsInfo.offset == (unsigned) (c.head - c.start)); - - CFF1Subrs *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) + CFF1FDArray *fda = c->start_embed (); + if (unlikely (!fda)) return false; + c->push (); + cff1_font_dict_op_serializer_t fontSzr; + auto it = + hb_zip (+ hb_iter (plan.fontdicts_mod), + hb_iter (plan.fontdicts_mod)); + if (likely (fda->serialize (c, it, fontSzr))) + plan.info.fd_array_link = c->pop_pack (false); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); + c->pop_discard (); return false; } } - /* Encoding */ - if (plan.subset_encoding) + /* FDSelect */ + if (acc.fdSelect != &Null (CFF1FDSelect)) { - assert (plan.offsets.encodingOffset == (unsigned) (c.head - c.start)); - Encoding *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, - plan.subset_enc_format, - plan.subset_enc_num_codes, - plan.subset_enc_code_ranges, - plan.subset_enc_supp_codes))) + c->push (); + if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *acc.fdSelect, acc.fdCount, + plan.subset_fdselect_format, plan.info.fd_select.size, + plan.subset_fdselect_ranges))) + plan.info.fd_select.link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding"); + c->pop_discard (); return false; } } @@ -954,129 +803,120 @@ static inline bool _write_cff1 (const cff_subset_plan &plan, /* Charset */ if (plan.subset_charset) { - assert (plan.offsets.charsetInfo.offset == (unsigned) (c.head - c.start)); - Charset *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, - plan.subset_charset_format, - plan.num_glyphs, - plan.subset_charset_ranges))) + Charset *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest->serialize (c, + plan.subset_charset_format, + plan.num_glyphs, + plan.subset_charset_ranges))) + plan.info.charset_link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset"); + c->pop_discard (); return false; } } - /* FDSelect */ - if (acc.fdSelect != &Null(CFF1FDSelect)) + /* Encoding */ + if (plan.subset_encoding) { - assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start)); - - if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *acc.fdSelect, acc.fdCount, - plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, - plan.subset_fdselect_ranges))) + Encoding *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest->serialize (c, + plan.subset_enc_format, + plan.subset_enc_num_codes, + plan.subset_enc_code_ranges, + plan.subset_enc_supp_codes))) + plan.info.encoding_link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect"); + c->pop_discard (); return false; } } - /* FDArray (FD Index) */ - if (acc.fdArray != &Null(CFF1FDArray)) + /* global subrs */ { - assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start)); - CFF1FDArray *fda = c.start_embed (); - if (unlikely (fda == nullptr)) return false; - cff1_font_dict_op_serializer_t fontSzr; - if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, - plan.fontdicts_mod, - fontSzr))) + c->push (); + CFF1Subrs *dest = c->start_embed (); + if (unlikely (!dest)) return false; + if (likely (dest->serialize (c, plan.subset_globalsubrs))) + c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray"); + c->pop_discard (); return false; } } - /* CharStrings */ + /* String INDEX */ { - assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start)); - CFF1CharStrings *cs = c.start_embed (); - if (unlikely (cs == nullptr)) return false; - if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) + CFF1StringIndex *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest->serialize (c, *acc.stringIndex, plan.sidmap))) + c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings"); + c->pop_discard (); return false; } } - /* private dicts & local subrs */ - assert (plan.offsets.privateDictInfo.offset == (unsigned) (c.head - c.start)); - for (unsigned int i = 0; i < acc.privateDicts.length; i++) + OT::cff1 *cff = c->allocate_min (); + if (unlikely (!cff)) + return false; + + /* header */ + cff->version.major = 0x01; + cff->version.minor = 0x00; + cff->nameIndex = cff->min_size; + cff->offSize = 4; /* unused? */ + + /* name INDEX */ + if (unlikely (!(*acc.nameIndex).copy (c))) return false; + + /* top dict INDEX */ { - if (plan.fdmap.includes (i)) + /* serialize singleton TopDict */ + TopDict *top = c->start_embed (); + if (!top) return false; + c->push (); + cff1_top_dict_op_serializer_t topSzr; + unsigned top_size = 0; + top_dict_modifiers_t modifier (plan.info, plan.topDictModSIDs); + if (likely (top->serialize (c, plan.topdict_mod, topSzr, modifier))) { - PrivateDict *pd = c.start_embed (); - if (unlikely (pd == nullptr)) return false; - unsigned int priv_size = plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size; - bool result; - cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); - /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ - unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0; - result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset); - if (unlikely (!result)) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); - return false; - } - if (plan.offsets.localSubrsInfos[i].size > 0) - { - CFF1Subrs *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); - return false; - } - } + top_size = c->length (); + c->pop_pack (false); } + else + { + c->pop_discard (); + return false; + } + /* serialize INDEX header for above */ + CFF1Index *dest = c->start_embed (); + if (!dest) return false; + return dest->serialize_header (c, hb_iter (hb_array_t (&top_size, 1))); } - - assert (c.head == c.end); - c.end_serialize (); - - return true; } static bool _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, - const char *data, - hb_subset_plan_t *plan, - hb_blob_t **prime /* OUT */) + hb_subset_context_t *c) { cff_subset_plan cff_plan; - if (unlikely (!cff_plan.create (acc, plan))) + if (unlikely (!cff_plan.create (acc, c->plan))) { DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan."); return false; } - unsigned int cff_prime_size = cff_plan.get_final_size (); - char *cff_prime_data = (char *) calloc (1, cff_prime_size); - - if (unlikely (!_write_cff1 (cff_plan, acc, plan->glyphs, - cff_prime_size, cff_prime_data))) { - DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff."); - free (cff_prime_data); - return false; - } - - *prime = hb_blob_create (cff_prime_data, - cff_prime_size, - HB_MEMORY_MODE_READONLY, - cff_prime_data, - free); - return true; + return _serialize_cff1 (c->serializer, cff_plan, acc, c->plan->num_output_glyphs ()); } /** @@ -1086,18 +926,15 @@ _hb_subset_cff1 (const OT::cff1::accelerator_subset_t &acc, * Return value: subsetted cff table. **/ bool -hb_subset_cff1 (hb_subset_plan_t *plan, - hb_blob_t **prime /* OUT */) +hb_subset_cff1 (hb_subset_context_t *c) { - hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table (plan->source); - const char *data = hb_blob_get_data(cff_blob, nullptr); - OT::cff1::accelerator_subset_t acc; - acc.init(plan->source); - bool result = likely (acc.is_valid ()) && - _hb_subset_cff1 (acc, data, plan, prime); - hb_blob_destroy (cff_blob); + acc.init (c->plan->source); + bool result = likely (acc.is_valid ()) && _hb_subset_cff1 (acc, c); acc.fini (); return result; } + + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.hh index 33a66380a39..aaf5def1ed5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff1.hh @@ -32,7 +32,6 @@ #include "hb-subset-plan.hh" HB_INTERNAL bool -hb_subset_cff1 (hb_subset_plan_t *plan, - hb_blob_t **cff_prime /* OUT */); +hb_subset_cff1 (hb_subset_context_t *c); #endif /* HB_SUBSET_CFF1_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc index ec69ed64894..6f1b4a7f6d9 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.cc @@ -24,6 +24,10 @@ * Adobe Author(s): Michiharu Ariza */ +#include "hb.hh" + +#ifndef HB_NO_SUBSET_CFF + #include "hb-open-type.hh" #include "hb-ot-cff2-table.hh" #include "hb-set.h" @@ -34,43 +38,31 @@ using namespace CFF; -struct cff2_sub_table_offsets_t : cff_sub_table_offsets_t +struct cff2_sub_table_info_t : cff_sub_table_info_t { - cff2_sub_table_offsets_t () - : cff_sub_table_offsets_t (), - varStoreOffset (0) + cff2_sub_table_info_t () + : cff_sub_table_info_t (), + var_store_link (0) {} - unsigned int varStoreOffset; + objidx_t var_store_link; }; struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<> { bool serialize (hb_serialize_context_t *c, const op_str_t &opstr, - const cff2_sub_table_offsets_t &offsets) const + const cff2_sub_table_info_t &info) const { TRACE_SERIALIZE (this); switch (opstr.op) { case OpCode_vstore: - return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset)); + return_trace (FontDict::serialize_link4_op(c, opstr.op, info.var_store_link)); default: - return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, offsets)); - } - } - - unsigned int calculate_serialized_size (const op_str_t &opstr) const - { - switch (opstr.op) - { - case OpCode_vstore: - return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); - - default: - return cff_top_dict_op_serializer_t<>::calculate_serialized_size (opstr); + return_trace (cff_top_dict_op_serializer_t<>::serialize (c, opstr, info)); } } }; @@ -183,7 +175,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_tset_parsed (); - env.returnFromSubr (); + env.return_from_subr (); param.set_current_str (env, false); break; @@ -213,9 +205,9 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_tadd_call_op (op, str_ref, env.context.subr_num); - hb_set_add (closure, env.context.subr_num); + closure->add (env.context.subr_num); param.set_current_str (env, true); } @@ -225,7 +217,10 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t { - static void finalize_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) + cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_) + : subr_subsetter_t (acc_, plan_) {} + + static void complete_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring) { /* vsindex is inserted at the beginning of the charstring as necessary */ if (env.seen_vsindex ()) @@ -239,9 +234,9 @@ struct cff2_subr_subsetter_t : subr_subsetter_tcount; drop_hints = plan->drop_hints; desubroutinize = plan->desubroutinize; - /* CFF2 header */ - final_size += OT::cff2::static_size; - - /* top dict */ - { - cff2_top_dict_op_serializer_t topSzr; - offsets.topDictInfo.size = TopDict::calculate_serialized_size (acc.topDict, topSzr); - final_size += offsets.topDictInfo.size; - } - if (desubroutinize) { /* Flatten global & local subrs */ subr_flattener_t - flattener(acc, plan->glyphs, plan->drop_hints); + flattener(acc, plan); if (!flattener.flatten (subset_charstrings)) return false; - - /* no global/local subroutines */ - offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (1, 0, 0); } else { + cff2_subr_subsetter_t subr_subsetter (acc, plan); + /* Subset subrs: collect used subroutines, leaving all unused ones behind */ - if (!subr_subsetter.subset (acc, plan->glyphs, plan->drop_hints)) + if (!subr_subsetter.subset ()) return false; /* encode charstrings, global subrs, local subrs with new subroutine numbers */ - if (!subr_subsetter.encode_charstrings (acc, plan->glyphs, subset_charstrings)) + if (!subr_subsetter.encode_charstrings (subset_charstrings)) return false; if (!subr_subsetter.encode_globalsubrs (subset_globalsubrs)) return false; - /* global subrs */ - unsigned int dataSize = subset_globalsubrs.total_size (); - offsets.globalSubrsInfo.offSize = calcOffSize (dataSize); - offsets.globalSubrsInfo.size = CFF2Subrs::calculate_serialized_size (offsets.globalSubrsInfo.offSize, subset_globalsubrs.length, dataSize); - /* local subrs */ - if (!offsets.localSubrsInfos.resize (orig_fdcount)) - return false; if (!subset_localsubrs.resize (orig_fdcount)) return false; for (unsigned int fd = 0; fd < orig_fdcount; fd++) { subset_localsubrs[fd].init (); - offsets.localSubrsInfos[fd].init (); - if (fdmap.includes (fd)) - { - if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) - return false; - - unsigned int dataSize = subset_localsubrs[fd].total_size (); - if (dataSize > 0) - { - offsets.localSubrsInfos[fd].offset = final_size; - offsets.localSubrsInfos[fd].offSize = calcOffSize (dataSize); - offsets.localSubrsInfos[fd].size = CFF2Subrs::calculate_serialized_size (offsets.localSubrsInfos[fd].offSize, subset_localsubrs[fd].length, dataSize); - } - } + if (!subr_subsetter.encode_localsubrs (fd, subset_localsubrs[fd])) + return false; } } - /* global subrs */ - offsets.globalSubrsInfo.offset = final_size; - final_size += offsets.globalSubrsInfo.size; - - /* variation store */ - if (acc.varStore != &Null(CFF2VariationStore)) - { - offsets.varStoreOffset = final_size; - final_size += acc.varStore->get_size (); - } - /* FDSelect */ - if (acc.fdSelect != &Null(CFF2FDSelect)) + if (acc.fdSelect != &Null (CFF2FDSelect)) { - offsets.FDSelectInfo.offset = final_size; - if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs, - orig_fdcount, - *(const FDSelect *)acc.fdSelect, - subset_fdcount, - offsets.FDSelectInfo.size, - subset_fdselect_format, - subset_fdselect_ranges, - fdmap))) + if (unlikely (!hb_plan_subset_cff_fdselect (plan, + orig_fdcount, + *(const FDSelect *)acc.fdSelect, + subset_fdcount, + subset_fdselect_size, + subset_fdselect_format, + subset_fdselect_ranges, + fdmap))) return false; - - final_size += offsets.FDSelectInfo.size; } else fdmap.identity (1); - /* FDArray (FDIndex) */ - { - offsets.FDArrayInfo.offset = final_size; - cff_font_dict_op_serializer_t fontSzr; - unsigned int dictsSize = 0; - for (unsigned int i = 0; i < acc.fontDicts.length; i++) - if (fdmap.includes (i)) - dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr); - - offsets.FDArrayInfo.offSize = calcOffSize (dictsSize); - final_size += CFF2Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize); - } - - /* CharStrings */ - { - offsets.charStringsInfo.offset = final_size; - unsigned int dataSize = subset_charstrings.total_size (); - offsets.charStringsInfo.offSize = calcOffSize (dataSize); - final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsInfo.offSize, plan->glyphs.length, dataSize); - } - - /* private dicts & local subrs */ - offsets.privateDictsOffset = final_size; - for (unsigned int i = 0; i < orig_fdcount; i++) - { - if (fdmap.includes (i)) - { - bool has_localsubrs = offsets.localSubrsInfos[i].size > 0; - cff_private_dict_op_serializer_t privSzr (desubroutinize, drop_hints); - unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr, has_localsubrs); - table_info_t privInfo = { final_size, priv_size, 0 }; - privateDictInfos.push (privInfo); - final_size += privInfo.size; - - if (!plan->desubroutinize && has_localsubrs) - { - offsets.localSubrsInfos[i].offset = final_size; - final_size += offsets.localSubrsInfos[i].size; - } - } - } - return true; } - unsigned int get_final_size () const { return final_size; } - - unsigned int final_size; - cff2_sub_table_offsets_t offsets; + cff2_sub_table_info_t info; unsigned int orig_fdcount; unsigned int subset_fdcount; + unsigned int subset_fdselect_size; unsigned int subset_fdselect_format; hb_vector_t subset_fdselect_ranges; - remap_t fdmap; + hb_inc_bimap_t fdmap; str_buff_vec_t subset_charstrings; str_buff_vec_t subset_globalsubrs; hb_vector_t subset_localsubrs; - hb_vector_t privateDictInfos; bool drop_hints; bool desubroutinize; - cff2_subr_subsetter_t subr_subsetter; }; -static inline bool _write_cff2 (const cff2_subset_plan &plan, - const OT::cff2::accelerator_subset_t &acc, - const hb_vector_t& glyphs, - unsigned int dest_sz, - void *dest) +static bool _serialize_cff2 (hb_serialize_context_t *c, + cff2_subset_plan &plan, + const OT::cff2::accelerator_subset_t &acc, + unsigned int num_glyphs) { - hb_serialize_context_t c (dest, dest_sz); - - OT::cff2 *cff2 = c.start_serialize (); - if (unlikely (!c.extend_min (*cff2))) - return false; - - /* header */ - cff2->version.major.set (0x02); - cff2->version.minor.set (0x00); - cff2->topDict.set (OT::cff2::static_size); + /* private dicts & local subrs */ + hb_vector_t private_dict_infos; + if (unlikely (!private_dict_infos.resize (plan.subset_fdcount))) return false; - /* top dict */ + for (int i = (int)acc.privateDicts.length; --i >= 0 ;) { - assert (cff2->topDict == (unsigned) (c.head - c.start)); - cff2->topDictSize.set (plan.offsets.topDictInfo.size); - TopDict &dict = cff2 + cff2->topDict; - cff2_top_dict_op_serializer_t topSzr; - if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets))) + if (plan.fdmap.has (i)) { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict"); - return false; - } - } + objidx_t subrs_link = 0; - /* global subrs */ - { - assert (cff2->topDict + plan.offsets.topDictInfo.size == (unsigned) (c.head - c.start)); - CFF2Subrs *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, plan.offsets.globalSubrsInfo.offSize, plan.subset_globalsubrs))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize global subroutines"); - return false; + if (plan.subset_localsubrs[i].length > 0) + { + CFF2Subrs *dest = c->start_embed (); + if (unlikely (!dest)) return false; + c->push (); + if (likely (dest->serialize (c, plan.subset_localsubrs[i]))) + subrs_link = c->pop_pack (); + else + { + c->pop_discard (); + return false; + } + } + PrivateDict *pd = c->start_embed (); + if (unlikely (!pd)) return false; + c->push (); + cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); + if (likely (pd->serialize (c, acc.privateDicts[i], privSzr, subrs_link))) + { + unsigned fd = plan.fdmap[i]; + private_dict_infos[fd].size = c->length (); + private_dict_infos[fd].link = c->pop_pack (); + } + else + { + c->pop_discard (); + return false; + } } } - /* variation store */ - if (acc.varStore != &Null(CFF2VariationStore)) + /* CharStrings */ { - assert (plan.offsets.varStoreOffset == (unsigned) (c.head - c.start)); - CFF2VariationStore *dest = c.start_embed (); - if (unlikely (!dest->serialize (&c, acc.varStore))) + CFF2CharStrings *cs = c->start_embed (); + if (unlikely (!cs)) return false; + c->push (); + if (likely (cs->serialize (c, plan.subset_charstrings))) + plan.info.char_strings_link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Variation Store"); + c->pop_discard (); return false; } } /* FDSelect */ - if (acc.fdSelect != &Null(CFF2FDSelect)) + if (acc.fdSelect != &Null (CFF2FDSelect)) { - assert (plan.offsets.FDSelectInfo.offset == (unsigned) (c.head - c.start)); - - if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs.length, *(const FDSelect *)acc.fdSelect, acc.fdArray->count, - plan.subset_fdselect_format, plan.offsets.FDSelectInfo.size, - plan.subset_fdselect_ranges))) + c->push (); + if (likely (hb_serialize_cff_fdselect (c, num_glyphs, *(const FDSelect *)acc.fdSelect, plan.orig_fdcount, + plan.subset_fdselect_format, plan.subset_fdselect_size, + plan.subset_fdselect_ranges))) + plan.info.fd_select.link = c->pop_pack (); + else { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 subset FDSelect"); + c->pop_discard (); return false; } } /* FDArray (FD Index) */ { - assert (plan.offsets.FDArrayInfo.offset == (unsigned) (c.head - c.start)); - CFF2FDArray *fda = c.start_embed (); - if (unlikely (fda == nullptr)) return false; - cff_font_dict_op_serializer_t fontSzr; - if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, - acc.fontDicts, plan.subset_fdcount, plan.fdmap, - fontSzr, plan.privateDictInfos))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray"); - return false; - } + c->push (); + CFF2FDArray *fda = c->start_embed (); + if (unlikely (!fda)) return false; + cff_font_dict_op_serializer_t fontSzr; + auto it = + + hb_zip (+ hb_iter (acc.fontDicts) + | hb_filter ([&] (const cff2_font_dict_values_t &_) + { return plan.fdmap.has (&_ - &acc.fontDicts[0]); }), + hb_iter (private_dict_infos)) + ; + if (unlikely (!fda->serialize (c, it, fontSzr))) return false; + plan.info.fd_array_link = c->pop_pack (); } - /* CharStrings */ + /* variation store */ + if (acc.varStore != &Null (CFF2VariationStore)) { - assert (plan.offsets.charStringsInfo.offset == (unsigned) (c.head - c.start)); - CFF2CharStrings *cs = c.start_embed (); - if (unlikely (cs == nullptr)) return false; - if (unlikely (!cs->serialize (&c, plan.offsets.charStringsInfo.offSize, plan.subset_charstrings))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 CharStrings"); - return false; - } + c->push (); + CFF2VariationStore *dest = c->start_embed (); + if (unlikely (!dest || !dest->serialize (c, acc.varStore))) return false; + plan.info.var_store_link = c->pop_pack (); } - /* private dicts & local subrs */ - assert (plan.offsets.privateDictsOffset == (unsigned) (c.head - c.start)); - for (unsigned int i = 0; i < acc.privateDicts.length; i++) + OT::cff2 *cff2 = c->allocate_min (); + if (unlikely (!cff2)) return false; + + /* header */ + cff2->version.major = 0x02; + cff2->version.minor = 0x00; + cff2->topDict = OT::cff2::static_size; + + /* top dict */ { - if (plan.fdmap.includes (i)) - { - PrivateDict *pd = c.start_embed (); - if (unlikely (pd == nullptr)) return false; - unsigned int priv_size = plan.privateDictInfos[plan.fdmap[i]].size; - bool result; - cff_private_dict_op_serializer_t privSzr (plan.desubroutinize, plan.drop_hints); - /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ - unsigned int subroffset = (plan.offsets.localSubrsInfos[i].size > 0)? priv_size: 0; - result = pd->serialize (&c, acc.privateDicts[i], privSzr, subroffset); - if (unlikely (!result)) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i); - return false; - } - if (plan.offsets.localSubrsInfos[i].size > 0) - { - CFF2Subrs *dest = c.start_embed (); - if (unlikely (dest == nullptr)) return false; - if (unlikely (!dest->serialize (&c, plan.offsets.localSubrsInfos[i].offSize, plan.subset_localsubrs[i]))) - { - DEBUG_MSG (SUBSET, nullptr, "failed to serialize local subroutines"); - return false; - } - } - } + TopDict &dict = cff2 + cff2->topDict; + cff2_top_dict_op_serializer_t topSzr; + if (unlikely (!dict.serialize (c, acc.topDict, topSzr, plan.info))) return false; + cff2->topDictSize = c->head - (const char *)&dict; } - assert (c.head == c.end); - c.end_serialize (); - - return true; + /* global subrs */ + { + CFF2Subrs *dest = c->start_embed (); + if (unlikely (!dest)) return false; + return dest->serialize (c, plan.subset_globalsubrs); + } } static bool _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, - const char *data, - hb_subset_plan_t *plan, - hb_blob_t **prime /* OUT */) + hb_subset_context_t *c) { cff2_subset_plan cff2_plan; - if (unlikely (!cff2_plan.create (acc, plan))) - { - DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan."); - return false; - } - - unsigned int cff2_prime_size = cff2_plan.get_final_size (); - char *cff2_prime_data = (char *) calloc (1, cff2_prime_size); - - if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs, - cff2_prime_size, cff2_prime_data))) { - DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2."); - free (cff2_prime_data); - return false; - } - - *prime = hb_blob_create (cff2_prime_data, - cff2_prime_size, - HB_MEMORY_MODE_READONLY, - cff2_prime_data, - free); - return true; + if (unlikely (!cff2_plan.create (acc, c->plan))) return false; + return _serialize_cff2 (c->serializer, cff2_plan, acc, c->plan->num_output_glyphs ()); } /** * hb_subset_cff2: - * Subsets the CFF2 table according to a provided plan. - * - * Return value: subsetted cff2 table. + * Subsets the CFF2 table according to a provided subset context. **/ bool -hb_subset_cff2 (hb_subset_plan_t *plan, - hb_blob_t **prime /* OUT */) +hb_subset_cff2 (hb_subset_context_t *c) { - hb_blob_t *cff2_blob = hb_sanitize_context_t().reference_table (plan->source); - const char *data = hb_blob_get_data(cff2_blob, nullptr); - OT::cff2::accelerator_subset_t acc; - acc.init(plan->source); - bool result = likely (acc.is_valid ()) && - _hb_subset_cff2 (acc, data, plan, prime); - - hb_blob_destroy (cff2_blob); + acc.init (c->plan->source); + bool result = likely (acc.is_valid ()) && _hb_subset_cff2 (acc, c); acc.fini (); return result; } + +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.hh index baac1a9be2f..f10556ddd74 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-cff2.hh @@ -32,7 +32,6 @@ #include "hb-subset-plan.hh" HB_INTERNAL bool -hb_subset_cff2 (hb_subset_plan_t *plan, - hb_blob_t **cff2_prime /* OUT */); +hb_subset_cff2 (hb_subset_context_t *c); #endif /* HB_SUBSET_CFF2_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.cc deleted file mode 100644 index 03c39a6dbbe..00000000000 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-glyf.cc +++ /dev/null @@ -1,310 +0,0 @@ -/* - * Copyright © 2018 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Garret Rieger, Roderick Sheeter - */ - -#include "hb-open-type.hh" -#include "hb-ot-glyf-table.hh" -#include "hb-set.h" -#include "hb-subset-glyf.hh" - -static bool -_calculate_glyf_and_loca_prime_size (const OT::glyf::accelerator_t &glyf, - hb_vector_t &glyph_ids, - hb_bool_t drop_hints, - bool *use_short_loca /* OUT */, - unsigned int *glyf_size /* OUT */, - unsigned int *loca_size /* OUT */, - hb_vector_t *instruction_ranges /* OUT */) -{ - unsigned int total = 0; - for (unsigned int i = 0; i < glyph_ids.length; i++) - { - hb_codepoint_t next_glyph = glyph_ids[i]; - if (!instruction_ranges->resize (instruction_ranges->length + 2)) - { - DEBUG_MSG(SUBSET, nullptr, "Failed to resize instruction_ranges."); - return false; - } - unsigned int *instruction_start = &(*instruction_ranges)[instruction_ranges->length - 2]; - *instruction_start = 0; - unsigned int *instruction_end = &(*instruction_ranges)[instruction_ranges->length - 1]; - *instruction_end = 0; - - unsigned int start_offset, end_offset; - if (unlikely (!(glyf.get_offsets (next_glyph, &start_offset, &end_offset) && - glyf.remove_padding (start_offset, &end_offset)))) - { - DEBUG_MSG(SUBSET, nullptr, "Invalid gid %d", next_glyph); - continue; - } - if (end_offset - start_offset < OT::glyf::GlyphHeader::static_size) - continue; /* 0-length glyph */ - - if (drop_hints) - { - if (unlikely (!glyf.get_instruction_offsets (start_offset, end_offset, - instruction_start, instruction_end))) - { - DEBUG_MSG(SUBSET, nullptr, "Unable to get instruction offsets for %d", next_glyph); - return false; - } - } - - total += end_offset - start_offset - (*instruction_end - *instruction_start); - /* round2 so short loca will work */ - total += total % 2; - } - - *glyf_size = total; - *use_short_loca = (total <= 131070); - *loca_size = (glyph_ids.length + 1) - * (*use_short_loca ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32)); - - DEBUG_MSG(SUBSET, nullptr, "preparing to subset glyf: final size %d, loca size %d, using %s loca", - total, - *loca_size, - *use_short_loca ? "short" : "long"); - return true; -} - -static bool -_write_loca_entry (unsigned int id, - unsigned int offset, - bool is_short, - void *loca_prime, - unsigned int loca_size) -{ - unsigned int entry_size = is_short ? sizeof (OT::HBUINT16) : sizeof (OT::HBUINT32); - if ((id + 1) * entry_size <= loca_size) - { - if (is_short) { - ((OT::HBUINT16*) loca_prime) [id].set (offset / 2); - } else { - ((OT::HBUINT32*) loca_prime) [id].set (offset); - } - return true; - } - - // Offset was not written because the write is out of bounds. - DEBUG_MSG(SUBSET, - nullptr, - "WARNING: Attempted to write an out of bounds loca entry at index %d. Loca size is %d.", - id, - loca_size); - return false; -} - -static void -_update_components (hb_subset_plan_t * plan, - char * glyph_start, - unsigned int length) -{ - OT::glyf::CompositeGlyphHeader::Iterator iterator; - if (OT::glyf::CompositeGlyphHeader::get_iterator (glyph_start, - length, - &iterator)) - { - do - { - hb_codepoint_t new_gid; - if (!plan->new_gid_for_old_gid (iterator.current->glyphIndex, - &new_gid)) - continue; - - ((OT::glyf::CompositeGlyphHeader *) iterator.current)->glyphIndex.set (new_gid); - } while (iterator.move_to_next ()); - } -} - -static bool _remove_composite_instruction_flag (char *glyf_prime, unsigned int length) -{ - /* remove WE_HAVE_INSTRUCTIONS from flags in dest */ - OT::glyf::CompositeGlyphHeader::Iterator composite_it; - if (unlikely (!OT::glyf::CompositeGlyphHeader::get_iterator (glyf_prime, length, &composite_it))) return false; - const OT::glyf::CompositeGlyphHeader *glyph; - do { - glyph = composite_it.current; - OT::HBUINT16 *flags = const_cast (&glyph->flags); - flags->set ( (uint16_t) *flags & ~OT::glyf::CompositeGlyphHeader::WE_HAVE_INSTRUCTIONS); - } while (composite_it.move_to_next ()); - return true; -} - -static bool -_write_glyf_and_loca_prime (hb_subset_plan_t *plan, - const OT::glyf::accelerator_t &glyf, - const char *glyf_data, - bool use_short_loca, - hb_vector_t &instruction_ranges, - unsigned int glyf_prime_size, - char *glyf_prime_data /* OUT */, - unsigned int loca_prime_size, - char *loca_prime_data /* OUT */) -{ - hb_vector_t &glyph_ids = plan->glyphs; - char *glyf_prime_data_next = glyf_prime_data; - - bool success = true; - for (unsigned int i = 0; i < glyph_ids.length; i++) - { - unsigned int start_offset, end_offset; - if (unlikely (!(glyf.get_offsets (glyph_ids[i], &start_offset, &end_offset) && - glyf.remove_padding (start_offset, &end_offset)))) - end_offset = start_offset = 0; - - unsigned int instruction_start = instruction_ranges[i * 2]; - unsigned int instruction_end = instruction_ranges[i * 2 + 1]; - - int length = end_offset - start_offset - (instruction_end - instruction_start); - - if (glyf_prime_data_next + length > glyf_prime_data + glyf_prime_size) - { - DEBUG_MSG(SUBSET, - nullptr, - "WARNING: Attempted to write an out of bounds glyph entry for gid %d (length %d)", - i, length); - return false; - } - - if (instruction_start == instruction_end) - memcpy (glyf_prime_data_next, glyf_data + start_offset, length); - else - { - memcpy (glyf_prime_data_next, glyf_data + start_offset, instruction_start - start_offset); - memcpy (glyf_prime_data_next + instruction_start - start_offset, glyf_data + instruction_end, end_offset - instruction_end); - /* if the instructions end at the end this was a composite glyph, else simple */ - if (instruction_end == end_offset) - { - if (unlikely (!_remove_composite_instruction_flag (glyf_prime_data_next, length))) return false; - } - else - /* zero instruction length, which is just before instruction_start */ - memset (glyf_prime_data_next + instruction_start - start_offset - 2, 0, 2); - } - - success = success && _write_loca_entry (i, - glyf_prime_data_next - glyf_prime_data, - use_short_loca, - loca_prime_data, - loca_prime_size); - _update_components (plan, glyf_prime_data_next, length); - - // TODO: don't align to two bytes if using long loca. - glyf_prime_data_next += length + (length % 2); // Align to 2 bytes for short loca. - } - - success = success && _write_loca_entry (glyph_ids.length, - glyf_prime_data_next - glyf_prime_data, - use_short_loca, - loca_prime_data, - loca_prime_size); - return success; -} - -static bool -_hb_subset_glyf_and_loca (const OT::glyf::accelerator_t &glyf, - const char *glyf_data, - hb_subset_plan_t *plan, - bool *use_short_loca, - hb_blob_t **glyf_prime /* OUT */, - hb_blob_t **loca_prime /* OUT */) -{ - // TODO(grieger): Sanity check allocation size for the new table. - hb_vector_t &glyphs_to_retain = plan->glyphs; - - unsigned int glyf_prime_size; - unsigned int loca_prime_size; - hb_vector_t instruction_ranges; - instruction_ranges.init (); - - if (unlikely (!_calculate_glyf_and_loca_prime_size (glyf, - glyphs_to_retain, - plan->drop_hints, - use_short_loca, - &glyf_prime_size, - &loca_prime_size, - &instruction_ranges))) { - instruction_ranges.fini (); - return false; - } - - char *glyf_prime_data = (char *) calloc (1, glyf_prime_size); - char *loca_prime_data = (char *) calloc (1, loca_prime_size); - if (unlikely (!_write_glyf_and_loca_prime (plan, glyf, glyf_data, - *use_short_loca, - instruction_ranges, - glyf_prime_size, glyf_prime_data, - loca_prime_size, loca_prime_data))) { - free (glyf_prime_data); - free (loca_prime_data); - instruction_ranges.fini (); - return false; - } - instruction_ranges.fini (); - - *glyf_prime = hb_blob_create (glyf_prime_data, - glyf_prime_size, - HB_MEMORY_MODE_READONLY, - glyf_prime_data, - free); - *loca_prime = hb_blob_create (loca_prime_data, - loca_prime_size, - HB_MEMORY_MODE_READONLY, - loca_prime_data, - free); - return true; -} - -/** - * hb_subset_glyf: - * Subsets the glyph table according to a provided plan. - * - * Return value: subsetted glyf table. - * - * Since: 1.7.5 - **/ -bool -hb_subset_glyf_and_loca (hb_subset_plan_t *plan, - bool *use_short_loca, /* OUT */ - hb_blob_t **glyf_prime, /* OUT */ - hb_blob_t **loca_prime /* OUT */) -{ - hb_blob_t *glyf_blob = hb_sanitize_context_t ().reference_table (plan->source); - const char *glyf_data = hb_blob_get_data (glyf_blob, nullptr); - - OT::glyf::accelerator_t glyf; - glyf.init (plan->source); - bool result = _hb_subset_glyf_and_loca (glyf, - glyf_data, - plan, - use_short_loca, - glyf_prime, - loca_prime); - - hb_blob_destroy (glyf_blob); - glyf.fini (); - - return result; -} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc index 3feeb5c7592..087981b5243 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.cc @@ -44,7 +44,45 @@ hb_subset_input_create_or_fail () input->unicodes = hb_set_create (); input->glyphs = hb_set_create (); - input->drop_layout = true; + input->name_ids = hb_set_create (); + hb_set_add_range (input->name_ids, 0, 6); + input->name_languages = hb_set_create (); + hb_set_add (input->name_languages, 0x0409); + input->drop_tables = hb_set_create (); + input->drop_hints = false; + input->desubroutinize = false; + input->retain_gids = false; + input->name_legacy = false; + + hb_tag_t default_drop_tables[] = { + // Layout disabled by default + HB_TAG ('G', 'S', 'U', 'B'), + HB_TAG ('G', 'P', 'O', 'S'), + HB_TAG ('G', 'D', 'E', 'F'), + HB_TAG ('m', 'o', 'r', 'x'), + HB_TAG ('m', 'o', 'r', 't'), + HB_TAG ('k', 'e', 'r', 'x'), + HB_TAG ('k', 'e', 'r', 'n'), + + // Copied from fontTools: + HB_TAG ('B', 'A', 'S', 'E'), + HB_TAG ('J', 'S', 'T', 'F'), + HB_TAG ('D', 'S', 'I', 'G'), + HB_TAG ('E', 'B', 'D', 'T'), + HB_TAG ('E', 'B', 'L', 'C'), + HB_TAG ('E', 'B', 'S', 'C'), + HB_TAG ('S', 'V', 'G', ' '), + HB_TAG ('P', 'C', 'L', 'T'), + HB_TAG ('L', 'T', 'S', 'H'), + // Graphite tables + HB_TAG ('F', 'e', 'a', 't'), + HB_TAG ('G', 'l', 'a', 't'), + HB_TAG ('G', 'l', 'o', 'c'), + HB_TAG ('S', 'i', 'l', 'f'), + HB_TAG ('S', 'i', 'l', 'l'), + }; + + input->drop_tables->add_array (default_drop_tables, ARRAY_LENGTH (default_drop_tables)); return input; } @@ -78,6 +116,9 @@ hb_subset_input_destroy (hb_subset_input_t *subset_input) hb_set_destroy (subset_input->unicodes); hb_set_destroy (subset_input->glyphs); + hb_set_destroy (subset_input->name_ids); + hb_set_destroy (subset_input->name_languages); + hb_set_destroy (subset_input->drop_tables); free (subset_input); } @@ -106,6 +147,24 @@ hb_subset_input_glyph_set (hb_subset_input_t *subset_input) return subset_input->glyphs; } +HB_EXTERN hb_set_t * +hb_subset_input_nameid_set (hb_subset_input_t *subset_input) +{ + return subset_input->name_ids; +} + +HB_EXTERN hb_set_t * +hb_subset_input_namelangid_set (hb_subset_input_t *subset_input) +{ + return subset_input->name_languages; +} + +HB_EXTERN hb_set_t * +hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input) +{ + return subset_input->drop_tables; +} + HB_EXTERN void hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, hb_bool_t drop_hints) @@ -120,27 +179,51 @@ hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input) } HB_EXTERN void -hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input, - hb_bool_t drop_layout) +hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, + hb_bool_t desubroutinize) { - subset_input->drop_layout = drop_layout; + subset_input->desubroutinize = desubroutinize; } HB_EXTERN hb_bool_t -hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input) +hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input) { - return subset_input->drop_layout; + return subset_input->desubroutinize; } +/** + * hb_subset_input_set_retain_gids: + * @subset_input: a subset_input. + * @retain_gids: If true the subsetter will not renumber glyph ids. + * Since: 2.4.0 + **/ HB_EXTERN void -hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, - hb_bool_t desubroutinize) +hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input, + hb_bool_t retain_gids) { - subset_input->desubroutinize = desubroutinize; + subset_input->retain_gids = retain_gids; } +/** + * hb_subset_input_get_retain_gids: + * Returns: value of retain_gids. + * Since: 2.4.0 + **/ HB_EXTERN hb_bool_t -hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input) +hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input) { - return subset_input->desubroutinize; + return subset_input->retain_gids; +} + +HB_EXTERN void +hb_subset_input_set_name_legacy (hb_subset_input_t *subset_input, + hb_bool_t name_legacy) +{ + subset_input->name_legacy = name_legacy; +} + +HB_EXTERN hb_bool_t +hb_subset_input_get_name_legacy (hb_subset_input_t *subset_input) +{ + return subset_input->name_legacy; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.hh index 8dad94f584e..0aeb96695b7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-input.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-input.hh @@ -40,15 +40,19 @@ struct hb_subset_input_t hb_set_t *unicodes; hb_set_t *glyphs; - - bool drop_hints : 1; - bool drop_layout : 1; - bool desubroutinize : 1; + hb_set_t *name_ids; + hb_set_t *name_languages; + hb_set_t *drop_tables; + + bool drop_hints; + bool desubroutinize; + bool retain_gids; + bool name_legacy; /* TODO * * features * lookups - * nameIDs + * name_ids * ... */ }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc index 69b432872da..2f2f343ae2b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.cc @@ -30,44 +30,47 @@ #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" +#include "hb-ot-layout-gdef-table.hh" +#include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-layout-gsub-table.hh" #include "hb-ot-cff1-table.hh" +#include "hb-ot-color-colr-table.hh" +#include "hb-ot-var-fvar-table.hh" +#include "hb-ot-stat-table.hh" -static void -_add_gid_and_children (const OT::glyf::accelerator_t &glyf, - hb_codepoint_t gid, - hb_set_t *gids_to_retain) -{ - if (hb_set_has (gids_to_retain, gid)) - // Already visited this gid, ignore. - return; - - hb_set_add (gids_to_retain, gid); - OT::glyf::CompositeGlyphHeader::Iterator composite; - if (glyf.get_composite (gid, &composite)) - { - do - { - _add_gid_and_children (glyf, (hb_codepoint_t) composite.current->glyphIndex, gids_to_retain); - } while (composite.move_to_next()); - } -} - -static void +#ifndef HB_NO_SUBSET_CFF +static inline void _add_cff_seac_components (const OT::cff1::accelerator_t &cff, - hb_codepoint_t gid, - hb_set_t *gids_to_retain) + hb_codepoint_t gid, + hb_set_t *gids_to_retain) { hb_codepoint_t base_gid, accent_gid; if (cff.get_seac_components (gid, &base_gid, &accent_gid)) { - hb_set_add (gids_to_retain, base_gid); - hb_set_add (gids_to_retain, accent_gid); + gids_to_retain->add (base_gid); + gids_to_retain->add (accent_gid); } } +#endif +#ifndef HB_NO_SUBSET_LAYOUT static void -_gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain) +_remap_indexes (const hb_set_t *indexes, + hb_map_t *mapping /* OUT */) +{ + unsigned count = indexes->get_population (); + + for (auto _ : + hb_zip (indexes->iter (), hb_range (count))) + mapping->set (_.first, _.second); + +} + +static inline void +_gsub_closure_glyphs_lookups_features (hb_face_t *face, + hb_set_t *gids_to_retain, + hb_map_t *gsub_lookups, + hb_map_t *gsub_features) { hb_set_t lookup_indices; hb_ot_layout_collect_lookups (face, @@ -79,9 +82,88 @@ _gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain) hb_ot_layout_lookups_substitute_closure (face, &lookup_indices, gids_to_retain); + hb_blob_ptr_t gsub = hb_sanitize_context_t ().reference_table (face); + gsub->closure_lookups (face, + gids_to_retain, + &lookup_indices); + _remap_indexes (&lookup_indices, gsub_lookups); + + //closure features + hb_set_t feature_indices; + gsub->closure_features (gsub_lookups, &feature_indices); + _remap_indexes (&feature_indices, gsub_features); + gsub.destroy (); } -static void +static inline void +_gpos_closure_lookups_features (hb_face_t *face, + const hb_set_t *gids_to_retain, + hb_map_t *gpos_lookups, + hb_map_t *gpos_features) +{ + hb_set_t lookup_indices; + hb_ot_layout_collect_lookups (face, + HB_OT_TAG_GPOS, + nullptr, + nullptr, + nullptr, + &lookup_indices); + hb_blob_ptr_t gpos = hb_sanitize_context_t ().reference_table (face); + gpos->closure_lookups (face, + gids_to_retain, + &lookup_indices); + _remap_indexes (&lookup_indices, gpos_lookups); + + //closure features + hb_set_t feature_indices; + gpos->closure_features (gpos_lookups, &feature_indices); + _remap_indexes (&feature_indices, gpos_features); + gpos.destroy (); +} +#endif + +#ifndef HB_NO_VAR +static inline void + _collect_layout_variation_indices (hb_face_t *face, + const hb_set_t *glyphset, + const hb_map_t *gpos_lookups, + hb_set_t *layout_variation_indices, + hb_map_t *layout_variation_idx_map) +{ + hb_blob_ptr_t gdef = hb_sanitize_context_t ().reference_table (face); + hb_blob_ptr_t gpos = hb_sanitize_context_t ().reference_table (face); + + if (!gdef->has_data ()) + { + gdef.destroy (); + gpos.destroy (); + return; + } + OT::hb_collect_variation_indices_context_t c (layout_variation_indices, glyphset, gpos_lookups); + gdef->collect_variation_indices (&c); + + if (hb_ot_layout_has_positioning (face)) + gpos->collect_variation_indices (&c); + + gdef->remap_layout_variation_indices (layout_variation_indices, layout_variation_idx_map); + + gdef.destroy (); + gpos.destroy (); +} +#endif + +static inline void +_cmap_closure (hb_face_t *face, + const hb_set_t *unicodes, + hb_set_t *glyphset) +{ + OT::cmap::accelerator_t cmap; + cmap.init (face); + cmap.table->closure_glyphs (unicodes, glyphset); + cmap.fini (); +} + +static inline void _remove_invalid_gids (hb_set_t *glyphs, unsigned int num_glyphs) { @@ -93,23 +175,29 @@ _remove_invalid_gids (hb_set_t *glyphs, } } -static hb_set_t * -_populate_gids_to_retain (hb_face_t *face, +static void +_populate_gids_to_retain (hb_subset_plan_t* plan, const hb_set_t *unicodes, + const hb_set_t *input_glyphs_to_retain, bool close_over_gsub, - hb_set_t *unicodes_to_retain, - hb_map_t *codepoint_to_glyph, - hb_vector_t *glyphs) + bool close_over_gpos, + bool close_over_gdef) { OT::cmap::accelerator_t cmap; OT::glyf::accelerator_t glyf; +#ifndef HB_NO_SUBSET_CFF OT::cff1::accelerator_t cff; - cmap.init (face); - glyf.init (face); - cff.init (face); +#endif + OT::COLR::accelerator_t colr; + cmap.init (plan->source); + glyf.init (plan->source); +#ifndef HB_NO_SUBSET_CFF + cff.init (plan->source); +#endif + colr.init (plan->source); - hb_set_t *initial_gids_to_retain = hb_set_create (); - initial_gids_to_retain->add (0); // Not-def + plan->_glyphset_gsub->add (0); // Not-def + hb_set_union (plan->_glyphset_gsub, input_glyphs_to_retain); hb_codepoint_t cp = HB_SET_VALUE_INVALID; while (unicodes->next (&cp)) @@ -120,48 +208,96 @@ _populate_gids_to_retain (hb_face_t *face, DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp); continue; } - unicodes_to_retain->add (cp); - codepoint_to_glyph->set (cp, gid); - initial_gids_to_retain->add (gid); + plan->unicodes->add (cp); + plan->codepoint_to_glyph->set (cp, gid); + plan->_glyphset_gsub->add (gid); } + _cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub); + +#ifndef HB_NO_SUBSET_LAYOUT if (close_over_gsub) - // Add all glyphs needed for GSUB substitutions. - _gsub_closure (face, initial_gids_to_retain); + // closure all glyphs/lookups/features needed for GSUB substitutions. + _gsub_closure_glyphs_lookups_features (plan->source, plan->_glyphset_gsub, plan->gsub_lookups, plan->gsub_features); + + if (close_over_gpos) + _gpos_closure_lookups_features (plan->source, plan->_glyphset_gsub, plan->gpos_lookups, plan->gpos_features); +#endif + _remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ()); // Populate a full set of glyphs to retain by adding all referenced // composite glyphs. hb_codepoint_t gid = HB_SET_VALUE_INVALID; - hb_set_t *all_gids_to_retain = hb_set_create (); - while (initial_gids_to_retain->next (&gid)) + while (plan->_glyphset_gsub->next (&gid)) { - _add_gid_and_children (glyf, gid, all_gids_to_retain); + glyf.add_gid_and_children (gid, plan->_glyphset); +#ifndef HB_NO_SUBSET_CFF if (cff.is_valid ()) - _add_cff_seac_components (cff, gid, all_gids_to_retain); + _add_cff_seac_components (cff, gid, plan->_glyphset); +#endif + if (colr.is_valid ()) + colr.closure_glyphs (gid, plan->_glyphset); } - hb_set_destroy (initial_gids_to_retain); - _remove_invalid_gids (all_gids_to_retain, face->get_num_glyphs ()); + _remove_invalid_gids (plan->_glyphset, plan->source->get_num_glyphs ()); - glyphs->alloc (all_gids_to_retain->get_population ()); - gid = HB_SET_VALUE_INVALID; - while (all_gids_to_retain->next (&gid)) - glyphs->push (gid); +#ifndef HB_NO_VAR + if (close_over_gdef) + _collect_layout_variation_indices (plan->source, plan->_glyphset, plan->gpos_lookups, plan->layout_variation_indices, plan->layout_variation_idx_map); +#endif +#ifndef HB_NO_SUBSET_CFF cff.fini (); +#endif glyf.fini (); cmap.fini (); - - return all_gids_to_retain; } static void -_create_old_gid_to_new_gid_map (const hb_vector_t &glyphs, - hb_map_t *glyph_map) +_create_old_gid_to_new_gid_map (const hb_face_t *face, + bool retain_gids, + const hb_set_t *all_gids_to_retain, + hb_map_t *glyph_map, /* OUT */ + hb_map_t *reverse_glyph_map, /* OUT */ + unsigned int *num_glyphs /* OUT */) { - for (unsigned int i = 0; i < glyphs.length; i++) { - glyph_map->set (glyphs[i], i); + if (!retain_gids) + { + + hb_enumerate (hb_iter (all_gids_to_retain), (hb_codepoint_t) 0) + | hb_sink (reverse_glyph_map) + ; + *num_glyphs = reverse_glyph_map->get_population (); + } else { + + hb_iter (all_gids_to_retain) + | hb_map ([] (hb_codepoint_t _) { + return hb_pair_t (_, _); + }) + | hb_sink (reverse_glyph_map) + ; + + unsigned max_glyph = + + hb_iter (all_gids_to_retain) + | hb_reduce (hb_max, 0u) + ; + *num_glyphs = max_glyph + 1; } + + + reverse_glyph_map->iter () + | hb_map (&hb_pair_t::reverse) + | hb_sink (glyph_map) + ; +} + +static void +_nameid_closure (hb_face_t *face, + hb_set_t *nameids) +{ +#ifndef HB_NO_STYLE + face->table.STAT->collect_name_ids (nameids); +#endif +#ifndef HB_NO_VAR + face->table.fvar->collect_name_ids (nameids); +#endif } /** @@ -175,28 +311,52 @@ _create_old_gid_to_new_gid_map (const hb_vector_t &glyphs, * Since: 1.7.5 **/ hb_subset_plan_t * -hb_subset_plan_create (hb_face_t *face, - hb_subset_input_t *input) +hb_subset_plan_create (hb_face_t *face, + hb_subset_input_t *input) { - hb_subset_plan_t *plan = hb_object_create (); + hb_subset_plan_t *plan; + if (unlikely (!(plan = hb_object_create ()))) + return const_cast (&Null (hb_subset_plan_t)); + plan->successful = true; plan->drop_hints = input->drop_hints; - plan->drop_layout = input->drop_layout; plan->desubroutinize = input->desubroutinize; - plan->unicodes = hb_set_create(); - plan->glyphs.init(); + plan->retain_gids = input->retain_gids; + plan->name_legacy = input->name_legacy; + plan->unicodes = hb_set_create (); + plan->name_ids = hb_set_reference (input->name_ids); + _nameid_closure (face, plan->name_ids); + plan->name_languages = hb_set_reference (input->name_languages); + plan->glyphs_requested = hb_set_reference (input->glyphs); + plan->drop_tables = hb_set_reference (input->drop_tables); plan->source = hb_face_reference (face); plan->dest = hb_face_builder_create (); - plan->codepoint_to_glyph = hb_map_create(); - plan->glyph_map = hb_map_create(); - plan->glyphset = _populate_gids_to_retain (face, - input->unicodes, - !plan->drop_layout, - plan->unicodes, - plan->codepoint_to_glyph, - &plan->glyphs); - _create_old_gid_to_new_gid_map (plan->glyphs, - plan->glyph_map); + + plan->_glyphset = hb_set_create (); + plan->_glyphset_gsub = hb_set_create (); + plan->codepoint_to_glyph = hb_map_create (); + plan->glyph_map = hb_map_create (); + plan->reverse_glyph_map = hb_map_create (); + plan->gsub_lookups = hb_map_create (); + plan->gpos_lookups = hb_map_create (); + plan->gsub_features = hb_map_create (); + plan->gpos_features = hb_map_create (); + plan->layout_variation_indices = hb_set_create (); + plan->layout_variation_idx_map = hb_map_create (); + + _populate_gids_to_retain (plan, + input->unicodes, + input->glyphs, + !input->drop_tables->has (HB_OT_TAG_GSUB), + !input->drop_tables->has (HB_OT_TAG_GPOS), + !input->drop_tables->has (HB_OT_TAG_GDEF)); + + _create_old_gid_to_new_gid_map (face, + input->retain_gids, + plan->_glyphset, + plan->glyph_map, + plan->reverse_glyph_map, + &plan->_num_output_glyphs); return plan; } @@ -212,12 +372,24 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) if (!hb_object_destroy (plan)) return; hb_set_destroy (plan->unicodes); - plan->glyphs.fini (); + hb_set_destroy (plan->name_ids); + hb_set_destroy (plan->name_languages); + hb_set_destroy (plan->glyphs_requested); + hb_set_destroy (plan->drop_tables); hb_face_destroy (plan->source); hb_face_destroy (plan->dest); hb_map_destroy (plan->codepoint_to_glyph); hb_map_destroy (plan->glyph_map); - hb_set_destroy (plan->glyphset); + hb_map_destroy (plan->reverse_glyph_map); + hb_set_destroy (plan->_glyphset); + hb_set_destroy (plan->_glyphset_gsub); + hb_map_destroy (plan->gsub_lookups); + hb_map_destroy (plan->gpos_lookups); + hb_map_destroy (plan->gsub_features); + hb_map_destroy (plan->gpos_features); + hb_set_destroy (plan->layout_variation_indices); + hb_map_destroy (plan->layout_variation_idx_map); + free (plan); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh index 83dd370f6a7..b029548e0dd 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset-plan.hh @@ -33,30 +33,111 @@ #include "hb-subset-input.hh" #include "hb-map.hh" +#include "hb-set.hh" struct hb_subset_plan_t { hb_object_header_t header; + bool successful : 1; bool drop_hints : 1; - bool drop_layout : 1; bool desubroutinize : 1; + bool retain_gids : 1; + bool name_legacy : 1; // For each cp that we'd like to retain maps to the corresponding gid. hb_set_t *unicodes; - hb_vector_t glyphs; - hb_set_t *glyphset; + // name_ids we would like to retain + hb_set_t *name_ids; + // name_languages we would like to retain + hb_set_t *name_languages; + + //glyph ids requested to retain + hb_set_t *glyphs_requested; + + // Tables which should be dropped. + hb_set_t *drop_tables; + + // The glyph subset hb_map_t *codepoint_to_glyph; + + // Old -> New glyph id mapping hb_map_t *glyph_map; + hb_map_t *reverse_glyph_map; // Plan is only good for a specific source/dest so keep them with it hb_face_t *source; hb_face_t *dest; - bool new_gid_for_codepoint (hb_codepoint_t codepoint, - hb_codepoint_t *new_gid) const + unsigned int _num_output_glyphs; + hb_set_t *_glyphset; + hb_set_t *_glyphset_gsub; + + //active lookups we'd like to retain + hb_map_t *gsub_lookups; + hb_map_t *gpos_lookups; + + //active features we'd like to retain + hb_map_t *gsub_features; + hb_map_t *gpos_features; + + //The set of layout item variation store delta set indices to be retained + hb_set_t *layout_variation_indices; + //Old -> New layout item variation store delta set index mapping + hb_map_t *layout_variation_idx_map; + + public: + + bool in_error () const { return !successful; } + + bool check_success(bool success) + { + successful = (successful && success); + return successful; + } + + /* + * The set of input glyph ids which will be retained in the subset. + * Does NOT include ids kept due to retain_gids. You probably want to use + * glyph_map/reverse_glyph_map. + */ + inline const hb_set_t * + glyphset () const + { + return _glyphset; + } + + /* + * The set of input glyph ids which will be retained in the subset. + */ + inline const hb_set_t * + glyphset_gsub () const + { + return _glyphset_gsub; + } + + /* + * The total number of output glyphs in the final subset. + */ + inline unsigned int + num_output_glyphs () const + { + return _num_output_glyphs; + } + + /* + * Given an output gid , returns true if that glyph id is an empty + * glyph (ie. it's a gid that we are dropping all data for). + */ + inline bool is_empty_glyph (hb_codepoint_t gid) const + { + return !_glyphset->has (gid); + } + + inline bool new_gid_for_codepoint (hb_codepoint_t codepoint, + hb_codepoint_t *new_gid) const { hb_codepoint_t old_gid = codepoint_to_glyph->get (codepoint); if (old_gid == HB_MAP_VALUE_INVALID) @@ -65,8 +146,8 @@ struct hb_subset_plan_t return new_gid_for_old_gid (old_gid, new_gid); } - bool new_gid_for_old_gid (hb_codepoint_t old_gid, - hb_codepoint_t *new_gid) const + inline bool new_gid_for_old_gid (hb_codepoint_t old_gid, + hb_codepoint_t *new_gid) const { hb_codepoint_t gid = glyph_map->get (old_gid); if (gid == HB_MAP_VALUE_INVALID) @@ -76,7 +157,18 @@ struct hb_subset_plan_t return true; } - bool + inline bool old_gid_for_new_gid (hb_codepoint_t new_gid, + hb_codepoint_t *old_gid) const + { + hb_codepoint_t gid = reverse_glyph_map->get (new_gid); + if (gid == HB_MAP_VALUE_INVALID) + return false; + + *old_gid = gid; + return true; + } + + inline bool add_table (hb_tag_t tag, hb_blob_t *contents) { diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc index 65841672ad6..43afc30b9ac 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.cc @@ -28,7 +28,6 @@ #include "hb-open-type.hh" #include "hb-subset.hh" -#include "hb-subset-glyf.hh" #include "hb-open-file.hh" #include "hb-ot-cmap-table.hh" @@ -38,218 +37,194 @@ #include "hb-ot-hhea-table.hh" #include "hb-ot-hmtx-table.hh" #include "hb-ot-maxp-table.hh" +#include "hb-ot-color-sbix-table.hh" +#include "hb-ot-color-colr-table.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-post-table.hh" #include "hb-ot-cff1-table.hh" #include "hb-ot-cff2-table.hh" #include "hb-ot-vorg-table.hh" +#include "hb-ot-name-table.hh" +#include "hb-ot-color-cbdt-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" +#include "hb-ot-var-gvar-table.hh" +#include "hb-ot-var-hvar-table.hh" -static unsigned int -_plan_estimate_subset_table_size (hb_subset_plan_t *plan, - unsigned int table_len) +static unsigned +_plan_estimate_subset_table_size (hb_subset_plan_t *plan, unsigned table_len) { - unsigned int src_glyphs = plan->source->get_num_glyphs (); - unsigned int dst_glyphs = plan->glyphset->get_population (); + unsigned src_glyphs = plan->source->get_num_glyphs (); + unsigned dst_glyphs = plan->glyphset ()->get_population (); if (unlikely (!src_glyphs)) return 512 + table_len; - return 512 + (unsigned int) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); + return 512 + (unsigned) (table_len * sqrt ((double) dst_glyphs / src_glyphs)); } template static bool -_subset2 (hb_subset_plan_t *plan) +_subset (hb_subset_plan_t *plan) { + bool result = false; hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table (plan->source); const TableType *table = source_blob->as (); hb_tag_t tag = TableType::tableTag; - hb_bool_t result = false; if (source_blob->data) { hb_vector_t buf; - unsigned int buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); + /* TODO Not all tables are glyph-related. 'name' table size for example should not be + * affected by number of glyphs. Accommodate that. */ + unsigned buf_size = _plan_estimate_subset_table_size (plan, source_blob->length); + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c initial estimated table size: %u bytes.", HB_UNTAG (tag), buf_size); if (unlikely (!buf.alloc (buf_size))) { - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to allocate %u bytes.", HB_UNTAG (tag), buf_size); + hb_blob_destroy (source_blob); return false; } retry: hb_serialize_context_t serializer ((void *) buf, buf_size); - hb_subset_context_t c (plan, &serializer); - result = table->subset (&c); - if (serializer.in_error ()) + serializer.start_serialize (); + hb_subset_context_t c (source_blob, plan, &serializer, tag); + bool needed = table->subset (&c); + if (serializer.ran_out_of_room) { buf_size += (buf_size >> 1) + 32; - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size); + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c ran out of room; reallocating to %u bytes.", HB_UNTAG (tag), buf_size); if (unlikely (!buf.alloc (buf_size))) { - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size); + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c failed to reallocate %u bytes.", HB_UNTAG (tag), buf_size); + hb_blob_destroy (source_blob); return false; } goto retry; } + serializer.end_serialize (); + + result = !serializer.in_error (); + if (result) { - hb_blob_t *dest_blob = serializer.copy_blob (); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length); - result = c.plan->add_table (tag, dest_blob); - hb_blob_destroy (dest_blob); - } - else - { - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); - result = true; + if (needed) + { + hb_blob_t *dest_blob = serializer.copy_blob (); + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c final subset table size: %u bytes.", HB_UNTAG (tag), dest_blob->length); + result = c.plan->add_table (tag, dest_blob); + hb_blob_destroy (dest_blob); + } + else + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset table subsetted to empty.", HB_UNTAG (tag)); + } } } else - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); hb_blob_destroy (source_blob); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!"); + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!"); return result; } -template static bool -_subset (hb_subset_plan_t *plan) +_is_table_present (hb_face_t *source, hb_tag_t tag) { - hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table (plan->source); - const TableType *table = source_blob->as (); - - hb_tag_t tag = TableType::tableTag; - hb_bool_t result = false; - if (source_blob->data) - result = table->subset (plan); - else - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset sanitize failed on source table.", HB_UNTAG (tag)); - - hb_blob_destroy (source_blob); - DEBUG_MSG(SUBSET, nullptr, "OT::%c%c%c%c::subset %s", HB_UNTAG (tag), result ? "success" : "FAILED!"); - return result; + hb_tag_t table_tags[32]; + unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); + while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) + { + for (unsigned i = 0; i < num_tables; ++i) + if (table_tags[i] == tag) + return true; + offset += num_tables; + } + return false; } - static bool -_subset_table (hb_subset_plan_t *plan, - hb_tag_t tag) +_should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) { - DEBUG_MSG(SUBSET, nullptr, "begin subset %c%c%c%c", HB_UNTAG (tag)); - bool result = true; - switch (tag) { - case HB_OT_TAG_glyf: - result = _subset (plan); - break; - case HB_OT_TAG_hdmx: - result = _subset (plan); - break; - case HB_OT_TAG_head: - // TODO that won't work well if there is no glyf - DEBUG_MSG(SUBSET, nullptr, "skip head, handled by glyf"); - result = true; - break; - case HB_OT_TAG_hhea: - DEBUG_MSG(SUBSET, nullptr, "skip hhea handled by hmtx"); - return true; - case HB_OT_TAG_hmtx: - result = _subset (plan); - break; - case HB_OT_TAG_vhea: - DEBUG_MSG(SUBSET, nullptr, "skip vhea handled by vmtx"); - return true; - case HB_OT_TAG_vmtx: - result = _subset (plan); - break; - case HB_OT_TAG_maxp: - result = _subset (plan); - break; - case HB_OT_TAG_loca: - DEBUG_MSG(SUBSET, nullptr, "skip loca handled by glyf"); - return true; - case HB_OT_TAG_cmap: - result = _subset (plan); - break; - case HB_OT_TAG_OS2: - result = _subset (plan); - break; - case HB_OT_TAG_post: - result = _subset (plan); - break; - case HB_OT_TAG_cff1: - result = _subset (plan); - break; - case HB_OT_TAG_cff2: - result = _subset (plan); - break; - case HB_OT_TAG_VORG: - result = _subset (plan); - break; - case HB_OT_TAG_GDEF: - result = _subset2 (plan); - break; - case HB_OT_TAG_GSUB: - result = _subset2 (plan); - break; - case HB_OT_TAG_GPOS: - result = _subset2 (plan); - break; + if (plan->drop_tables->has (tag)) + return true; - default: - hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); - if (likely (source_table)) - result = plan->add_table (tag, source_table); - else - result = false; - hb_blob_destroy (source_table); - break; + switch (tag) + { + case HB_TAG ('c','v','a','r'): /* hint table, fallthrough */ + case HB_TAG ('c','v','t',' '): /* hint table, fallthrough */ + case HB_TAG ('f','p','g','m'): /* hint table, fallthrough */ + case HB_TAG ('p','r','e','p'): /* hint table, fallthrough */ + case HB_TAG ('h','d','m','x'): /* hint table, fallthrough */ + case HB_TAG ('V','D','M','X'): /* hint table, fallthrough */ + return plan->drop_hints; + +#ifdef HB_NO_SUBSET_LAYOUT + // Drop Layout Tables if requested. + case HB_OT_TAG_GDEF: + case HB_OT_TAG_GPOS: + case HB_OT_TAG_GSUB: + case HB_TAG ('m','o','r','x'): + case HB_TAG ('m','o','r','t'): + case HB_TAG ('k','e','r','x'): + case HB_TAG ('k','e','r','n'): + return true; +#endif + + default: + return false; } - DEBUG_MSG(SUBSET, nullptr, "subset %c%c%c%c %s", HB_UNTAG (tag), result ? "ok" : "FAILED"); - return result; } static bool -_should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) +_subset_table (hb_subset_plan_t *plan, hb_tag_t tag) { - switch (tag) { - case HB_TAG ('c', 'v', 'a', 'r'): /* hint table, fallthrough */ - case HB_TAG ('c', 'v', 't', ' '): /* hint table, fallthrough */ - case HB_TAG ('f', 'p', 'g', 'm'): /* hint table, fallthrough */ - case HB_TAG ('p', 'r', 'e', 'p'): /* hint table, fallthrough */ - case HB_TAG ('h', 'd', 'm', 'x'): /* hint table, fallthrough */ - case HB_TAG ('V', 'D', 'M', 'X'): /* hint table, fallthrough */ - return plan->drop_hints; - // Drop Layout Tables if requested. - case HB_OT_TAG_GDEF: - case HB_OT_TAG_GPOS: - case HB_OT_TAG_GSUB: - return plan->drop_layout; - // Drop these tables below by default, list pulled - // from fontTools: - case HB_TAG ('B', 'A', 'S', 'E'): - case HB_TAG ('J', 'S', 'T', 'F'): - case HB_TAG ('D', 'S', 'I', 'G'): - case HB_TAG ('E', 'B', 'D', 'T'): - case HB_TAG ('E', 'B', 'L', 'C'): - case HB_TAG ('E', 'B', 'S', 'C'): - case HB_TAG ('S', 'V', 'G', ' '): - case HB_TAG ('P', 'C', 'L', 'T'): - case HB_TAG ('L', 'T', 'S', 'H'): - // Graphite tables: - case HB_TAG ('F', 'e', 'a', 't'): - case HB_TAG ('G', 'l', 'a', 't'): - case HB_TAG ('G', 'l', 'o', 'c'): - case HB_TAG ('S', 'i', 'l', 'f'): - case HB_TAG ('S', 'i', 'l', 'l'): - // Colour - case HB_TAG ('s', 'b', 'i', 'x'): - return true; - default: - return false; + DEBUG_MSG (SUBSET, nullptr, "subset %c%c%c%c", HB_UNTAG (tag)); + switch (tag) + { + case HB_OT_TAG_glyf: return _subset (plan); + case HB_OT_TAG_hdmx: return _subset (plan); + case HB_OT_TAG_name: return _subset (plan); + case HB_OT_TAG_head: + if (_is_table_present (plan->source, HB_OT_TAG_glyf) && !_should_drop_table (plan, HB_OT_TAG_glyf)) + return true; /* skip head, handled by glyf */ + return _subset (plan); + case HB_OT_TAG_hhea: return true; /* skip hhea, handled by hmtx */ + case HB_OT_TAG_hmtx: return _subset (plan); + case HB_OT_TAG_vhea: return true; /* skip vhea, handled by vmtx */ + case HB_OT_TAG_vmtx: return _subset (plan); + case HB_OT_TAG_maxp: return _subset (plan); + case HB_OT_TAG_sbix: return _subset (plan); + case HB_OT_TAG_loca: return true; /* skip loca, handled by glyf */ + case HB_OT_TAG_cmap: return _subset (plan); + case HB_OT_TAG_OS2 : return _subset (plan); + case HB_OT_TAG_post: return _subset (plan); + case HB_OT_TAG_COLR: return _subset (plan); + case HB_OT_TAG_CBLC: return _subset (plan); + case HB_OT_TAG_CBDT: return true; /* skip CBDT, handled by CBLC */ + +#ifndef HB_NO_SUBSET_CFF + case HB_OT_TAG_cff1: return _subset (plan); + case HB_OT_TAG_cff2: return _subset (plan); + case HB_OT_TAG_VORG: return _subset (plan); +#endif + +#ifndef HB_NO_SUBSET_LAYOUT + case HB_OT_TAG_GDEF: return _subset (plan); + case HB_OT_TAG_GSUB: return _subset (plan); + case HB_OT_TAG_GPOS: return _subset (plan); + case HB_OT_TAG_gvar: return _subset (plan); + case HB_OT_TAG_HVAR: return _subset (plan); + case HB_OT_TAG_VVAR: return _subset (plan); +#endif + + default: + hb_blob_t *source_table = hb_face_reference_table (plan->source, tag); + bool result = plan->add_table (tag, source_table); + hb_blob_destroy (source_table); + return result; } } @@ -261,33 +236,34 @@ _should_drop_table (hb_subset_plan_t *plan, hb_tag_t tag) * Subsets a font according to provided input. **/ hb_face_t * -hb_subset (hb_face_t *source, - hb_subset_input_t *input) +hb_subset (hb_face_t *source, hb_subset_input_t *input) { if (unlikely (!input || !source)) return hb_face_get_empty (); hb_subset_plan_t *plan = hb_subset_plan_create (source, input); + if (unlikely (plan->in_error ())) + return hb_face_get_empty (); - hb_tag_t table_tags[32]; - unsigned int offset = 0, count; + hb_set_t tags_set; bool success = true; - do { - count = ARRAY_LENGTH (table_tags); - hb_face_get_table_tags (source, offset, &count, table_tags); - for (unsigned int i = 0; i < count; i++) + hb_tag_t table_tags[32]; + unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); + while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) + { + for (unsigned i = 0; i < num_tables; ++i) { hb_tag_t tag = table_tags[i]; - if (_should_drop_table (plan, tag)) - { - DEBUG_MSG(SUBSET, nullptr, "drop %c%c%c%c", HB_UNTAG (tag)); - continue; - } - success = success && _subset_table (plan, tag); + if (_should_drop_table (plan, tag) && !tags_set.has (tag)) continue; + tags_set.add (tag); + success = _subset_table (plan, tag); + if (unlikely (!success)) goto end; } - offset += count; - } while (success && count == ARRAY_LENGTH (table_tags)); + offset += num_tables; + } +end: hb_face_t *result = success ? hb_face_reference (plan->dest) : hb_face_get_empty (); + hb_subset_plan_destroy (plan); return result; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.h b/src/java.desktop/share/native/libharfbuzz/hb-subset.h index 75cc00aa39d..3deab75e2e2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.h @@ -54,6 +54,15 @@ hb_subset_input_unicode_set (hb_subset_input_t *subset_input); HB_EXTERN hb_set_t * hb_subset_input_glyph_set (hb_subset_input_t *subset_input); +HB_EXTERN hb_set_t * +hb_subset_input_nameid_set (hb_subset_input_t *subset_input); + +HB_EXTERN hb_set_t * +hb_subset_input_namelangid_set (hb_subset_input_t *subset_input); + +HB_EXTERN hb_set_t * +hb_subset_input_drop_tables_set (hb_subset_input_t *subset_input); + HB_EXTERN void hb_subset_input_set_drop_hints (hb_subset_input_t *subset_input, hb_bool_t drop_hints); @@ -61,16 +70,22 @@ HB_EXTERN hb_bool_t hb_subset_input_get_drop_hints (hb_subset_input_t *subset_input); HB_EXTERN void -hb_subset_input_set_drop_layout (hb_subset_input_t *subset_input, - hb_bool_t drop_layout); +hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, + hb_bool_t desubroutinize); HB_EXTERN hb_bool_t -hb_subset_input_get_drop_layout (hb_subset_input_t *subset_input); +hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input); HB_EXTERN void -hb_subset_input_set_desubroutinize (hb_subset_input_t *subset_input, - hb_bool_t desubroutinize); +hb_subset_input_set_retain_gids (hb_subset_input_t *subset_input, + hb_bool_t retain_gids); HB_EXTERN hb_bool_t -hb_subset_input_get_desubroutinize (hb_subset_input_t *subset_input); +hb_subset_input_get_retain_gids (hb_subset_input_t *subset_input); + +HB_EXTERN void +hb_subset_input_set_name_legacy (hb_subset_input_t *subset_input, + hb_bool_t name_legacy); +HB_EXTERN hb_bool_t +hb_subset_input_get_name_legacy (hb_subset_input_t *subset_input); /* hb_subset () */ HB_EXTERN hb_face_t * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-subset.hh b/src/java.desktop/share/native/libharfbuzz/hb-subset.hh index d4d72092257..dbbe45131d2 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-subset.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-subset.hh @@ -40,19 +40,33 @@ struct hb_subset_context_t : hb_dispatch_context_t { const char *get_name () { return "SUBSET"; } - template - bool dispatch (const T &obj) { return obj.subset (this); } - static bool default_return_value () { return true; } + static return_t default_return_value () { return true; } + private: + template auto + _dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN + ( obj.subset (this, hb_forward (ds)...) ) + template auto + _dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN + ( obj.dispatch (this, hb_forward (ds)...) ) + public: + template auto + dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN + ( _dispatch (obj, hb_prioritize, hb_forward (ds)...) ) + + hb_blob_t *source_blob; hb_subset_plan_t *plan; hb_serialize_context_t *serializer; - unsigned int debug_depth; + hb_tag_t table_tag; - hb_subset_context_t (hb_subset_plan_t *plan_, - hb_serialize_context_t *serializer_) : + hb_subset_context_t (hb_blob_t *source_blob_, + hb_subset_plan_t *plan_, + hb_serialize_context_t *serializer_, + hb_tag_t table_tag_) : + source_blob (source_blob_), plan (plan_), serializer (serializer_), - debug_depth (0) {} + table_tag (table_tag_) {} }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh new file mode 100644 index 00000000000..88623db3387 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ucd-table.hh @@ -0,0 +1,6780 @@ +/* == Start of generated table == */ +/* + * The following table is generated by running: + * + * ./gen-ucd-table.py ucd.nounihan.grouped.xml + * + * on file with this description: Unicode 13.0.0 + */ + +#ifndef HB_UCD_TABLE_HH +#define HB_UCD_TABLE_HH + +#include "hb.hh" + +static const hb_script_t +_hb_ucd_sc_map[157] = +{ + HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED, + HB_SCRIPT_UNKNOWN, HB_SCRIPT_ARABIC, + HB_SCRIPT_ARMENIAN, HB_SCRIPT_BENGALI, + HB_SCRIPT_CYRILLIC, HB_SCRIPT_DEVANAGARI, + HB_SCRIPT_GEORGIAN, HB_SCRIPT_GREEK, + HB_SCRIPT_GUJARATI, HB_SCRIPT_GURMUKHI, + HB_SCRIPT_HANGUL, HB_SCRIPT_HAN, + HB_SCRIPT_HEBREW, HB_SCRIPT_HIRAGANA, + HB_SCRIPT_KANNADA, HB_SCRIPT_KATAKANA, + HB_SCRIPT_LAO, HB_SCRIPT_LATIN, + HB_SCRIPT_MALAYALAM, HB_SCRIPT_ORIYA, + HB_SCRIPT_TAMIL, HB_SCRIPT_TELUGU, + HB_SCRIPT_THAI, HB_SCRIPT_TIBETAN, + HB_SCRIPT_BOPOMOFO, HB_SCRIPT_BRAILLE, + HB_SCRIPT_CANADIAN_SYLLABICS, HB_SCRIPT_CHEROKEE, + HB_SCRIPT_ETHIOPIC, HB_SCRIPT_KHMER, + HB_SCRIPT_MONGOLIAN, HB_SCRIPT_MYANMAR, + HB_SCRIPT_OGHAM, HB_SCRIPT_RUNIC, + HB_SCRIPT_SINHALA, HB_SCRIPT_SYRIAC, + HB_SCRIPT_THAANA, HB_SCRIPT_YI, + HB_SCRIPT_DESERET, HB_SCRIPT_GOTHIC, + HB_SCRIPT_OLD_ITALIC, HB_SCRIPT_BUHID, + HB_SCRIPT_HANUNOO, HB_SCRIPT_TAGALOG, + HB_SCRIPT_TAGBANWA, HB_SCRIPT_CYPRIOT, + HB_SCRIPT_LIMBU, HB_SCRIPT_LINEAR_B, + HB_SCRIPT_OSMANYA, HB_SCRIPT_SHAVIAN, + HB_SCRIPT_TAI_LE, HB_SCRIPT_UGARITIC, + HB_SCRIPT_BUGINESE, HB_SCRIPT_COPTIC, + HB_SCRIPT_GLAGOLITIC, HB_SCRIPT_KHAROSHTHI, + HB_SCRIPT_NEW_TAI_LUE, HB_SCRIPT_OLD_PERSIAN, + HB_SCRIPT_SYLOTI_NAGRI, HB_SCRIPT_TIFINAGH, + HB_SCRIPT_BALINESE, HB_SCRIPT_CUNEIFORM, + HB_SCRIPT_NKO, HB_SCRIPT_PHAGS_PA, + HB_SCRIPT_PHOENICIAN, HB_SCRIPT_CARIAN, + HB_SCRIPT_CHAM, HB_SCRIPT_KAYAH_LI, + HB_SCRIPT_LEPCHA, HB_SCRIPT_LYCIAN, + HB_SCRIPT_LYDIAN, HB_SCRIPT_OL_CHIKI, + HB_SCRIPT_REJANG, HB_SCRIPT_SAURASHTRA, + HB_SCRIPT_SUNDANESE, HB_SCRIPT_VAI, + HB_SCRIPT_AVESTAN, HB_SCRIPT_BAMUM, + HB_SCRIPT_EGYPTIAN_HIEROGLYPHS, HB_SCRIPT_IMPERIAL_ARAMAIC, + HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, + HB_SCRIPT_JAVANESE, HB_SCRIPT_KAITHI, + HB_SCRIPT_LISU, HB_SCRIPT_MEETEI_MAYEK, + HB_SCRIPT_OLD_SOUTH_ARABIAN, HB_SCRIPT_OLD_TURKIC, + HB_SCRIPT_SAMARITAN, HB_SCRIPT_TAI_THAM, + HB_SCRIPT_TAI_VIET, HB_SCRIPT_BATAK, + HB_SCRIPT_BRAHMI, HB_SCRIPT_MANDAIC, + HB_SCRIPT_CHAKMA, HB_SCRIPT_MEROITIC_CURSIVE, + HB_SCRIPT_MEROITIC_HIEROGLYPHS, HB_SCRIPT_MIAO, + HB_SCRIPT_SHARADA, HB_SCRIPT_SORA_SOMPENG, + HB_SCRIPT_TAKRI, HB_SCRIPT_BASSA_VAH, + HB_SCRIPT_CAUCASIAN_ALBANIAN, HB_SCRIPT_DUPLOYAN, + HB_SCRIPT_ELBASAN, HB_SCRIPT_GRANTHA, + HB_SCRIPT_KHOJKI, HB_SCRIPT_KHUDAWADI, + HB_SCRIPT_LINEAR_A, HB_SCRIPT_MAHAJANI, + HB_SCRIPT_MANICHAEAN, HB_SCRIPT_MENDE_KIKAKUI, + HB_SCRIPT_MODI, HB_SCRIPT_MRO, + HB_SCRIPT_NABATAEAN, HB_SCRIPT_OLD_NORTH_ARABIAN, + HB_SCRIPT_OLD_PERMIC, HB_SCRIPT_PAHAWH_HMONG, + HB_SCRIPT_PALMYRENE, HB_SCRIPT_PAU_CIN_HAU, + HB_SCRIPT_PSALTER_PAHLAVI, HB_SCRIPT_SIDDHAM, + HB_SCRIPT_TIRHUTA, HB_SCRIPT_WARANG_CITI, + HB_SCRIPT_AHOM, HB_SCRIPT_ANATOLIAN_HIEROGLYPHS, + HB_SCRIPT_HATRAN, HB_SCRIPT_MULTANI, + HB_SCRIPT_OLD_HUNGARIAN, HB_SCRIPT_SIGNWRITING, + HB_SCRIPT_ADLAM, HB_SCRIPT_BHAIKSUKI, + HB_SCRIPT_MARCHEN, HB_SCRIPT_OSAGE, + HB_SCRIPT_TANGUT, HB_SCRIPT_NEWA, + HB_SCRIPT_MASARAM_GONDI, HB_SCRIPT_NUSHU, + HB_SCRIPT_SOYOMBO, HB_SCRIPT_ZANABAZAR_SQUARE, + HB_SCRIPT_DOGRA, HB_SCRIPT_GUNJALA_GONDI, + HB_SCRIPT_HANIFI_ROHINGYA, HB_SCRIPT_MAKASAR, + HB_SCRIPT_MEDEFAIDRIN, HB_SCRIPT_OLD_SOGDIAN, + HB_SCRIPT_SOGDIAN, HB_SCRIPT_ELYMAIC, + HB_SCRIPT_NANDINAGARI, HB_SCRIPT_NYIAKENG_PUACHUE_HMONG, + HB_SCRIPT_WANCHO, HB_SCRIPT_CHORASMIAN, + HB_SCRIPT_DIVES_AKURU, HB_SCRIPT_KHITAN_SMALL_SCRIPT, + HB_SCRIPT_YEZIDI, +}; +static const uint16_t +_hb_ucd_dm1_p0_map[825] = +{ + 0x003Bu, 0x004Bu, 0x0060u, 0x00B4u, 0x00B7u, 0x00C5u, 0x02B9u, 0x0300u, + 0x0301u, 0x0313u, 0x0385u, 0x0386u, 0x0388u, 0x0389u, 0x038Au, 0x038Cu, + 0x038Eu, 0x038Fu, 0x0390u, 0x03A9u, 0x03ACu, 0x03ADu, 0x03AEu, 0x03AFu, + 0x03B0u, 0x03B9u, 0x03CCu, 0x03CDu, 0x03CEu, 0x2002u, 0x2003u, 0x3008u, + 0x3009u, 0x349Eu, 0x34B9u, 0x34BBu, 0x34DFu, 0x3515u, 0x36EEu, 0x36FCu, + 0x3781u, 0x382Fu, 0x3862u, 0x387Cu, 0x38C7u, 0x38E3u, 0x391Cu, 0x393Au, + 0x3A2Eu, 0x3A6Cu, 0x3AE4u, 0x3B08u, 0x3B19u, 0x3B49u, 0x3B9Du, 0x3C18u, + 0x3C4Eu, 0x3D33u, 0x3D96u, 0x3EACu, 0x3EB8u, 0x3F1Bu, 0x3FFCu, 0x4008u, + 0x4018u, 0x4039u, 0x4046u, 0x4096u, 0x40E3u, 0x412Fu, 0x4202u, 0x4227u, + 0x42A0u, 0x4301u, 0x4334u, 0x4359u, 0x43D5u, 0x43D9u, 0x440Bu, 0x446Bu, + 0x452Bu, 0x455Du, 0x4561u, 0x456Bu, 0x45D7u, 0x45F9u, 0x4635u, 0x46BEu, + 0x46C7u, 0x4995u, 0x49E6u, 0x4A6Eu, 0x4A76u, 0x4AB2u, 0x4B33u, 0x4BCEu, + 0x4CCEu, 0x4CEDu, 0x4CF8u, 0x4D56u, 0x4E0Du, 0x4E26u, 0x4E32u, 0x4E38u, + 0x4E39u, 0x4E3Du, 0x4E41u, 0x4E82u, 0x4E86u, 0x4EAEu, 0x4EC0u, 0x4ECCu, + 0x4EE4u, 0x4F60u, 0x4F80u, 0x4F86u, 0x4F8Bu, 0x4FAEu, 0x4FBBu, 0x4FBFu, + 0x5002u, 0x502Bu, 0x507Au, 0x5099u, 0x50CFu, 0x50DAu, 0x50E7u, 0x5140u, + 0x5145u, 0x514Du, 0x5154u, 0x5164u, 0x5167u, 0x5168u, 0x5169u, 0x516Du, + 0x5177u, 0x5180u, 0x518Du, 0x5192u, 0x5195u, 0x5197u, 0x51A4u, 0x51ACu, + 0x51B5u, 0x51B7u, 0x51C9u, 0x51CCu, 0x51DCu, 0x51DEu, 0x51F5u, 0x5203u, + 0x5207u, 0x5217u, 0x5229u, 0x523Au, 0x523Bu, 0x5246u, 0x5272u, 0x5277u, + 0x5289u, 0x529Bu, 0x52A3u, 0x52B3u, 0x52C7u, 0x52C9u, 0x52D2u, 0x52DEu, + 0x52E4u, 0x52F5u, 0x52FAu, 0x5305u, 0x5306u, 0x5317u, 0x533Fu, 0x5349u, + 0x5351u, 0x535Au, 0x5373u, 0x5375u, 0x537Du, 0x537Fu, 0x53C3u, 0x53CAu, + 0x53DFu, 0x53E5u, 0x53EBu, 0x53F1u, 0x5406u, 0x540Fu, 0x541Du, 0x5438u, + 0x5442u, 0x5448u, 0x5468u, 0x549Eu, 0x54A2u, 0x54BDu, 0x54F6u, 0x5510u, + 0x5553u, 0x5555u, 0x5563u, 0x5584u, 0x5587u, 0x5599u, 0x559Du, 0x55ABu, + 0x55B3u, 0x55C0u, 0x55C2u, 0x55E2u, 0x5606u, 0x5651u, 0x5668u, 0x5674u, + 0x56F9u, 0x5716u, 0x5717u, 0x578Bu, 0x57CEu, 0x57F4u, 0x580Du, 0x5831u, + 0x5832u, 0x5840u, 0x585Au, 0x585Eu, 0x58A8u, 0x58ACu, 0x58B3u, 0x58D8u, + 0x58DFu, 0x58EEu, 0x58F2u, 0x58F7u, 0x5906u, 0x591Au, 0x5922u, 0x5944u, + 0x5948u, 0x5951u, 0x5954u, 0x5962u, 0x5973u, 0x59D8u, 0x59ECu, 0x5A1Bu, + 0x5A27u, 0x5A62u, 0x5A66u, 0x5AB5u, 0x5B08u, 0x5B28u, 0x5B3Eu, 0x5B85u, + 0x5BC3u, 0x5BD8u, 0x5BE7u, 0x5BEEu, 0x5BF3u, 0x5BFFu, 0x5C06u, 0x5C22u, + 0x5C3Fu, 0x5C60u, 0x5C62u, 0x5C64u, 0x5C65u, 0x5C6Eu, 0x5C8Du, 0x5CC0u, + 0x5D19u, 0x5D43u, 0x5D50u, 0x5D6Bu, 0x5D6Eu, 0x5D7Cu, 0x5DB2u, 0x5DBAu, + 0x5DE1u, 0x5DE2u, 0x5DFDu, 0x5E28u, 0x5E3Du, 0x5E69u, 0x5E74u, 0x5EA6u, + 0x5EB0u, 0x5EB3u, 0x5EB6u, 0x5EC9u, 0x5ECAu, 0x5ED2u, 0x5ED3u, 0x5ED9u, + 0x5EECu, 0x5EFEu, 0x5F04u, 0x5F22u, 0x5F53u, 0x5F62u, 0x5F69u, 0x5F6Bu, + 0x5F8Bu, 0x5F9Au, 0x5FA9u, 0x5FADu, 0x5FCDu, 0x5FD7u, 0x5FF5u, 0x5FF9u, + 0x6012u, 0x601Cu, 0x6075u, 0x6081u, 0x6094u, 0x60C7u, 0x60D8u, 0x60E1u, + 0x6108u, 0x6144u, 0x6148u, 0x614Cu, 0x614Eu, 0x6160u, 0x6168u, 0x617Au, + 0x618Eu, 0x6190u, 0x61A4u, 0x61AFu, 0x61B2u, 0x61DEu, 0x61F2u, 0x61F6u, + 0x6200u, 0x6210u, 0x621Bu, 0x622Eu, 0x6234u, 0x625Du, 0x62B1u, 0x62C9u, + 0x62CFu, 0x62D3u, 0x62D4u, 0x62FCu, 0x62FEu, 0x633Du, 0x6350u, 0x6368u, + 0x637Bu, 0x6383u, 0x63A0u, 0x63A9u, 0x63C4u, 0x63C5u, 0x63E4u, 0x641Cu, + 0x6422u, 0x6452u, 0x6469u, 0x6477u, 0x647Eu, 0x649Au, 0x649Du, 0x64C4u, + 0x654Fu, 0x6556u, 0x656Cu, 0x6578u, 0x6599u, 0x65C5u, 0x65E2u, 0x65E3u, + 0x6613u, 0x6649u, 0x6674u, 0x6688u, 0x6691u, 0x669Cu, 0x66B4u, 0x66C6u, + 0x66F4u, 0x66F8u, 0x6700u, 0x6717u, 0x671Bu, 0x6721u, 0x674Eu, 0x6753u, + 0x6756u, 0x675Eu, 0x677Bu, 0x6785u, 0x6797u, 0x67F3u, 0x67FAu, 0x6817u, + 0x681Fu, 0x6852u, 0x6881u, 0x6885u, 0x688Eu, 0x68A8u, 0x6914u, 0x6942u, + 0x69A3u, 0x69EAu, 0x6A02u, 0x6A13u, 0x6AA8u, 0x6AD3u, 0x6ADBu, 0x6B04u, + 0x6B21u, 0x6B54u, 0x6B72u, 0x6B77u, 0x6B79u, 0x6B9Fu, 0x6BAEu, 0x6BBAu, + 0x6BBBu, 0x6C4Eu, 0x6C67u, 0x6C88u, 0x6CBFu, 0x6CCCu, 0x6CCDu, 0x6CE5u, + 0x6D16u, 0x6D1Bu, 0x6D1Eu, 0x6D34u, 0x6D3Eu, 0x6D41u, 0x6D69u, 0x6D6Au, + 0x6D77u, 0x6D78u, 0x6D85u, 0x6DCBu, 0x6DDAu, 0x6DEAu, 0x6DF9u, 0x6E1Au, + 0x6E2Fu, 0x6E6Eu, 0x6E9Cu, 0x6EBAu, 0x6EC7u, 0x6ECBu, 0x6ED1u, 0x6EDBu, + 0x6F0Fu, 0x6F22u, 0x6F23u, 0x6F6Eu, 0x6FC6u, 0x6FEBu, 0x6FFEu, 0x701Bu, + 0x701Eu, 0x7039u, 0x704Au, 0x7070u, 0x7077u, 0x707Du, 0x7099u, 0x70ADu, + 0x70C8u, 0x70D9u, 0x7145u, 0x7149u, 0x716Eu, 0x719Cu, 0x71CEu, 0x71D0u, + 0x7210u, 0x721Bu, 0x7228u, 0x722Bu, 0x7235u, 0x7250u, 0x7262u, 0x7280u, + 0x7295u, 0x72AFu, 0x72C0u, 0x72FCu, 0x732Au, 0x7375u, 0x737Au, 0x7387u, + 0x738Bu, 0x73A5u, 0x73B2u, 0x73DEu, 0x7406u, 0x7409u, 0x7422u, 0x7447u, + 0x745Cu, 0x7469u, 0x7471u, 0x7485u, 0x7489u, 0x7498u, 0x74CAu, 0x7506u, + 0x7524u, 0x753Bu, 0x753Eu, 0x7559u, 0x7565u, 0x7570u, 0x75E2u, 0x7610u, + 0x761Du, 0x761Fu, 0x7642u, 0x7669u, 0x76CAu, 0x76DBu, 0x76E7u, 0x76F4u, + 0x7701u, 0x771Eu, 0x771Fu, 0x7740u, 0x774Au, 0x778Bu, 0x77A7u, 0x784Eu, + 0x786Bu, 0x788Cu, 0x7891u, 0x78CAu, 0x78CCu, 0x78FBu, 0x792Au, 0x793Cu, + 0x793Eu, 0x7948u, 0x7949u, 0x7950u, 0x7956u, 0x795Du, 0x795Eu, 0x7965u, + 0x797Fu, 0x798Du, 0x798Eu, 0x798Fu, 0x79AEu, 0x79CAu, 0x79EBu, 0x7A1Cu, + 0x7A40u, 0x7A4Au, 0x7A4Fu, 0x7A81u, 0x7AB1u, 0x7ACBu, 0x7AEEu, 0x7B20u, + 0x7BC0u, 0x7BC6u, 0x7BC9u, 0x7C3Eu, 0x7C60u, 0x7C7Bu, 0x7C92u, 0x7CBEu, + 0x7CD2u, 0x7CD6u, 0x7CE3u, 0x7CE7u, 0x7CE8u, 0x7D00u, 0x7D10u, 0x7D22u, + 0x7D2Fu, 0x7D5Bu, 0x7D63u, 0x7DA0u, 0x7DBEu, 0x7DC7u, 0x7DF4u, 0x7E02u, + 0x7E09u, 0x7E37u, 0x7E41u, 0x7E45u, 0x7F3Eu, 0x7F72u, 0x7F79u, 0x7F7Au, + 0x7F85u, 0x7F95u, 0x7F9Au, 0x7FBDu, 0x7FFAu, 0x8001u, 0x8005u, 0x8046u, + 0x8060u, 0x806Fu, 0x8070u, 0x807Eu, 0x808Bu, 0x80ADu, 0x80B2u, 0x8103u, + 0x813Eu, 0x81D8u, 0x81E8u, 0x81EDu, 0x8201u, 0x8204u, 0x8218u, 0x826Fu, + 0x8279u, 0x828Bu, 0x8291u, 0x829Du, 0x82B1u, 0x82B3u, 0x82BDu, 0x82E5u, + 0x82E6u, 0x831Du, 0x8323u, 0x8336u, 0x8352u, 0x8353u, 0x8363u, 0x83ADu, + 0x83BDu, 0x83C9u, 0x83CAu, 0x83CCu, 0x83DCu, 0x83E7u, 0x83EFu, 0x83F1u, + 0x843Du, 0x8449u, 0x8457u, 0x84EEu, 0x84F1u, 0x84F3u, 0x84FCu, 0x8516u, + 0x8564u, 0x85CDu, 0x85FAu, 0x8606u, 0x8612u, 0x862Du, 0x863Fu, 0x8650u, + 0x865Cu, 0x8667u, 0x8669u, 0x8688u, 0x86A9u, 0x86E2u, 0x870Eu, 0x8728u, + 0x876Bu, 0x8779u, 0x8786u, 0x87BAu, 0x87E1u, 0x8801u, 0x881Fu, 0x884Cu, + 0x8860u, 0x8863u, 0x88C2u, 0x88CFu, 0x88D7u, 0x88DEu, 0x88E1u, 0x88F8u, + 0x88FAu, 0x8910u, 0x8941u, 0x8964u, 0x8986u, 0x898Bu, 0x8996u, 0x8AA0u, + 0x8AAAu, 0x8ABFu, 0x8ACBu, 0x8AD2u, 0x8AD6u, 0x8AEDu, 0x8AF8u, 0x8AFEu, + 0x8B01u, 0x8B39u, 0x8B58u, 0x8B80u, 0x8B8Au, 0x8C48u, 0x8C55u, 0x8CABu, + 0x8CC1u, 0x8CC2u, 0x8CC8u, 0x8CD3u, 0x8D08u, 0x8D1Bu, 0x8D77u, 0x8DBCu, + 0x8DCBu, 0x8DEFu, 0x8DF0u, 0x8ECAu, 0x8ED4u, 0x8F26u, 0x8F2Au, 0x8F38u, + 0x8F3Bu, 0x8F62u, 0x8F9Eu, 0x8FB0u, 0x8FB6u, 0x9023u, 0x9038u, 0x9072u, + 0x907Cu, 0x908Fu, 0x9094u, 0x90CEu, 0x90DEu, 0x90F1u, 0x90FDu, 0x9111u, + 0x911Bu, 0x916Au, 0x9199u, 0x91B4u, 0x91CCu, 0x91CFu, 0x91D1u, 0x9234u, + 0x9238u, 0x9276u, 0x927Cu, 0x92D7u, 0x92D8u, 0x9304u, 0x934Au, 0x93F9u, + 0x9415u, 0x958Bu, 0x95ADu, 0x95B7u, 0x962Eu, 0x964Bu, 0x964Du, 0x9675u, + 0x9678u, 0x967Cu, 0x9686u, 0x96A3u, 0x96B7u, 0x96B8u, 0x96C3u, 0x96E2u, + 0x96E3u, 0x96F6u, 0x96F7u, 0x9723u, 0x9732u, 0x9748u, 0x9756u, 0x97DBu, + 0x97E0u, 0x97FFu, 0x980Bu, 0x9818u, 0x9829u, 0x983Bu, 0x985Eu, 0x98E2u, + 0x98EFu, 0x98FCu, 0x9928u, 0x9929u, 0x99A7u, 0x99C2u, 0x99F1u, 0x99FEu, + 0x9A6Au, 0x9B12u, 0x9B6Fu, 0x9C40u, 0x9C57u, 0x9CFDu, 0x9D67u, 0x9DB4u, + 0x9DFAu, 0x9E1Eu, 0x9E7Fu, 0x9E97u, 0x9E9Fu, 0x9EBBu, 0x9ECEu, 0x9EF9u, + 0x9EFEu, 0x9F05u, 0x9F0Fu, 0x9F16u, 0x9F3Bu, 0x9F43u, 0x9F8Du, 0x9F8Eu, + 0x9F9Cu, +}; +static const uint16_t +_hb_ucd_dm1_p2_map[110] = +{ + 0x0122u, 0x051Cu, 0x0525u, 0x054Bu, 0x063Au, 0x0804u, 0x08DEu, 0x0A2Cu, + 0x0B63u, 0x14E4u, 0x16A8u, 0x16EAu, 0x19C8u, 0x1B18u, 0x1D0Bu, 0x1DE4u, + 0x1DE6u, 0x2183u, 0x219Fu, 0x2331u, 0x26D4u, 0x2844u, 0x284Au, 0x2B0Cu, + 0x2BF1u, 0x300Au, 0x32B8u, 0x335Fu, 0x3393u, 0x339Cu, 0x33C3u, 0x33D5u, + 0x346Du, 0x36A3u, 0x38A7u, 0x3A8Du, 0x3AFAu, 0x3CBCu, 0x3D1Eu, 0x3ED1u, + 0x3F5Eu, 0x3F8Eu, 0x4263u, 0x42EEu, 0x43ABu, 0x4608u, 0x4735u, 0x4814u, + 0x4C36u, 0x4C92u, 0x4FA1u, 0x4FB8u, 0x5044u, 0x50F2u, 0x50F3u, 0x5119u, + 0x5133u, 0x5249u, 0x541Du, 0x5626u, 0x569Au, 0x56C5u, 0x597Cu, 0x5AA7u, + 0x5BABu, 0x5C80u, 0x5CD0u, 0x5F86u, 0x61DAu, 0x6228u, 0x6247u, 0x62D9u, + 0x633Eu, 0x64DAu, 0x6523u, 0x65A8u, 0x67A7u, 0x67B5u, 0x6B3Cu, 0x6C36u, + 0x6CD5u, 0x6D6Bu, 0x6F2Cu, 0x6FB1u, 0x70D2u, 0x73CAu, 0x7667u, 0x78AEu, + 0x7966u, 0x7CA8u, 0x7ED3u, 0x7F2Fu, 0x85D2u, 0x85EDu, 0x872Eu, 0x8BFAu, + 0x8D77u, 0x9145u, 0x91DFu, 0x921Au, 0x940Au, 0x9496u, 0x95B6u, 0x9B30u, + 0xA0CEu, 0xA105u, 0xA20Eu, 0xA291u, 0xA392u, 0xA600u, +}; +static const uint32_t +_hb_ucd_dm2_u32_map[638] = +{ + HB_CODEPOINT_ENCODE3_11_7_14 (0x003Cu, 0x0338u, 0x226Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x003Du, 0x0338u, 0x2260u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x003Eu, 0x0338u, 0x226Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0300u, 0x00C0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0301u, 0x00C1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0302u, 0x00C2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0303u, 0x00C3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0304u, 0x0100u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0306u, 0x0102u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0307u, 0x0226u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0308u, 0x00C4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0309u, 0x1EA2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Au, 0x00C5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Cu, 0x01CDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x030Fu, 0x0200u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0311u, 0x0202u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0323u, 0x1EA0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0325u, 0x1E00u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0041u, 0x0328u, 0x0104u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0307u, 0x1E02u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0323u, 0x1E04u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0042u, 0x0331u, 0x1E06u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0301u, 0x0106u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0302u, 0x0108u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0307u, 0x010Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x030Cu, 0x010Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0043u, 0x0327u, 0x00C7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0307u, 0x1E0Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x030Cu, 0x010Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0323u, 0x1E0Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0327u, 0x1E10u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x032Du, 0x1E12u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0044u, 0x0331u, 0x1E0Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0300u, 0x00C8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0301u, 0x00C9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0302u, 0x00CAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0303u, 0x1EBCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0304u, 0x0112u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0306u, 0x0114u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0307u, 0x0116u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0308u, 0x00CBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0309u, 0x1EBAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x030Cu, 0x011Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x030Fu, 0x0204u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0311u, 0x0206u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0323u, 0x1EB8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0327u, 0x0228u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0328u, 0x0118u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x032Du, 0x1E18u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0045u, 0x0330u, 0x1E1Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0046u, 0x0307u, 0x1E1Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0301u, 0x01F4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0302u, 0x011Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0304u, 0x1E20u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0306u, 0x011Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0307u, 0x0120u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x030Cu, 0x01E6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0047u, 0x0327u, 0x0122u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0302u, 0x0124u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0307u, 0x1E22u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0308u, 0x1E26u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x030Cu, 0x021Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0323u, 0x1E24u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x0327u, 0x1E28u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0048u, 0x032Eu, 0x1E2Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0300u, 0x00CCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0301u, 0x00CDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0302u, 0x00CEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0303u, 0x0128u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0304u, 0x012Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0306u, 0x012Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0307u, 0x0130u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0308u, 0x00CFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0309u, 0x1EC8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x030Cu, 0x01CFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x030Fu, 0x0208u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0311u, 0x020Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0323u, 0x1ECAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0328u, 0x012Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0049u, 0x0330u, 0x1E2Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Au, 0x0302u, 0x0134u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0301u, 0x1E30u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x030Cu, 0x01E8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0323u, 0x1E32u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0327u, 0x0136u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Bu, 0x0331u, 0x1E34u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0301u, 0x0139u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x030Cu, 0x013Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0323u, 0x1E36u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0327u, 0x013Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x032Du, 0x1E3Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Cu, 0x0331u, 0x1E3Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0301u, 0x1E3Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0307u, 0x1E40u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Du, 0x0323u, 0x1E42u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0300u, 0x01F8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0301u, 0x0143u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0303u, 0x00D1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0307u, 0x1E44u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x030Cu, 0x0147u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0323u, 0x1E46u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0327u, 0x0145u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x032Du, 0x1E4Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Eu, 0x0331u, 0x1E48u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0300u, 0x00D2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0301u, 0x00D3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0302u, 0x00D4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0303u, 0x00D5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0304u, 0x014Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0306u, 0x014Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0307u, 0x022Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0308u, 0x00D6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0309u, 0x1ECEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Bu, 0x0150u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Cu, 0x01D1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x030Fu, 0x020Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0311u, 0x020Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x031Bu, 0x01A0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0323u, 0x1ECCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x004Fu, 0x0328u, 0x01EAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0050u, 0x0301u, 0x1E54u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0050u, 0x0307u, 0x1E56u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0301u, 0x0154u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0307u, 0x1E58u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x030Cu, 0x0158u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x030Fu, 0x0210u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0311u, 0x0212u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0323u, 0x1E5Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0327u, 0x0156u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0052u, 0x0331u, 0x1E5Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0301u, 0x015Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0302u, 0x015Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0307u, 0x1E60u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x030Cu, 0x0160u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0323u, 0x1E62u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0326u, 0x0218u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0053u, 0x0327u, 0x015Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0307u, 0x1E6Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x030Cu, 0x0164u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0323u, 0x1E6Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0326u, 0x021Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0327u, 0x0162u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x032Du, 0x1E70u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0054u, 0x0331u, 0x1E6Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0300u, 0x00D9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0301u, 0x00DAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0302u, 0x00DBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0303u, 0x0168u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0304u, 0x016Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0306u, 0x016Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0308u, 0x00DCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0309u, 0x1EE6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Au, 0x016Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Bu, 0x0170u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Cu, 0x01D3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x030Fu, 0x0214u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0311u, 0x0216u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x031Bu, 0x01AFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0323u, 0x1EE4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0324u, 0x1E72u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0328u, 0x0172u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x032Du, 0x1E76u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0055u, 0x0330u, 0x1E74u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0056u, 0x0303u, 0x1E7Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0056u, 0x0323u, 0x1E7Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0300u, 0x1E80u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0301u, 0x1E82u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0302u, 0x0174u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0307u, 0x1E86u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0308u, 0x1E84u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0057u, 0x0323u, 0x1E88u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0058u, 0x0307u, 0x1E8Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0058u, 0x0308u, 0x1E8Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0300u, 0x1EF2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0301u, 0x00DDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0302u, 0x0176u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0303u, 0x1EF8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0304u, 0x0232u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0307u, 0x1E8Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0308u, 0x0178u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0309u, 0x1EF6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0059u, 0x0323u, 0x1EF4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0301u, 0x0179u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0302u, 0x1E90u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0307u, 0x017Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x030Cu, 0x017Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0323u, 0x1E92u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x005Au, 0x0331u, 0x1E94u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0300u, 0x00E0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0301u, 0x00E1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0302u, 0x00E2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0303u, 0x00E3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0304u, 0x0101u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0306u, 0x0103u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0307u, 0x0227u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0308u, 0x00E4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0309u, 0x1EA3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Au, 0x00E5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Cu, 0x01CEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x030Fu, 0x0201u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0311u, 0x0203u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0323u, 0x1EA1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0325u, 0x1E01u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0061u, 0x0328u, 0x0105u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0307u, 0x1E03u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0323u, 0x1E05u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0062u, 0x0331u, 0x1E07u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0301u, 0x0107u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0302u, 0x0109u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0307u, 0x010Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x030Cu, 0x010Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0063u, 0x0327u, 0x00E7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0307u, 0x1E0Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x030Cu, 0x010Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0323u, 0x1E0Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0327u, 0x1E11u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x032Du, 0x1E13u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0064u, 0x0331u, 0x1E0Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0300u, 0x00E8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0301u, 0x00E9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0302u, 0x00EAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0303u, 0x1EBDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0304u, 0x0113u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0306u, 0x0115u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0307u, 0x0117u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0308u, 0x00EBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0309u, 0x1EBBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x030Cu, 0x011Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x030Fu, 0x0205u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0311u, 0x0207u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0323u, 0x1EB9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0327u, 0x0229u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0328u, 0x0119u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x032Du, 0x1E19u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0065u, 0x0330u, 0x1E1Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0066u, 0x0307u, 0x1E1Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0301u, 0x01F5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0302u, 0x011Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0304u, 0x1E21u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0306u, 0x011Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0307u, 0x0121u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x030Cu, 0x01E7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0067u, 0x0327u, 0x0123u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0302u, 0x0125u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0307u, 0x1E23u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0308u, 0x1E27u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x030Cu, 0x021Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0323u, 0x1E25u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0327u, 0x1E29u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x032Eu, 0x1E2Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0068u, 0x0331u, 0x1E96u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0300u, 0x00ECu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0301u, 0x00EDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0302u, 0x00EEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0303u, 0x0129u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0304u, 0x012Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0306u, 0x012Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0308u, 0x00EFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0309u, 0x1EC9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x030Cu, 0x01D0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x030Fu, 0x0209u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0311u, 0x020Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0323u, 0x1ECBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0328u, 0x012Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0069u, 0x0330u, 0x1E2Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Au, 0x0302u, 0x0135u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Au, 0x030Cu, 0x01F0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0301u, 0x1E31u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x030Cu, 0x01E9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0323u, 0x1E33u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0327u, 0x0137u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Bu, 0x0331u, 0x1E35u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0301u, 0x013Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x030Cu, 0x013Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0323u, 0x1E37u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0327u, 0x013Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x032Du, 0x1E3Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Cu, 0x0331u, 0x1E3Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0301u, 0x1E3Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0307u, 0x1E41u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Du, 0x0323u, 0x1E43u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0300u, 0x01F9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0301u, 0x0144u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0303u, 0x00F1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0307u, 0x1E45u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x030Cu, 0x0148u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0323u, 0x1E47u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0327u, 0x0146u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x032Du, 0x1E4Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Eu, 0x0331u, 0x1E49u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0300u, 0x00F2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0301u, 0x00F3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0302u, 0x00F4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0303u, 0x00F5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0304u, 0x014Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0306u, 0x014Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0307u, 0x022Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0308u, 0x00F6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0309u, 0x1ECFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Bu, 0x0151u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Cu, 0x01D2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x030Fu, 0x020Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0311u, 0x020Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x031Bu, 0x01A1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0323u, 0x1ECDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x006Fu, 0x0328u, 0x01EBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0070u, 0x0301u, 0x1E55u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0070u, 0x0307u, 0x1E57u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0301u, 0x0155u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0307u, 0x1E59u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x030Cu, 0x0159u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x030Fu, 0x0211u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0311u, 0x0213u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0323u, 0x1E5Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0327u, 0x0157u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0072u, 0x0331u, 0x1E5Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0301u, 0x015Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0302u, 0x015Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0307u, 0x1E61u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x030Cu, 0x0161u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0323u, 0x1E63u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0326u, 0x0219u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0073u, 0x0327u, 0x015Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0307u, 0x1E6Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0308u, 0x1E97u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x030Cu, 0x0165u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0323u, 0x1E6Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0326u, 0x021Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0327u, 0x0163u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x032Du, 0x1E71u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0074u, 0x0331u, 0x1E6Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0300u, 0x00F9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0301u, 0x00FAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0302u, 0x00FBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0303u, 0x0169u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0304u, 0x016Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0306u, 0x016Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0308u, 0x00FCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0309u, 0x1EE7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Au, 0x016Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Bu, 0x0171u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Cu, 0x01D4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x030Fu, 0x0215u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0311u, 0x0217u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x031Bu, 0x01B0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0323u, 0x1EE5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0324u, 0x1E73u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0328u, 0x0173u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x032Du, 0x1E77u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0075u, 0x0330u, 0x1E75u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0076u, 0x0303u, 0x1E7Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0076u, 0x0323u, 0x1E7Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0300u, 0x1E81u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0301u, 0x1E83u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0302u, 0x0175u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0307u, 0x1E87u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0308u, 0x1E85u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x030Au, 0x1E98u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0077u, 0x0323u, 0x1E89u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0078u, 0x0307u, 0x1E8Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0078u, 0x0308u, 0x1E8Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0300u, 0x1EF3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0301u, 0x00FDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0302u, 0x0177u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0303u, 0x1EF9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0304u, 0x0233u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0307u, 0x1E8Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0308u, 0x00FFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0309u, 0x1EF7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x030Au, 0x1E99u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0079u, 0x0323u, 0x1EF5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0301u, 0x017Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0302u, 0x1E91u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0307u, 0x017Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x030Cu, 0x017Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0323u, 0x1E93u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x007Au, 0x0331u, 0x1E95u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0300u, 0x1FEDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0301u, 0x0385u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00A8u, 0x0342u, 0x1FC1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0300u, 0x1EA6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0301u, 0x1EA4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0303u, 0x1EAAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C2u, 0x0309u, 0x1EA8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C4u, 0x0304u, 0x01DEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C5u, 0x0301u, 0x01FAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6u, 0x0301u, 0x01FCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C6u, 0x0304u, 0x01E2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00C7u, 0x0301u, 0x1E08u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0300u, 0x1EC0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0301u, 0x1EBEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0303u, 0x1EC4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00CAu, 0x0309u, 0x1EC2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00CFu, 0x0301u, 0x1E2Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0300u, 0x1ED2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0301u, 0x1ED0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0303u, 0x1ED6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D4u, 0x0309u, 0x1ED4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0301u, 0x1E4Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0304u, 0x022Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D5u, 0x0308u, 0x1E4Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D6u, 0x0304u, 0x022Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00D8u, 0x0301u, 0x01FEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0300u, 0x01DBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0301u, 0x01D7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x0304u, 0x01D5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00DCu, 0x030Cu, 0x01D9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0300u, 0x1EA7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0301u, 0x1EA5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0303u, 0x1EABu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E2u, 0x0309u, 0x1EA9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E4u, 0x0304u, 0x01DFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E5u, 0x0301u, 0x01FBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6u, 0x0301u, 0x01FDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E6u, 0x0304u, 0x01E3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00E7u, 0x0301u, 0x1E09u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0300u, 0x1EC1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0301u, 0x1EBFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0303u, 0x1EC5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00EAu, 0x0309u, 0x1EC3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00EFu, 0x0301u, 0x1E2Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0300u, 0x1ED3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0301u, 0x1ED1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0303u, 0x1ED7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F4u, 0x0309u, 0x1ED5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0301u, 0x1E4Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0304u, 0x022Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F5u, 0x0308u, 0x1E4Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F6u, 0x0304u, 0x022Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00F8u, 0x0301u, 0x01FFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0300u, 0x01DCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0301u, 0x01D8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x0304u, 0x01D6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x00FCu, 0x030Cu, 0x01DAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0300u, 0x1EB0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0301u, 0x1EAEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0303u, 0x1EB4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0102u, 0x0309u, 0x1EB2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0300u, 0x1EB1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0301u, 0x1EAFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0303u, 0x1EB5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0103u, 0x0309u, 0x1EB3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0112u, 0x0300u, 0x1E14u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0112u, 0x0301u, 0x1E16u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0113u, 0x0300u, 0x1E15u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0113u, 0x0301u, 0x1E17u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x014Cu, 0x0300u, 0x1E50u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x014Cu, 0x0301u, 0x1E52u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x014Du, 0x0300u, 0x1E51u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x014Du, 0x0301u, 0x1E53u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x015Au, 0x0307u, 0x1E64u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x015Bu, 0x0307u, 0x1E65u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0160u, 0x0307u, 0x1E66u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0161u, 0x0307u, 0x1E67u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0168u, 0x0301u, 0x1E78u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0169u, 0x0301u, 0x1E79u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x016Au, 0x0308u, 0x1E7Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x016Bu, 0x0308u, 0x1E7Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x017Fu, 0x0307u, 0x1E9Bu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0300u, 0x1EDCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0301u, 0x1EDAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0303u, 0x1EE0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0309u, 0x1EDEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A0u, 0x0323u, 0x1EE2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0300u, 0x1EDDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0301u, 0x1EDBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0303u, 0x1EE1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0309u, 0x1EDFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01A1u, 0x0323u, 0x1EE3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0300u, 0x1EEAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0301u, 0x1EE8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0303u, 0x1EEEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0309u, 0x1EECu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01AFu, 0x0323u, 0x1EF0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0300u, 0x1EEBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0301u, 0x1EE9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0303u, 0x1EEFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0309u, 0x1EEDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01B0u, 0x0323u, 0x1EF1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01B7u, 0x030Cu, 0x01EEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01EAu, 0x0304u, 0x01ECu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x01EBu, 0x0304u, 0x01EDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0226u, 0x0304u, 0x01E0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0227u, 0x0304u, 0x01E1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0228u, 0x0306u, 0x1E1Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0229u, 0x0306u, 0x1E1Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x022Eu, 0x0304u, 0x0230u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x022Fu, 0x0304u, 0x0231u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0292u, 0x030Cu, 0x01EFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0308u, 0x0301u, 0x0000u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0300u, 0x1FBAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0301u, 0x0386u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0304u, 0x1FB9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0306u, 0x1FB8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0313u, 0x1F08u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0314u, 0x1F09u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0391u, 0x0345u, 0x1FBCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0300u, 0x1FC8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0301u, 0x0388u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0313u, 0x1F18u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0395u, 0x0314u, 0x1F19u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0300u, 0x1FCAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0301u, 0x0389u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0313u, 0x1F28u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0314u, 0x1F29u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0397u, 0x0345u, 0x1FCCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0300u, 0x1FDAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0301u, 0x038Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0304u, 0x1FD9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0306u, 0x1FD8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0308u, 0x03AAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0313u, 0x1F38u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0399u, 0x0314u, 0x1F39u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0300u, 0x1FF8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0301u, 0x038Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0313u, 0x1F48u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x039Fu, 0x0314u, 0x1F49u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A1u, 0x0314u, 0x1FECu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0300u, 0x1FEAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0301u, 0x038Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0304u, 0x1FE9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0306u, 0x1FE8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0308u, 0x03ABu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A5u, 0x0314u, 0x1F59u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0300u, 0x1FFAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0301u, 0x038Fu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0313u, 0x1F68u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0314u, 0x1F69u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03A9u, 0x0345u, 0x1FFCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03ACu, 0x0345u, 0x1FB4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03AEu, 0x0345u, 0x1FC4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0300u, 0x1F70u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0301u, 0x03ACu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0304u, 0x1FB1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0306u, 0x1FB0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0313u, 0x1F00u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0314u, 0x1F01u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0342u, 0x1FB6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B1u, 0x0345u, 0x1FB3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0300u, 0x1F72u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0301u, 0x03ADu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0313u, 0x1F10u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B5u, 0x0314u, 0x1F11u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0300u, 0x1F74u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0301u, 0x03AEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0313u, 0x1F20u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0314u, 0x1F21u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0342u, 0x1FC6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B7u, 0x0345u, 0x1FC3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0300u, 0x1F76u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0301u, 0x03AFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0304u, 0x1FD1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0306u, 0x1FD0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0308u, 0x03CAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0313u, 0x1F30u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0314u, 0x1F31u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03B9u, 0x0342u, 0x1FD6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0300u, 0x1F78u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0301u, 0x03CCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0313u, 0x1F40u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03BFu, 0x0314u, 0x1F41u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1u, 0x0313u, 0x1FE4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C1u, 0x0314u, 0x1FE5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0300u, 0x1F7Au), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0301u, 0x03CDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0304u, 0x1FE1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0306u, 0x1FE0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0308u, 0x03CBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0313u, 0x1F50u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0314u, 0x1F51u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C5u, 0x0342u, 0x1FE6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0300u, 0x1F7Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0301u, 0x03CEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0313u, 0x1F60u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0314u, 0x1F61u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0342u, 0x1FF6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03C9u, 0x0345u, 0x1FF3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0300u, 0x1FD2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0301u, 0x0390u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CAu, 0x0342u, 0x1FD7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0300u, 0x1FE2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0301u, 0x03B0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CBu, 0x0342u, 0x1FE7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03CEu, 0x0345u, 0x1FF4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2u, 0x0301u, 0x03D3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x03D2u, 0x0308u, 0x03D4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0406u, 0x0308u, 0x0407u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0410u, 0x0306u, 0x04D0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0410u, 0x0308u, 0x04D2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0413u, 0x0301u, 0x0403u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0300u, 0x0400u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0306u, 0x04D6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0415u, 0x0308u, 0x0401u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0416u, 0x0306u, 0x04C1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0416u, 0x0308u, 0x04DCu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0417u, 0x0308u, 0x04DEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0300u, 0x040Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0304u, 0x04E2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0306u, 0x0419u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0418u, 0x0308u, 0x04E4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x041Au, 0x0301u, 0x040Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x041Eu, 0x0308u, 0x04E6u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0304u, 0x04EEu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0306u, 0x040Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x0308u, 0x04F0u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0423u, 0x030Bu, 0x04F2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0427u, 0x0308u, 0x04F4u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x042Bu, 0x0308u, 0x04F8u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x042Du, 0x0308u, 0x04ECu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0430u, 0x0306u, 0x04D1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0430u, 0x0308u, 0x04D3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0433u, 0x0301u, 0x0453u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0300u, 0x0450u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0306u, 0x04D7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0435u, 0x0308u, 0x0451u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0436u, 0x0306u, 0x04C2u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0436u, 0x0308u, 0x04DDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0437u, 0x0308u, 0x04DFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0300u, 0x045Du), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0304u, 0x04E3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0306u, 0x0439u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0438u, 0x0308u, 0x04E5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x043Au, 0x0301u, 0x045Cu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x043Eu, 0x0308u, 0x04E7u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0304u, 0x04EFu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0306u, 0x045Eu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x0308u, 0x04F1u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0443u, 0x030Bu, 0x04F3u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0447u, 0x0308u, 0x04F5u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x044Bu, 0x0308u, 0x04F9u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x044Du, 0x0308u, 0x04EDu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0456u, 0x0308u, 0x0457u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0474u, 0x030Fu, 0x0476u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x0475u, 0x030Fu, 0x0477u), + HB_CODEPOINT_ENCODE3_11_7_14 (0x04D8u, 0x0308u, 0x04DAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x04D9u, 0x0308u, 0x04DBu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x04E8u, 0x0308u, 0x04EAu), + HB_CODEPOINT_ENCODE3_11_7_14 (0x04E9u, 0x0308u, 0x04EBu), +}; +static const uint64_t +_hb_ucd_dm2_u64_map[388] = +{ + HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05B8u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05D0u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05D1u, 0x05BFu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D2u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05D3u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D4u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05D5u, 0x05B9u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D5u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05D6u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D8u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05D9u, 0x05B4u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05D9u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05DAu, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05DBu, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05DBu, 0x05BFu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05DCu, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05DEu, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E0u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05E1u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E3u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05E4u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E4u, 0x05BFu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05E6u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E7u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05E8u, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05C1u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05E9u, 0x05C2u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x05EAu, 0x05BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x05F2u, 0x05B7u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0627u, 0x0653u, 0x0622u), HB_CODEPOINT_ENCODE3 (0x0627u, 0x0654u, 0x0623u), + HB_CODEPOINT_ENCODE3 (0x0627u, 0x0655u, 0x0625u), HB_CODEPOINT_ENCODE3 (0x0648u, 0x0654u, 0x0624u), + HB_CODEPOINT_ENCODE3 (0x064Au, 0x0654u, 0x0626u), HB_CODEPOINT_ENCODE3 (0x06C1u, 0x0654u, 0x06C2u), + HB_CODEPOINT_ENCODE3 (0x06D2u, 0x0654u, 0x06D3u), HB_CODEPOINT_ENCODE3 (0x06D5u, 0x0654u, 0x06C0u), + HB_CODEPOINT_ENCODE3 (0x0915u, 0x093Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0916u, 0x093Cu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0917u, 0x093Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x091Cu, 0x093Cu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0921u, 0x093Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0922u, 0x093Cu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0928u, 0x093Cu, 0x0929u), HB_CODEPOINT_ENCODE3 (0x092Bu, 0x093Cu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x092Fu, 0x093Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0930u, 0x093Cu, 0x0931u), + HB_CODEPOINT_ENCODE3 (0x0933u, 0x093Cu, 0x0934u), HB_CODEPOINT_ENCODE3 (0x09A1u, 0x09BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x09A2u, 0x09BCu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x09AFu, 0x09BCu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x09C7u, 0x09BEu, 0x09CBu), HB_CODEPOINT_ENCODE3 (0x09C7u, 0x09D7u, 0x09CCu), + HB_CODEPOINT_ENCODE3 (0x0A16u, 0x0A3Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0A17u, 0x0A3Cu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0A1Cu, 0x0A3Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0A2Bu, 0x0A3Cu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0A32u, 0x0A3Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0A38u, 0x0A3Cu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0B21u, 0x0B3Cu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0B22u, 0x0B3Cu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B3Eu, 0x0B4Bu), HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B56u, 0x0B48u), + HB_CODEPOINT_ENCODE3 (0x0B47u, 0x0B57u, 0x0B4Cu), HB_CODEPOINT_ENCODE3 (0x0B92u, 0x0BD7u, 0x0B94u), + HB_CODEPOINT_ENCODE3 (0x0BC6u, 0x0BBEu, 0x0BCAu), HB_CODEPOINT_ENCODE3 (0x0BC6u, 0x0BD7u, 0x0BCCu), + HB_CODEPOINT_ENCODE3 (0x0BC7u, 0x0BBEu, 0x0BCBu), HB_CODEPOINT_ENCODE3 (0x0C46u, 0x0C56u, 0x0C48u), + HB_CODEPOINT_ENCODE3 (0x0CBFu, 0x0CD5u, 0x0CC0u), HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CC2u, 0x0CCAu), + HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CD5u, 0x0CC7u), HB_CODEPOINT_ENCODE3 (0x0CC6u, 0x0CD6u, 0x0CC8u), + HB_CODEPOINT_ENCODE3 (0x0CCAu, 0x0CD5u, 0x0CCBu), HB_CODEPOINT_ENCODE3 (0x0D46u, 0x0D3Eu, 0x0D4Au), + HB_CODEPOINT_ENCODE3 (0x0D46u, 0x0D57u, 0x0D4Cu), HB_CODEPOINT_ENCODE3 (0x0D47u, 0x0D3Eu, 0x0D4Bu), + HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DCAu, 0x0DDAu), HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DCFu, 0x0DDCu), + HB_CODEPOINT_ENCODE3 (0x0DD9u, 0x0DDFu, 0x0DDEu), HB_CODEPOINT_ENCODE3 (0x0DDCu, 0x0DCAu, 0x0DDDu), + HB_CODEPOINT_ENCODE3 (0x0F40u, 0x0FB5u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F42u, 0x0FB7u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0F4Cu, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F51u, 0x0FB7u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0F56u, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F5Bu, 0x0FB7u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F72u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F74u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0F71u, 0x0F80u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F90u, 0x0FB5u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0F92u, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0F9Cu, 0x0FB7u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0FA1u, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0FA6u, 0x0FB7u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0FABu, 0x0FB7u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x0FB2u, 0x0F80u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x0FB3u, 0x0F80u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1025u, 0x102Eu, 0x1026u), + HB_CODEPOINT_ENCODE3 (0x1B05u, 0x1B35u, 0x1B06u), HB_CODEPOINT_ENCODE3 (0x1B07u, 0x1B35u, 0x1B08u), + HB_CODEPOINT_ENCODE3 (0x1B09u, 0x1B35u, 0x1B0Au), HB_CODEPOINT_ENCODE3 (0x1B0Bu, 0x1B35u, 0x1B0Cu), + HB_CODEPOINT_ENCODE3 (0x1B0Du, 0x1B35u, 0x1B0Eu), HB_CODEPOINT_ENCODE3 (0x1B11u, 0x1B35u, 0x1B12u), + HB_CODEPOINT_ENCODE3 (0x1B3Au, 0x1B35u, 0x1B3Bu), HB_CODEPOINT_ENCODE3 (0x1B3Cu, 0x1B35u, 0x1B3Du), + HB_CODEPOINT_ENCODE3 (0x1B3Eu, 0x1B35u, 0x1B40u), HB_CODEPOINT_ENCODE3 (0x1B3Fu, 0x1B35u, 0x1B41u), + HB_CODEPOINT_ENCODE3 (0x1B42u, 0x1B35u, 0x1B43u), HB_CODEPOINT_ENCODE3 (0x1E36u, 0x0304u, 0x1E38u), + HB_CODEPOINT_ENCODE3 (0x1E37u, 0x0304u, 0x1E39u), HB_CODEPOINT_ENCODE3 (0x1E5Au, 0x0304u, 0x1E5Cu), + HB_CODEPOINT_ENCODE3 (0x1E5Bu, 0x0304u, 0x1E5Du), HB_CODEPOINT_ENCODE3 (0x1E62u, 0x0307u, 0x1E68u), + HB_CODEPOINT_ENCODE3 (0x1E63u, 0x0307u, 0x1E69u), HB_CODEPOINT_ENCODE3 (0x1EA0u, 0x0302u, 0x1EACu), + HB_CODEPOINT_ENCODE3 (0x1EA0u, 0x0306u, 0x1EB6u), HB_CODEPOINT_ENCODE3 (0x1EA1u, 0x0302u, 0x1EADu), + HB_CODEPOINT_ENCODE3 (0x1EA1u, 0x0306u, 0x1EB7u), HB_CODEPOINT_ENCODE3 (0x1EB8u, 0x0302u, 0x1EC6u), + HB_CODEPOINT_ENCODE3 (0x1EB9u, 0x0302u, 0x1EC7u), HB_CODEPOINT_ENCODE3 (0x1ECCu, 0x0302u, 0x1ED8u), + HB_CODEPOINT_ENCODE3 (0x1ECDu, 0x0302u, 0x1ED9u), HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0300u, 0x1F02u), + HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0301u, 0x1F04u), HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0342u, 0x1F06u), + HB_CODEPOINT_ENCODE3 (0x1F00u, 0x0345u, 0x1F80u), HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0300u, 0x1F03u), + HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0301u, 0x1F05u), HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0342u, 0x1F07u), + HB_CODEPOINT_ENCODE3 (0x1F01u, 0x0345u, 0x1F81u), HB_CODEPOINT_ENCODE3 (0x1F02u, 0x0345u, 0x1F82u), + HB_CODEPOINT_ENCODE3 (0x1F03u, 0x0345u, 0x1F83u), HB_CODEPOINT_ENCODE3 (0x1F04u, 0x0345u, 0x1F84u), + HB_CODEPOINT_ENCODE3 (0x1F05u, 0x0345u, 0x1F85u), HB_CODEPOINT_ENCODE3 (0x1F06u, 0x0345u, 0x1F86u), + HB_CODEPOINT_ENCODE3 (0x1F07u, 0x0345u, 0x1F87u), HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0300u, 0x1F0Au), + HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0301u, 0x1F0Cu), HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0342u, 0x1F0Eu), + HB_CODEPOINT_ENCODE3 (0x1F08u, 0x0345u, 0x1F88u), HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0300u, 0x1F0Bu), + HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0301u, 0x1F0Du), HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0342u, 0x1F0Fu), + HB_CODEPOINT_ENCODE3 (0x1F09u, 0x0345u, 0x1F89u), HB_CODEPOINT_ENCODE3 (0x1F0Au, 0x0345u, 0x1F8Au), + HB_CODEPOINT_ENCODE3 (0x1F0Bu, 0x0345u, 0x1F8Bu), HB_CODEPOINT_ENCODE3 (0x1F0Cu, 0x0345u, 0x1F8Cu), + HB_CODEPOINT_ENCODE3 (0x1F0Du, 0x0345u, 0x1F8Du), HB_CODEPOINT_ENCODE3 (0x1F0Eu, 0x0345u, 0x1F8Eu), + HB_CODEPOINT_ENCODE3 (0x1F0Fu, 0x0345u, 0x1F8Fu), HB_CODEPOINT_ENCODE3 (0x1F10u, 0x0300u, 0x1F12u), + HB_CODEPOINT_ENCODE3 (0x1F10u, 0x0301u, 0x1F14u), HB_CODEPOINT_ENCODE3 (0x1F11u, 0x0300u, 0x1F13u), + HB_CODEPOINT_ENCODE3 (0x1F11u, 0x0301u, 0x1F15u), HB_CODEPOINT_ENCODE3 (0x1F18u, 0x0300u, 0x1F1Au), + HB_CODEPOINT_ENCODE3 (0x1F18u, 0x0301u, 0x1F1Cu), HB_CODEPOINT_ENCODE3 (0x1F19u, 0x0300u, 0x1F1Bu), + HB_CODEPOINT_ENCODE3 (0x1F19u, 0x0301u, 0x1F1Du), HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0300u, 0x1F22u), + HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0301u, 0x1F24u), HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0342u, 0x1F26u), + HB_CODEPOINT_ENCODE3 (0x1F20u, 0x0345u, 0x1F90u), HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0300u, 0x1F23u), + HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0301u, 0x1F25u), HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0342u, 0x1F27u), + HB_CODEPOINT_ENCODE3 (0x1F21u, 0x0345u, 0x1F91u), HB_CODEPOINT_ENCODE3 (0x1F22u, 0x0345u, 0x1F92u), + HB_CODEPOINT_ENCODE3 (0x1F23u, 0x0345u, 0x1F93u), HB_CODEPOINT_ENCODE3 (0x1F24u, 0x0345u, 0x1F94u), + HB_CODEPOINT_ENCODE3 (0x1F25u, 0x0345u, 0x1F95u), HB_CODEPOINT_ENCODE3 (0x1F26u, 0x0345u, 0x1F96u), + HB_CODEPOINT_ENCODE3 (0x1F27u, 0x0345u, 0x1F97u), HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0300u, 0x1F2Au), + HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0301u, 0x1F2Cu), HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0342u, 0x1F2Eu), + HB_CODEPOINT_ENCODE3 (0x1F28u, 0x0345u, 0x1F98u), HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0300u, 0x1F2Bu), + HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0301u, 0x1F2Du), HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0342u, 0x1F2Fu), + HB_CODEPOINT_ENCODE3 (0x1F29u, 0x0345u, 0x1F99u), HB_CODEPOINT_ENCODE3 (0x1F2Au, 0x0345u, 0x1F9Au), + HB_CODEPOINT_ENCODE3 (0x1F2Bu, 0x0345u, 0x1F9Bu), HB_CODEPOINT_ENCODE3 (0x1F2Cu, 0x0345u, 0x1F9Cu), + HB_CODEPOINT_ENCODE3 (0x1F2Du, 0x0345u, 0x1F9Du), HB_CODEPOINT_ENCODE3 (0x1F2Eu, 0x0345u, 0x1F9Eu), + HB_CODEPOINT_ENCODE3 (0x1F2Fu, 0x0345u, 0x1F9Fu), HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0300u, 0x1F32u), + HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0301u, 0x1F34u), HB_CODEPOINT_ENCODE3 (0x1F30u, 0x0342u, 0x1F36u), + HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0300u, 0x1F33u), HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0301u, 0x1F35u), + HB_CODEPOINT_ENCODE3 (0x1F31u, 0x0342u, 0x1F37u), HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0300u, 0x1F3Au), + HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0301u, 0x1F3Cu), HB_CODEPOINT_ENCODE3 (0x1F38u, 0x0342u, 0x1F3Eu), + HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0300u, 0x1F3Bu), HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0301u, 0x1F3Du), + HB_CODEPOINT_ENCODE3 (0x1F39u, 0x0342u, 0x1F3Fu), HB_CODEPOINT_ENCODE3 (0x1F40u, 0x0300u, 0x1F42u), + HB_CODEPOINT_ENCODE3 (0x1F40u, 0x0301u, 0x1F44u), HB_CODEPOINT_ENCODE3 (0x1F41u, 0x0300u, 0x1F43u), + HB_CODEPOINT_ENCODE3 (0x1F41u, 0x0301u, 0x1F45u), HB_CODEPOINT_ENCODE3 (0x1F48u, 0x0300u, 0x1F4Au), + HB_CODEPOINT_ENCODE3 (0x1F48u, 0x0301u, 0x1F4Cu), HB_CODEPOINT_ENCODE3 (0x1F49u, 0x0300u, 0x1F4Bu), + HB_CODEPOINT_ENCODE3 (0x1F49u, 0x0301u, 0x1F4Du), HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0300u, 0x1F52u), + HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0301u, 0x1F54u), HB_CODEPOINT_ENCODE3 (0x1F50u, 0x0342u, 0x1F56u), + HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0300u, 0x1F53u), HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0301u, 0x1F55u), + HB_CODEPOINT_ENCODE3 (0x1F51u, 0x0342u, 0x1F57u), HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0300u, 0x1F5Bu), + HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0301u, 0x1F5Du), HB_CODEPOINT_ENCODE3 (0x1F59u, 0x0342u, 0x1F5Fu), + HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0300u, 0x1F62u), HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0301u, 0x1F64u), + HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0342u, 0x1F66u), HB_CODEPOINT_ENCODE3 (0x1F60u, 0x0345u, 0x1FA0u), + HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0300u, 0x1F63u), HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0301u, 0x1F65u), + HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0342u, 0x1F67u), HB_CODEPOINT_ENCODE3 (0x1F61u, 0x0345u, 0x1FA1u), + HB_CODEPOINT_ENCODE3 (0x1F62u, 0x0345u, 0x1FA2u), HB_CODEPOINT_ENCODE3 (0x1F63u, 0x0345u, 0x1FA3u), + HB_CODEPOINT_ENCODE3 (0x1F64u, 0x0345u, 0x1FA4u), HB_CODEPOINT_ENCODE3 (0x1F65u, 0x0345u, 0x1FA5u), + HB_CODEPOINT_ENCODE3 (0x1F66u, 0x0345u, 0x1FA6u), HB_CODEPOINT_ENCODE3 (0x1F67u, 0x0345u, 0x1FA7u), + HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0300u, 0x1F6Au), HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0301u, 0x1F6Cu), + HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0342u, 0x1F6Eu), HB_CODEPOINT_ENCODE3 (0x1F68u, 0x0345u, 0x1FA8u), + HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0300u, 0x1F6Bu), HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0301u, 0x1F6Du), + HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0342u, 0x1F6Fu), HB_CODEPOINT_ENCODE3 (0x1F69u, 0x0345u, 0x1FA9u), + HB_CODEPOINT_ENCODE3 (0x1F6Au, 0x0345u, 0x1FAAu), HB_CODEPOINT_ENCODE3 (0x1F6Bu, 0x0345u, 0x1FABu), + HB_CODEPOINT_ENCODE3 (0x1F6Cu, 0x0345u, 0x1FACu), HB_CODEPOINT_ENCODE3 (0x1F6Du, 0x0345u, 0x1FADu), + HB_CODEPOINT_ENCODE3 (0x1F6Eu, 0x0345u, 0x1FAEu), HB_CODEPOINT_ENCODE3 (0x1F6Fu, 0x0345u, 0x1FAFu), + HB_CODEPOINT_ENCODE3 (0x1F70u, 0x0345u, 0x1FB2u), HB_CODEPOINT_ENCODE3 (0x1F74u, 0x0345u, 0x1FC2u), + HB_CODEPOINT_ENCODE3 (0x1F7Cu, 0x0345u, 0x1FF2u), HB_CODEPOINT_ENCODE3 (0x1FB6u, 0x0345u, 0x1FB7u), + HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0300u, 0x1FCDu), HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0301u, 0x1FCEu), + HB_CODEPOINT_ENCODE3 (0x1FBFu, 0x0342u, 0x1FCFu), HB_CODEPOINT_ENCODE3 (0x1FC6u, 0x0345u, 0x1FC7u), + HB_CODEPOINT_ENCODE3 (0x1FF6u, 0x0345u, 0x1FF7u), HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0300u, 0x1FDDu), + HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0301u, 0x1FDEu), HB_CODEPOINT_ENCODE3 (0x1FFEu, 0x0342u, 0x1FDFu), + HB_CODEPOINT_ENCODE3 (0x2190u, 0x0338u, 0x219Au), HB_CODEPOINT_ENCODE3 (0x2192u, 0x0338u, 0x219Bu), + HB_CODEPOINT_ENCODE3 (0x2194u, 0x0338u, 0x21AEu), HB_CODEPOINT_ENCODE3 (0x21D0u, 0x0338u, 0x21CDu), + HB_CODEPOINT_ENCODE3 (0x21D2u, 0x0338u, 0x21CFu), HB_CODEPOINT_ENCODE3 (0x21D4u, 0x0338u, 0x21CEu), + HB_CODEPOINT_ENCODE3 (0x2203u, 0x0338u, 0x2204u), HB_CODEPOINT_ENCODE3 (0x2208u, 0x0338u, 0x2209u), + HB_CODEPOINT_ENCODE3 (0x220Bu, 0x0338u, 0x220Cu), HB_CODEPOINT_ENCODE3 (0x2223u, 0x0338u, 0x2224u), + HB_CODEPOINT_ENCODE3 (0x2225u, 0x0338u, 0x2226u), HB_CODEPOINT_ENCODE3 (0x223Cu, 0x0338u, 0x2241u), + HB_CODEPOINT_ENCODE3 (0x2243u, 0x0338u, 0x2244u), HB_CODEPOINT_ENCODE3 (0x2245u, 0x0338u, 0x2247u), + HB_CODEPOINT_ENCODE3 (0x2248u, 0x0338u, 0x2249u), HB_CODEPOINT_ENCODE3 (0x224Du, 0x0338u, 0x226Du), + HB_CODEPOINT_ENCODE3 (0x2261u, 0x0338u, 0x2262u), HB_CODEPOINT_ENCODE3 (0x2264u, 0x0338u, 0x2270u), + HB_CODEPOINT_ENCODE3 (0x2265u, 0x0338u, 0x2271u), HB_CODEPOINT_ENCODE3 (0x2272u, 0x0338u, 0x2274u), + HB_CODEPOINT_ENCODE3 (0x2273u, 0x0338u, 0x2275u), HB_CODEPOINT_ENCODE3 (0x2276u, 0x0338u, 0x2278u), + HB_CODEPOINT_ENCODE3 (0x2277u, 0x0338u, 0x2279u), HB_CODEPOINT_ENCODE3 (0x227Au, 0x0338u, 0x2280u), + HB_CODEPOINT_ENCODE3 (0x227Bu, 0x0338u, 0x2281u), HB_CODEPOINT_ENCODE3 (0x227Cu, 0x0338u, 0x22E0u), + HB_CODEPOINT_ENCODE3 (0x227Du, 0x0338u, 0x22E1u), HB_CODEPOINT_ENCODE3 (0x2282u, 0x0338u, 0x2284u), + HB_CODEPOINT_ENCODE3 (0x2283u, 0x0338u, 0x2285u), HB_CODEPOINT_ENCODE3 (0x2286u, 0x0338u, 0x2288u), + HB_CODEPOINT_ENCODE3 (0x2287u, 0x0338u, 0x2289u), HB_CODEPOINT_ENCODE3 (0x2291u, 0x0338u, 0x22E2u), + HB_CODEPOINT_ENCODE3 (0x2292u, 0x0338u, 0x22E3u), HB_CODEPOINT_ENCODE3 (0x22A2u, 0x0338u, 0x22ACu), + HB_CODEPOINT_ENCODE3 (0x22A8u, 0x0338u, 0x22ADu), HB_CODEPOINT_ENCODE3 (0x22A9u, 0x0338u, 0x22AEu), + HB_CODEPOINT_ENCODE3 (0x22ABu, 0x0338u, 0x22AFu), HB_CODEPOINT_ENCODE3 (0x22B2u, 0x0338u, 0x22EAu), + HB_CODEPOINT_ENCODE3 (0x22B3u, 0x0338u, 0x22EBu), HB_CODEPOINT_ENCODE3 (0x22B4u, 0x0338u, 0x22ECu), + HB_CODEPOINT_ENCODE3 (0x22B5u, 0x0338u, 0x22EDu), HB_CODEPOINT_ENCODE3 (0x2ADDu, 0x0338u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x3046u, 0x3099u, 0x3094u), HB_CODEPOINT_ENCODE3 (0x304Bu, 0x3099u, 0x304Cu), + HB_CODEPOINT_ENCODE3 (0x304Du, 0x3099u, 0x304Eu), HB_CODEPOINT_ENCODE3 (0x304Fu, 0x3099u, 0x3050u), + HB_CODEPOINT_ENCODE3 (0x3051u, 0x3099u, 0x3052u), HB_CODEPOINT_ENCODE3 (0x3053u, 0x3099u, 0x3054u), + HB_CODEPOINT_ENCODE3 (0x3055u, 0x3099u, 0x3056u), HB_CODEPOINT_ENCODE3 (0x3057u, 0x3099u, 0x3058u), + HB_CODEPOINT_ENCODE3 (0x3059u, 0x3099u, 0x305Au), HB_CODEPOINT_ENCODE3 (0x305Bu, 0x3099u, 0x305Cu), + HB_CODEPOINT_ENCODE3 (0x305Du, 0x3099u, 0x305Eu), HB_CODEPOINT_ENCODE3 (0x305Fu, 0x3099u, 0x3060u), + HB_CODEPOINT_ENCODE3 (0x3061u, 0x3099u, 0x3062u), HB_CODEPOINT_ENCODE3 (0x3064u, 0x3099u, 0x3065u), + HB_CODEPOINT_ENCODE3 (0x3066u, 0x3099u, 0x3067u), HB_CODEPOINT_ENCODE3 (0x3068u, 0x3099u, 0x3069u), + HB_CODEPOINT_ENCODE3 (0x306Fu, 0x3099u, 0x3070u), HB_CODEPOINT_ENCODE3 (0x306Fu, 0x309Au, 0x3071u), + HB_CODEPOINT_ENCODE3 (0x3072u, 0x3099u, 0x3073u), HB_CODEPOINT_ENCODE3 (0x3072u, 0x309Au, 0x3074u), + HB_CODEPOINT_ENCODE3 (0x3075u, 0x3099u, 0x3076u), HB_CODEPOINT_ENCODE3 (0x3075u, 0x309Au, 0x3077u), + HB_CODEPOINT_ENCODE3 (0x3078u, 0x3099u, 0x3079u), HB_CODEPOINT_ENCODE3 (0x3078u, 0x309Au, 0x307Au), + HB_CODEPOINT_ENCODE3 (0x307Bu, 0x3099u, 0x307Cu), HB_CODEPOINT_ENCODE3 (0x307Bu, 0x309Au, 0x307Du), + HB_CODEPOINT_ENCODE3 (0x309Du, 0x3099u, 0x309Eu), HB_CODEPOINT_ENCODE3 (0x30A6u, 0x3099u, 0x30F4u), + HB_CODEPOINT_ENCODE3 (0x30ABu, 0x3099u, 0x30ACu), HB_CODEPOINT_ENCODE3 (0x30ADu, 0x3099u, 0x30AEu), + HB_CODEPOINT_ENCODE3 (0x30AFu, 0x3099u, 0x30B0u), HB_CODEPOINT_ENCODE3 (0x30B1u, 0x3099u, 0x30B2u), + HB_CODEPOINT_ENCODE3 (0x30B3u, 0x3099u, 0x30B4u), HB_CODEPOINT_ENCODE3 (0x30B5u, 0x3099u, 0x30B6u), + HB_CODEPOINT_ENCODE3 (0x30B7u, 0x3099u, 0x30B8u), HB_CODEPOINT_ENCODE3 (0x30B9u, 0x3099u, 0x30BAu), + HB_CODEPOINT_ENCODE3 (0x30BBu, 0x3099u, 0x30BCu), HB_CODEPOINT_ENCODE3 (0x30BDu, 0x3099u, 0x30BEu), + HB_CODEPOINT_ENCODE3 (0x30BFu, 0x3099u, 0x30C0u), HB_CODEPOINT_ENCODE3 (0x30C1u, 0x3099u, 0x30C2u), + HB_CODEPOINT_ENCODE3 (0x30C4u, 0x3099u, 0x30C5u), HB_CODEPOINT_ENCODE3 (0x30C6u, 0x3099u, 0x30C7u), + HB_CODEPOINT_ENCODE3 (0x30C8u, 0x3099u, 0x30C9u), HB_CODEPOINT_ENCODE3 (0x30CFu, 0x3099u, 0x30D0u), + HB_CODEPOINT_ENCODE3 (0x30CFu, 0x309Au, 0x30D1u), HB_CODEPOINT_ENCODE3 (0x30D2u, 0x3099u, 0x30D3u), + HB_CODEPOINT_ENCODE3 (0x30D2u, 0x309Au, 0x30D4u), HB_CODEPOINT_ENCODE3 (0x30D5u, 0x3099u, 0x30D6u), + HB_CODEPOINT_ENCODE3 (0x30D5u, 0x309Au, 0x30D7u), HB_CODEPOINT_ENCODE3 (0x30D8u, 0x3099u, 0x30D9u), + HB_CODEPOINT_ENCODE3 (0x30D8u, 0x309Au, 0x30DAu), HB_CODEPOINT_ENCODE3 (0x30DBu, 0x3099u, 0x30DCu), + HB_CODEPOINT_ENCODE3 (0x30DBu, 0x309Au, 0x30DDu), HB_CODEPOINT_ENCODE3 (0x30EFu, 0x3099u, 0x30F7u), + HB_CODEPOINT_ENCODE3 (0x30F0u, 0x3099u, 0x30F8u), HB_CODEPOINT_ENCODE3 (0x30F1u, 0x3099u, 0x30F9u), + HB_CODEPOINT_ENCODE3 (0x30F2u, 0x3099u, 0x30FAu), HB_CODEPOINT_ENCODE3 (0x30FDu, 0x3099u, 0x30FEu), + HB_CODEPOINT_ENCODE3 (0xFB49u, 0x05C1u, 0x0000u), HB_CODEPOINT_ENCODE3 (0xFB49u, 0x05C2u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x11099u, 0x110BAu, 0x1109Au),HB_CODEPOINT_ENCODE3 (0x1109Bu, 0x110BAu, 0x1109Cu), + HB_CODEPOINT_ENCODE3 (0x110A5u, 0x110BAu, 0x110ABu),HB_CODEPOINT_ENCODE3 (0x11131u, 0x11127u, 0x1112Eu), + HB_CODEPOINT_ENCODE3 (0x11132u, 0x11127u, 0x1112Fu),HB_CODEPOINT_ENCODE3 (0x11347u, 0x1133Eu, 0x1134Bu), + HB_CODEPOINT_ENCODE3 (0x11347u, 0x11357u, 0x1134Cu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114B0u, 0x114BCu), + HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BAu, 0x114BBu),HB_CODEPOINT_ENCODE3 (0x114B9u, 0x114BDu, 0x114BEu), + HB_CODEPOINT_ENCODE3 (0x115B8u, 0x115AFu, 0x115BAu),HB_CODEPOINT_ENCODE3 (0x115B9u, 0x115AFu, 0x115BBu), + HB_CODEPOINT_ENCODE3 (0x11935u, 0x11930u, 0x11938u), HB_CODEPOINT_ENCODE3 (0x1D157u, 0x1D165u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D158u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Eu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D16Fu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D170u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D171u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D15Fu, 0x1D172u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D1B9u, 0x1D165u, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BAu, 0x1D165u, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BBu, 0x1D16Fu, 0x0000u), + HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Eu, 0x0000u), HB_CODEPOINT_ENCODE3 (0x1D1BCu, 0x1D16Fu, 0x0000u), +}; + +#ifndef HB_OPTIMIZE_SIZE + +static const uint8_t +_hb_ucd_u8[32480] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 27, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 28, + 29, 26, 30, 31, 32, 33, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 34, 35, 35, 35, 35, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 26, 57, 58, 59, 59, 59, 59, 59, 26, 26, 60, 59, 59, 59, 59, 59, + 59, 59, 26, 61, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 26, 62, 59, 63, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 64, 26, 26, 65, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 66, 67, 59, 59, 59, 59, 68, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 69, 70, 71, 72, 73, 74, 59, 59, + 75, 76, 59, 59, 77, 59, 78, 79, 80, 81, 73, 82, 83, 84, 59, 59, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 85, 26, 26, 26, 26, 26, 26, 26, 86, 87, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 88, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 89, 59, 59, 59, 59, 59, 59, 26, 90, 59, 59, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 91, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 92, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 93, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 94, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 25, 25, 25, 21, + 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 21, 18, 24, 16, + 24, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 25, 18, 25, 0, + 29, 21, 23, 23, 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, + 26, 25, 15, 15, 24, 5, 21, 21, 24, 15, 7, 19, 15, 15, 15, 21, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 25, 9, 9, 9, 9, 9, 9, 9, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 5, 5, + 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, + 9, 5, 9, 5, 9, 5, 9, 5, 5, 9, 5, 9, 5, 9, 5, 9, + 5, 9, 5, 9, 5, 9, 5, 9, 5, 5, 9, 5, 9, 5, 9, 5, + 9, 5, 9, 5, 9, 5, 9, 5, 9, 9, 5, 9, 5, 9, 5, 5, + 5, 9, 9, 5, 9, 5, 9, 9, 5, 9, 9, 9, 5, 5, 9, 9, + 9, 9, 5, 9, 9, 5, 9, 9, 9, 5, 5, 5, 9, 9, 5, 9, + 9, 5, 9, 5, 9, 5, 9, 9, 5, 9, 5, 5, 9, 5, 9, 9, + 5, 9, 9, 9, 5, 9, 5, 9, 9, 5, 5, 7, 9, 5, 5, 5, + 7, 7, 7, 7, 9, 8, 5, 9, 8, 5, 9, 8, 5, 9, 5, 9, + 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 5, 9, 5, + 5, 9, 8, 5, 9, 5, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5, + 9, 5, 9, 5, 5, 5, 5, 5, 5, 5, 9, 9, 5, 9, 9, 5, + 5, 9, 5, 9, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, + 5, 5, 5, 5, 7, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 24, 24, 24, 24, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 6, 6, 6, 6, 6, 24, 24, 24, 24, 24, 24, 24, 6, 24, 6, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 9, 5, 9, 5, 6, 24, 9, 5, 2, 2, 6, 5, 5, 5, 21, 9, + 2, 2, 2, 2, 24, 24, 9, 21, 9, 9, 9, 2, 9, 2, 9, 9, + 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, + 5, 5, 9, 9, 9, 5, 5, 5, 9, 5, 9, 5, 9, 5, 9, 5, + 5, 5, 5, 5, 9, 5, 25, 9, 5, 9, 9, 5, 5, 9, 9, 9, + 9, 5, 26, 12, 12, 12, 12, 12, 11, 11, 9, 5, 9, 5, 9, 5, + 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 5, + 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 2, 2, 6, 21, 21, 21, 21, 21, 21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 21, 17, 2, 2, 26, 26, 23, + 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 17, 12, + 21, 12, 12, 21, 12, 12, 21, 12, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7, + 7, 7, 7, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 25, 25, 25, 21, 21, 23, 21, 21, 26, 26, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 1, 2, 21, 21, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 7, 7, + 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 21, 7, 12, 12, 12, 12, 12, 12, 12, 1, 26, 12, + 12, 12, 12, 12, 12, 6, 6, 12, 12, 26, 12, 12, 12, 12, 7, 7, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 26, 26, 7, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 1, + 7, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 6, 6, 26, 21, 21, 21, 6, 2, 2, 12, 23, 23, + 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 6, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 6, 12, 12, 12, 6, 12, 12, 12, 12, 12, 2, 2, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 2, 2, 21, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 1, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 12, 7, 10, 10, + 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, 10, 12, 10, 10, + 7, 12, 12, 12, 12, 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 12, 12, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, + 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, + 7, 2, 7, 2, 2, 2, 7, 7, 7, 7, 2, 2, 12, 7, 10, 10, + 10, 12, 12, 12, 12, 2, 2, 10, 10, 2, 2, 10, 10, 12, 7, 2, + 2, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 7, 7, 2, 7, + 7, 7, 12, 12, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 7, 7, 23, 23, 15, 15, 15, 15, 15, 15, 26, 23, 7, 21, 12, 2, + 2, 12, 12, 10, 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7, + 7, 2, 7, 7, 2, 7, 7, 2, 7, 7, 2, 2, 12, 2, 10, 10, + 10, 12, 12, 2, 2, 2, 2, 12, 12, 2, 2, 12, 12, 12, 2, 2, + 2, 12, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, 7, 2, 7, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 12, 12, 7, 7, 7, 12, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 12, 12, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, + 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 10, + 10, 12, 12, 12, 12, 12, 2, 12, 12, 10, 2, 10, 10, 12, 2, 2, + 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 21, 23, 2, 2, 2, 2, 2, 2, 2, 7, 12, 12, 12, 12, 12, 12, + 2, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, + 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 12, + 10, 12, 12, 12, 12, 2, 2, 10, 10, 2, 2, 10, 10, 12, 2, 2, + 2, 2, 2, 2, 2, 12, 12, 10, 2, 2, 2, 2, 7, 7, 2, 7, + 26, 7, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 12, 7, 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 7, 7, + 7, 2, 7, 7, 7, 7, 2, 2, 2, 7, 7, 2, 7, 2, 7, 7, + 2, 2, 2, 7, 7, 2, 2, 2, 7, 7, 7, 2, 2, 2, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 10, 10, + 12, 10, 10, 2, 2, 2, 10, 10, 10, 2, 10, 10, 10, 12, 2, 2, + 7, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, + 15, 15, 15, 26, 26, 26, 26, 26, 26, 23, 26, 2, 2, 2, 2, 2, + 12, 10, 10, 10, 12, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, + 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 7, 12, 12, + 12, 10, 10, 10, 10, 2, 12, 12, 12, 2, 12, 12, 12, 12, 2, 2, + 2, 2, 2, 2, 2, 12, 12, 2, 7, 7, 7, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 21, 15, 15, 15, 15, 15, 15, 15, 26, + 7, 12, 10, 10, 21, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, + 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 2, 12, 7, 10, 12, + 10, 10, 10, 10, 10, 2, 12, 10, 10, 2, 10, 10, 12, 12, 2, 2, + 2, 2, 2, 2, 2, 10, 10, 2, 2, 2, 2, 2, 2, 2, 7, 2, + 2, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 12, 12, 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 7, 10, 10, + 10, 12, 12, 12, 12, 2, 10, 10, 10, 2, 10, 10, 10, 12, 7, 26, + 2, 2, 2, 2, 7, 7, 7, 10, 15, 15, 15, 15, 15, 15, 15, 7, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 7, 7, 7, 7, 7, 7, + 2, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 7, 7, 7, 7, 7, 7, + 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 12, 2, 2, 2, 2, 10, + 10, 10, 12, 12, 12, 2, 12, 2, 10, 10, 10, 10, 10, 10, 10, 10, + 2, 2, 10, 10, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 12, 7, 7, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 23, + 7, 7, 7, 7, 7, 7, 6, 12, 12, 12, 12, 12, 12, 12, 12, 21, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 2, 2, 2, 2, + 2, 7, 7, 2, 7, 2, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, + 7, 7, 7, 7, 2, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 12, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 7, 2, 2, + 7, 7, 7, 7, 7, 2, 6, 2, 12, 12, 12, 12, 12, 12, 2, 2, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 7, 7, 7, 7, + 7, 26, 26, 26, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 26, 21, 26, 26, 26, 12, 12, 26, 26, 26, 26, 26, 26, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 26, 12, 26, 12, 26, 12, 22, 18, 22, 18, 10, 10, + 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, + 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, + 12, 12, 12, 12, 12, 21, 12, 12, 7, 7, 7, 7, 7, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 26, 26, + 26, 26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26, 2, 26, 26, + 21, 21, 21, 21, 21, 26, 26, 26, 26, 21, 21, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 12, 12, 12, + 12, 10, 12, 12, 12, 12, 12, 12, 10, 12, 12, 10, 10, 12, 12, 7, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 21, 21, 21, 21, + 7, 7, 7, 7, 7, 7, 10, 10, 12, 12, 7, 7, 7, 7, 12, 12, + 12, 7, 10, 10, 10, 7, 7, 10, 10, 10, 10, 10, 10, 10, 7, 7, + 7, 12, 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 12, 10, 10, 12, 12, 10, 10, 10, 10, 10, 10, 12, 7, 10, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 10, 10, 10, 12, 26, 26, + 9, 9, 9, 9, 9, 9, 2, 9, 2, 2, 2, 2, 2, 9, 2, 2, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 21, 6, 5, 5, 5, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 7, 7, 7, 7, 2, 2, + 7, 2, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 2, + 7, 2, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 12, 12, 12, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, + 9, 9, 9, 9, 9, 9, 2, 2, 5, 5, 5, 5, 5, 5, 2, 2, + 17, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 26, 21, 7, + 29, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 22, 18, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 21, 21, 14, 14, + 14, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, + 7, 7, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 12, 12, 12, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 2, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 12, 12, 10, 12, 12, 12, 12, 12, 12, 12, 10, 10, + 10, 10, 10, 10, 10, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 21, 21, 21, 6, 21, 21, 21, 23, 7, 12, 2, 2, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, + 21, 21, 21, 21, 21, 21, 17, 21, 21, 21, 21, 12, 12, 12, 1, 2, + 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 7, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, + 12, 12, 12, 10, 10, 10, 10, 12, 12, 10, 10, 10, 2, 2, 2, 2, + 10, 10, 12, 10, 10, 10, 10, 10, 10, 12, 12, 12, 2, 2, 2, 2, + 26, 2, 2, 2, 21, 21, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, + 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 2, 2, 2, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 7, 7, 7, 7, 7, 7, 7, 12, 12, 10, 10, 12, 2, 2, 21, 21, + 7, 7, 7, 7, 7, 10, 12, 10, 12, 12, 12, 12, 12, 12, 12, 2, + 12, 10, 12, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 10, + 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 12, + 21, 21, 21, 21, 21, 21, 21, 6, 21, 21, 21, 21, 21, 21, 2, 2, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 12, + 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 12, 12, 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 12, 10, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10, + 10, 10, 12, 10, 10, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, + 21, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, + 12, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 12, 12, 12, 7, 7, + 7, 7, 7, 7, 7, 7, 12, 10, 12, 12, 10, 10, 10, 12, 10, 12, + 12, 12, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 21, + 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 10, 12, 12, 12, 12, + 12, 12, 12, 12, 10, 10, 12, 12, 2, 2, 2, 21, 21, 21, 21, 21, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 21, 21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, + 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, + 12, 12, 12, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 10, 12, 12, 12, 12, 12, 12, 12, 7, 7, 7, 7, 12, 7, 7, + 7, 7, 7, 7, 12, 7, 7, 10, 12, 12, 7, 2, 2, 2, 2, 2, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, + 9, 5, 9, 5, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, + 5, 5, 5, 5, 5, 5, 2, 2, 9, 9, 9, 9, 9, 9, 2, 2, + 5, 5, 5, 5, 5, 5, 5, 5, 2, 9, 2, 9, 2, 9, 2, 9, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, + 5, 5, 5, 5, 5, 5, 5, 5, 8, 8, 8, 8, 8, 8, 8, 8, + 5, 5, 5, 5, 5, 2, 5, 5, 9, 9, 9, 9, 8, 24, 5, 24, + 24, 24, 5, 5, 5, 2, 5, 5, 9, 9, 9, 9, 8, 24, 24, 24, + 5, 5, 5, 5, 2, 2, 5, 5, 9, 9, 9, 9, 2, 24, 24, 24, + 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 24, 24, 24, + 2, 2, 5, 5, 5, 2, 5, 5, 9, 9, 9, 9, 8, 24, 24, 2, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 1, 1, 1, 1, 1, + 17, 17, 17, 17, 17, 17, 21, 21, 20, 19, 22, 20, 20, 19, 22, 20, + 21, 21, 21, 21, 21, 21, 21, 21, 27, 28, 1, 1, 1, 1, 1, 29, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 20, 19, 21, 21, 21, 21, 16, + 16, 21, 21, 21, 25, 22, 18, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 25, 21, 16, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 29, + 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 15, 6, 2, 2, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18, 6, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 25, 25, 25, 22, 18, 2, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, 2, 2, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, + 11, 12, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 26, 26, 9, 26, 26, 26, 26, 9, 26, 26, 5, 9, 9, 9, 5, 5, + 9, 9, 9, 5, 26, 9, 26, 26, 25, 9, 9, 9, 9, 9, 26, 26, + 26, 26, 26, 26, 9, 26, 9, 26, 9, 26, 9, 9, 9, 9, 26, 5, + 9, 9, 9, 9, 5, 7, 7, 7, 7, 5, 26, 26, 5, 5, 9, 9, + 25, 25, 25, 25, 25, 9, 5, 5, 5, 5, 26, 25, 26, 26, 5, 26, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 9, 5, 14, 14, 14, 14, 15, 26, 26, 2, 2, 2, 2, + 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 25, 25, 26, 26, 26, 26, + 25, 26, 26, 25, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 25, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, + 26, 26, 25, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 26, 26, 26, 26, + 25, 25, 26, 26, 26, 26, 26, 26, 26, 22, 18, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, + 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15, + 26, 26, 26, 26, 26, 26, 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 25, 25, 25, 25, 25, 25, 25, 25, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 25, + 26, 26, 26, 26, 26, 26, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18, + 22, 18, 22, 18, 22, 18, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 25, 25, 25, 25, 25, 22, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, + 25, 25, 25, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, + 18, 22, 18, 22, 18, 22, 18, 22, 18, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 22, 18, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 22, 18, 25, 25, + 25, 25, 25, 25, 25, 26, 26, 25, 25, 25, 25, 25, 25, 26, 26, 26, + 26, 26, 26, 26, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, + 9, 5, 9, 9, 9, 5, 5, 9, 5, 9, 5, 9, 5, 9, 9, 9, + 9, 5, 9, 5, 5, 9, 5, 5, 5, 5, 5, 5, 6, 6, 9, 9, + 9, 5, 9, 5, 5, 26, 26, 26, 26, 26, 26, 9, 5, 9, 5, 12, + 12, 12, 9, 5, 2, 2, 2, 2, 2, 21, 21, 21, 21, 15, 21, 21, + 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 2, 2, 5, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 6, + 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, + 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 2, + 21, 21, 20, 19, 20, 19, 21, 21, 21, 20, 19, 21, 20, 19, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 17, 21, 21, 17, 21, 20, 19, 21, 21, + 20, 19, 22, 18, 22, 18, 22, 18, 22, 18, 21, 21, 21, 21, 21, 6, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 17, 17, 21, 21, 21, 21, + 17, 21, 22, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 26, 26, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, + 29, 21, 21, 21, 26, 6, 7, 14, 22, 18, 22, 18, 22, 18, 22, 18, + 22, 18, 26, 26, 22, 18, 22, 18, 22, 18, 22, 18, 17, 22, 18, 18, + 26, 14, 14, 14, 14, 14, 14, 14, 14, 14, 12, 12, 12, 12, 10, 10, + 17, 6, 6, 6, 6, 6, 26, 26, 14, 14, 14, 6, 7, 21, 26, 26, + 7, 7, 7, 7, 7, 7, 7, 2, 2, 12, 12, 24, 24, 6, 6, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 6, 6, 6, 7, + 2, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 26, 26, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 15, 15, 15, 15, 15, 15, + 26, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 7, 7, 7, 7, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 21, 21, 21, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 2, 2, 2, 2, + 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 7, 12, + 11, 11, 11, 21, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 21, 6, + 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 6, 6, 12, 12, + 7, 7, 7, 7, 7, 7, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 12, 12, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, + 24, 24, 24, 24, 24, 24, 24, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 24, 24, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, + 5, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, + 6, 5, 5, 5, 5, 5, 5, 5, 5, 9, 5, 9, 5, 9, 9, 5, + 9, 5, 9, 5, 9, 5, 9, 5, 6, 24, 24, 9, 5, 9, 5, 7, + 9, 5, 9, 5, 5, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, + 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 9, 9, 9, 9, 5, + 9, 9, 9, 9, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, 9, 5, + 2, 2, 9, 5, 9, 9, 9, 9, 5, 9, 5, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 9, 5, 7, 6, 6, 5, 7, 7, 7, 7, 7, + 7, 7, 12, 7, 7, 7, 12, 7, 7, 7, 7, 12, 7, 7, 7, 7, + 7, 7, 7, 10, 10, 12, 12, 10, 26, 26, 26, 26, 12, 2, 2, 2, + 15, 15, 15, 15, 15, 15, 26, 26, 23, 26, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, + 10, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 21, 21, + 12, 12, 7, 7, 7, 7, 7, 7, 21, 21, 21, 7, 21, 7, 7, 12, + 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 21, 21, + 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21, + 7, 7, 7, 12, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 10, 10, + 10, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 6, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 21, 21, + 7, 7, 7, 7, 7, 12, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 7, 7, 7, 7, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 10, + 10, 12, 12, 10, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 12, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 2, 2, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 21, 21, 21, 21, + 6, 7, 7, 7, 7, 7, 7, 26, 26, 26, 7, 10, 12, 10, 7, 7, + 12, 7, 12, 12, 12, 7, 7, 12, 12, 7, 7, 7, 7, 7, 12, 12, + 7, 12, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 6, 21, 21, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 12, 12, 10, 10, + 21, 21, 7, 6, 6, 10, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, 2, + 2, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 24, 6, 6, 6, 6, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 24, 24, 2, 2, 2, 2, + 7, 7, 7, 10, 10, 12, 10, 10, 12, 10, 10, 21, 10, 12, 2, 2, + 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 7, 7, 7, 7, 7, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 5, 5, 5, 5, 5, 2, 2, 2, 2, 2, 7, 12, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 25, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 7, 2, + 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 18, 22, + 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 23, 26, 2, 2, + 21, 21, 21, 21, 21, 21, 21, 22, 18, 21, 2, 2, 2, 2, 2, 2, + 21, 17, 17, 16, 16, 22, 18, 22, 18, 22, 18, 22, 18, 22, 18, 22, + 18, 22, 18, 22, 18, 21, 21, 22, 18, 21, 21, 21, 21, 16, 16, 16, + 21, 21, 21, 2, 21, 21, 21, 21, 17, 22, 18, 22, 18, 22, 18, 21, + 21, 21, 25, 17, 25, 25, 25, 2, 21, 23, 21, 21, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 1, + 2, 21, 21, 21, 23, 21, 21, 21, 22, 18, 21, 25, 21, 17, 21, 21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 25, 18, 25, 22, + 18, 21, 22, 18, 21, 21, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, + 2, 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, + 2, 2, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 2, 2, 2, + 23, 23, 25, 24, 26, 23, 23, 2, 26, 25, 25, 25, 25, 26, 26, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 26, 26, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 7, + 21, 21, 21, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 14, 14, 14, 14, 14, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 15, 15, 26, 26, 26, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, + 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 2, 2, + 12, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, + 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, 7, 7, + 7, 14, 7, 7, 7, 7, 7, 7, 7, 7, 14, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 21, + 7, 7, 7, 7, 2, 2, 2, 2, 7, 7, 7, 7, 7, 7, 7, 7, + 21, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, + 9, 9, 9, 9, 2, 2, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 2, 2, + 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21, + 7, 7, 7, 7, 7, 7, 2, 2, 7, 2, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 2, 2, 7, 2, 2, 7, + 7, 7, 7, 7, 7, 7, 2, 21, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 7, 7, 7, 7, 7, 7, 26, 26, 15, 15, 15, 15, 15, 15, 15, + 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 7, 7, 2, 7, 7, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, + 7, 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 2, 2, 2, 21, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 21, + 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 15, 15, 7, 7, + 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 12, 12, 12, 2, 12, 12, 2, 2, 2, 2, 2, 12, 12, 12, 12, + 7, 7, 7, 7, 2, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 2, 2, 12, 12, 12, 2, 2, 2, 2, 12, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 21, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 15, 15, 15, + 7, 7, 7, 7, 7, 7, 7, 7, 26, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 12, 12, 2, 2, 2, 2, 15, 15, 15, 15, 15, + 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 2, 2, 2, 21, 21, 21, 21, 21, 21, 21, + 7, 7, 7, 7, 7, 7, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 7, 7, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, + 7, 7, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 21, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, 15, + 9, 9, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 15, 15, 15, 15, 15, 15, + 7, 7, 7, 7, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 12, 12, 17, 2, 2, + 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 15, 15, 15, 15, 15, 15, 15, 7, 2, 2, 2, 2, 2, 2, 2, 2, + 12, 15, 15, 15, 15, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, + 10, 12, 10, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 21, 21, 2, 2, + 15, 15, 15, 15, 15, 15, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, + 10, 10, 10, 12, 12, 12, 12, 10, 10, 12, 12, 21, 21, 1, 21, 21, + 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, + 12, 12, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 10, 12, 12, 12, + 12, 12, 12, 12, 12, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 21, 21, 21, 21, 7, 10, 10, 7, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 12, 21, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 12, 10, + 10, 7, 7, 7, 7, 21, 21, 21, 21, 12, 12, 12, 12, 21, 10, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 7, 21, 7, 21, 21, 21, + 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 12, + 12, 12, 10, 10, 12, 10, 12, 12, 21, 21, 21, 21, 21, 21, 12, 2, + 7, 7, 7, 7, 7, 7, 7, 2, 7, 2, 7, 7, 7, 7, 2, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 21, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, + 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, + 12, 12, 10, 10, 2, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, + 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 2, 12, 12, 7, 10, 10, + 12, 10, 10, 10, 10, 2, 2, 10, 10, 2, 2, 10, 10, 10, 2, 2, + 7, 2, 2, 2, 2, 2, 2, 10, 2, 2, 2, 2, 2, 7, 7, 7, + 7, 7, 10, 10, 2, 2, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, + 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, + 10, 10, 12, 12, 12, 10, 12, 7, 7, 7, 7, 21, 21, 21, 21, 21, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 21, 21, 2, 21, 12, 7, + 10, 10, 10, 12, 12, 12, 12, 12, 12, 10, 12, 10, 10, 10, 10, 12, + 12, 10, 12, 12, 7, 7, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, + 10, 10, 12, 12, 12, 12, 2, 2, 10, 10, 10, 10, 12, 12, 10, 12, + 12, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 7, 7, 7, 7, 12, 12, 2, 2, + 10, 10, 10, 12, 12, 12, 12, 12, 12, 12, 12, 10, 10, 12, 10, 12, + 12, 21, 21, 21, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 10, 12, 10, 10, + 12, 12, 12, 12, 12, 12, 10, 12, 7, 2, 2, 2, 2, 2, 2, 2, + 10, 10, 12, 12, 12, 12, 10, 12, 12, 12, 12, 12, 2, 2, 2, 2, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 15, 21, 21, 21, 26, + 12, 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 2, 2, 2, 2, + 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7, + 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, 2, 2, 7, 7, 7, 7, + 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, + 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 2, 12, 12, 10, 12, 7, + 10, 7, 10, 12, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 7, 7, 7, 7, 7, 7, + 7, 10, 10, 10, 12, 12, 12, 12, 2, 2, 12, 12, 10, 10, 10, 10, + 12, 7, 21, 7, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 7, 7, 7, 7, 7, + 7, 7, 7, 12, 12, 12, 12, 12, 12, 10, 7, 12, 12, 12, 12, 21, + 21, 21, 21, 21, 21, 21, 21, 12, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 12, 12, 12, 12, 12, 12, 10, 10, 12, 12, 12, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 10, 12, 12, 21, 21, 21, 7, 21, 21, + 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 10, 12, + 7, 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 21, 21, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 2, 10, 12, 12, 12, 12, 12, 12, + 12, 10, 12, 12, 10, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, + 7, 12, 12, 12, 12, 12, 12, 2, 2, 2, 12, 2, 12, 12, 2, 12, + 12, 12, 12, 12, 12, 12, 7, 12, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 2, 7, 7, 2, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10, 2, + 12, 12, 2, 10, 10, 12, 10, 12, 7, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 12, 12, 10, 10, 21, 21, 2, 2, 2, 2, 2, 2, 2, + 15, 15, 15, 15, 15, 26, 26, 26, 26, 26, 26, 26, 26, 23, 23, 23, + 23, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 21, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, + 21, 21, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 12, 12, 12, 12, 12, 21, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 12, 12, 12, 12, 12, 12, 12, 21, 21, 21, 21, 21, 26, 26, 26, 26, + 6, 6, 6, 6, 21, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 15, 15, 15, 15, 15, + 15, 15, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 2, 7, 7, 7, + 15, 15, 15, 15, 15, 15, 15, 21, 21, 21, 21, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 2, 2, 12, + 7, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 12, + 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 21, 6, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 10, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 7, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 2, 26, 12, 12, 21, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 26, 26, 26, 26, 26, 2, 2, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 10, 10, 12, 12, 12, 26, 26, 26, 10, 10, 10, + 10, 10, 10, 1, 1, 1, 1, 1, 1, 1, 1, 12, 12, 12, 12, 12, + 12, 12, 12, 26, 26, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 12, 12, 12, 12, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 12, 12, 12, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, + 5, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 2, 9, 9, + 2, 2, 9, 2, 2, 9, 9, 2, 2, 9, 9, 9, 9, 2, 9, 9, + 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 2, 5, 2, 5, 5, 5, + 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 9, 9, 2, 9, 9, 9, 9, 2, 2, 9, 9, 9, + 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 2, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 2, 9, 9, 9, 9, 2, + 9, 9, 9, 9, 9, 2, 9, 2, 2, 2, 9, 9, 9, 9, 9, 9, + 9, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 2, 2, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, + 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 25, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 25, + 5, 5, 5, 5, 5, 5, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 25, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 25, 5, 5, 5, 5, 5, 5, 9, 5, 2, 2, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, 26, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 26, 26, 26, + 26, 26, 26, 26, 26, 12, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 12, 26, 26, 21, 21, 21, 21, 21, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12, + 12, 12, 2, 12, 12, 2, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, + 12, 12, 12, 12, 12, 12, 12, 6, 6, 6, 6, 6, 6, 6, 2, 2, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 7, 26, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 23, + 7, 7, 7, 7, 7, 2, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 5, 5, 5, 5, 12, 12, 12, 12, 12, 12, 12, 6, 2, 2, 2, 2, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15, 15, 15, + 23, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, + 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 2, 7, 7, 2, 7, 2, 2, 7, 2, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 2, 7, 2, 2, 2, 2, + 2, 2, 7, 2, 2, 2, 2, 7, 2, 7, 2, 7, 2, 7, 7, 7, + 2, 7, 7, 2, 7, 2, 2, 7, 2, 7, 2, 7, 2, 7, 2, 7, + 2, 7, 7, 2, 7, 2, 2, 7, 7, 7, 7, 2, 7, 7, 7, 7, + 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 7, 7, 7, 2, 7, 2, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, + 2, 7, 7, 7, 2, 7, 7, 7, 7, 7, 2, 7, 7, 7, 7, 7, + 25, 25, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, + 2, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 24, 24, 24, 24, 24, + 26, 26, 26, 26, 26, 26, 26, 26, 2, 2, 2, 2, 2, 2, 2, 2, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 2, 26, 26, 26, + 26, 26, 26, 26, 26, 2, 2, 2, 26, 26, 26, 2, 2, 2, 2, 2, + 26, 26, 26, 2, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 12, 12, 13, 14, 12, 15, 16, 17, 18, 19, 20, + 21, 22, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 24, 25, + 0, 26, 27, 0, 28, 29, 30, 31, 32, 33, 0, 34, 0, 0, 0, 0, + 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 38, 0, 0, 0, 0, + 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, + 43, 44, 45, 46, 0, 47, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 50, 0, 0, 0, + 0, 0, 0, 51, 0, 52, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 54, 55, 0, 0, 0, 0, 56, 0, 0, 57, 58, 0, + 59, 60, 61, 62, 63, 64, 65, 0, 66, 67, 0, 68, 69, 70, 71, 0, + 60, 0, 72, 73, 74, 75, 0, 0, 69, 0, 76, 77, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 78, 79, 0, 0, 0, 0, 0, 0, 0, 0, 80, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 82, 83, 84, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 85, 0, 79, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 87, 88, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 1, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 14, 15, 16, 17, 18, 19, 20, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 21, 0, 0, 0, 0, 0, 22, 23, 24, + 0, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 27, + 28, 29, 0, 0, 0, 0, 30, 0, 0, 0, 31, 32, 33, 34, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 13, 35, 36, 0, 0, 26, 37, 38, 39, 0, 0, 0, 0, 0, 40, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 1, + 42, 43, 44, 45, 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, 48, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 46, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 50, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 0, 47, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 54, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 56, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, 58, 59, 0, 0, 0, 0, + 0, 0, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 65, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 66, + 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 67, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 68, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 70, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 71, 72, 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 66, 74, 0, 0, 0, 0, 0, 0, 75, 76, 72, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 67, 0, 0, 0, + 0, 77, 78, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, + 80, 0, 79, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 81, 82, + 83, 84, 85, 86, 0, 0, 0, 0, 0, 0, 0, 0, 87, 88, 89, 1, + 1, 1, 90, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 92, 93, + 94, 95, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 71, 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 98, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 71,100,101, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 86, 0,102, 0, 0, 0, 0, 67, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, + 1, 1, 86, 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0,104, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,105, 0, 73, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,106,107,108, 0, 0, 0, + 0, 0,102, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 47, 0, 0, 0, 0, 0,109, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,110,111, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26,112, 0,113, 0, 0, 0, 0, 0,114, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 115, 0, 0, 0, 0, 0, 0, 0,100, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117,118, 72, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,102, 0, 0, 0, + 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0,119, 0, 0, 0, 0, + 0, 0, 0, 0,112, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, + 0, 0,105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 73,120, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,121, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,122, 0, 0, 0, 0, 0, 0, 0, 0, 0,123, 0, 47, 0, 0, + 26,124,124, 0, 0, 0, 0, 0, 0, 0, 0, 0,125, 0, 0, 49, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,126, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97,127, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,128, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,129,105, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 0, 0, 0, 0, 0, 0, 67, 0, 97, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,131, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,132, 0, 0, 0, 0, 0, 0, 0,133, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,134, 0, 0, 0, 0,135, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 136,137,138,139,140,141, 0, 0, 0,142, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,143, 0, 0, 0, + 0, 0, 0, 0,133, 1, 1,144,145,112, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,146, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,100,147, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230, + 230,230,230,230,230,230,230,230,230,232,220,220,220,220,232,216, + 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220, + 220,220,220,220,220,220,220,220, 1, 1, 1, 1, 1,220,220,220, + 220,230,230,230,230,230,230,230,230,240,230,220,220,220,230,230, + 230,220,220, 0,230,230,230,220,220,220,220,230,232,220,220,230, + 233,234,234,233,234,234,233,230,230,230,230,230, 0, 0, 0,230, + 230,230,230,230, 0,220,230,230,230,230,220,230,230,230,222,220, + 230,230,230,230,230,230,220,220,220,220,220,220,230,230,220,230, + 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, + 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, + 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230, + 230,220,220,230,230,230,230,230,220,230,230,220, 35, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,230, + 230, 0, 0,230,230,230,230,220,230, 0, 0,230,230, 0,220,230, + 230,220, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0,230,220,230,230, + 220,230,230,220,220,220,230,220,220,230,220,230,230,230,220,230, + 220,230,220,230,220,230,230, 0, 0, 0, 0, 0,230,230,220,230, + 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0, 0,230,230, 0,230, + 230,230,230,230,230,230,230,230, 0,230,230,230, 0,230,230,230, + 230,230, 0, 0, 0,220,220,220, 0, 0, 0, 0, 0, 0, 0,220, + 230,230,230,230,230,230, 0,220,230,230,220,230,230,220,230,230, + 230,220,220,220, 27, 28, 29,230,230,230,220,230,230,220,220,230, + 230,230,230,230, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0, 0, 0, + 0, 0,230, 0, 0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 9, + 9, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0,103,103, 9, 0, + 0, 0, 0, 0,107,107,107,107, 0, 0, 0, 0,118,118, 9, 0, + 0, 0, 0, 0,122,122,122,122, 0, 0, 0, 0,220,220, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,220, 0,220, 0,216, 0, 0, + 0, 0, 0, 0, 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130, + 130,130, 0, 0,130, 0,230,230, 9, 0,230,230, 0, 0, 0, 0, + 0, 0,220, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,230,230,230, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, 0,230, 0, 0, 0,228, 0, 0, + 0, 0, 0, 0, 0,222,230,220, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,230,220, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, + 0, 0, 0, 0,230,230,230,230,230, 0, 0,220,230,230,230,230, + 230,220,220,220,220,220,220,230,230,220, 0,220, 0, 0, 0,230, + 220,230,230,230,230,230,230,230, 0, 0, 0, 0, 0, 0, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0,230,230,230, 0, + 1,220,220,220,220,220,230,230,220,220,220,220,230, 0, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0,220, 0, 0, 0, 0, 0, 0, + 230, 0, 0, 0,230,230, 0, 0, 0, 0, 0, 0,230,230,220,230, + 230,230,230,230,230,230,220,230,230,234,214,220,202,230,230,230, + 230,230,230,230,230,230,230,230,230,230,232,228,228,220, 0,230, + 233,220,230,220,230,230, 1, 1,230,230,230,230, 1, 1, 1,230, + 230, 0, 0, 0, 0,230, 0, 0, 0, 1, 1,230,220,230, 1, 1, + 220,220,220,220,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 9, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 0,230,230,230,230,230,230,230,230, + 230,230, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0,220, + 220,220, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 7, + 0, 0, 0, 0,230, 0,230,230,220, 0, 0,230,230, 0, 0, 0, + 0, 0,230,230, 0,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 26, 0,230,230,230,230,230,230,230,220,220,220,220,220, + 220,220,230,230,230,230,230, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,220, 0,230,230, 1,220, 0, 0, 0, 0, 9, 0, 0, 0, 0, + 0,230,220, 0, 0, 0, 0,230,230, 0, 0, 0, 0, 0, 0, 0, + 0, 0,220,220,230,230,230,220,230,220,220,220, 0, 9, 7, 0, + 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 9, 7, 0, 0, 7, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, + 7, 0, 0, 0,230,230,230,230,230, 0, 0, 0, 0, 0, 9, 0, + 0, 0, 7, 0, 0, 0, 9, 7, 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, + 0, 9, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, + 9, 9, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0,230,230,230,230, + 230,230,230, 0, 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 0, 0,216,216, 1, 1, 1, 0, 0, + 0,226,216,216,216,216,216, 0, 0, 0, 0, 0, 0, 0, 0,220, + 220,220,220,220,220,220,220, 0, 0,230,230,230,230,230,220,220, + 0, 0, 0, 0, 0, 0,230,230,230,230, 0, 0, 0, 0,230,230, + 230, 0, 0, 0,230, 0, 0,230,230,230,230,230,230,230, 0,230, + 230, 0,230,230,220,220,220,220,220,220,220, 0,230,230, 7, 0, + 0, 0, 0, 0, 16, 17, 17, 17, 17, 17, 17, 33, 17, 17, 17, 19, + 17, 17, 17, 17, 20,101, 17,113,129,169, 17, 27, 28, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17,237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, + 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, + 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 7, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, + 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, + 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, + 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, + 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 20, + 20, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 21, 32, 4, 0, 10, 0, 33, 7, 20, 20, 20, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 8, 34, 34, 35, 36, 34, 37, 0, 38, 1, 20, 20, + 0, 0, 39, 0, 1, 1, 0, 8, 21, 1, 20, 0, 0, 0, 1, 0, + 0, 40, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 21, + 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, + 0, 0, 26, 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 7, 20, 41, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 21, 0, 42, 43, 44, 0, 45, + 0, 8, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 21, 0, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 3, 4, 0, 0, 0, 0, 0, 0, 3, 47, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, + 0, 0, 3, 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 12, 13, 14, 15, 16, 17, 18, 17, 19, 20, 21, 22, 23, 24, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 27, 28, 28, 29, 30, 31, 32, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, + 52, 53, 54, 55, 56, 57, 58, 35, 35, 35, 35, 35, 59, 59, 60, 35, + 35, 35, 35, 35, 35, 35, 61, 62, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 63, 64, 35, 65, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 67, 66, 68, 69, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 70, 71, 35, 35, + 35, 35, 72, 35, 35, 35, 35, 35, 35, 35, 35, 35, 73, 74, 75, 76, + 77, 78, 35, 35, 79, 80, 35, 35, 81, 35, 82, 83, 84, 85, 17, 86, + 87, 88, 35, 35, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 89, 25, 25, 25, 25, 25, 25, 25, 90, + 91, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 92, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 93, 35, 35, 35, 35, 35, 35, + 25, 94, 35, 35, 25, 25, 25, 25, 25, 25, 25, 25, 25, 95, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, + 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, 9, 9, 2, 2, + 9, 9, 9, 9, 0, 9, 2, 2, 2, 2, 9, 0, 9, 0, 9, 9, + 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 4, 4, 4, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, + 2, 2, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 2, 2, 2, 2, 14, 14, 14, 14, 14, 14, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, + 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 0, 3, 2, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 2, 2, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 2, 2, 64, 64, 64, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 2, 2, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, + 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 2, 2, 95, 2, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 2, 5, 5, 5, 5, 5, + 5, 5, 5, 2, 2, 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, + 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, + 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, + 2, 5, 5, 5, 5, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, + 2, 2, 5, 5, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 2, 2, 11, 11, 11, 2, 11, 11, 11, 11, 11, + 11, 2, 2, 2, 2, 11, 11, 2, 2, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, + 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11, + 2, 2, 11, 2, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, + 2, 11, 11, 11, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, + 11, 11, 11, 2, 11, 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 2, 10, 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, + 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10, + 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, + 2, 10, 10, 10, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 2, 2, 2, 2, 2, 2, 2, 10, + 10, 10, 10, 10, 10, 10, 2, 21, 21, 21, 2, 21, 21, 21, 21, 21, + 21, 21, 21, 2, 2, 21, 21, 2, 2, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, + 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21, + 2, 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, + 2, 21, 21, 21, 2, 2, 2, 2, 2, 2, 2, 21, 21, 21, 2, 2, + 2, 2, 21, 21, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, + 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, + 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22, + 22, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 2, 2, 2, 2, 22, 22, 22, 22, 22, 2, 2, 2, 22, 22, 22, 2, + 22, 22, 22, 22, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 2, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 2, 23, 23, 23, 2, + 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 2, 23, 23, + 23, 2, 2, 2, 2, 2, 23, 23, 23, 23, 2, 2, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 2, 16, 16, 16, 2, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, + 2, 2, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2, + 16, 16, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 16, 2, 2, 2, + 2, 2, 2, 2, 16, 2, 16, 16, 16, 16, 2, 2, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 2, 16, 16, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 2, 20, 20, 20, 2, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, + 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 2, 20, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 2, 36, 2, 2, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, + 36, 2, 2, 2, 2, 36, 36, 36, 36, 36, 36, 2, 36, 2, 36, 36, + 36, 36, 36, 36, 36, 36, 2, 2, 2, 2, 2, 2, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 2, 2, 36, 36, 36, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 2, 2, 2, 2, 0, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, + 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 2, 18, 2, 18, 18, + 18, 18, 18, 18, 2, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 2, 2, 18, 18, 18, 18, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 2, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 2, 2, 2, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 0, 0, 0, 0, 25, + 25, 2, 2, 2, 2, 2, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 8, 2, 2, + 2, 2, 2, 8, 2, 2, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2, + 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 2, + 30, 30, 30, 30, 2, 2, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, + 30, 30, 30, 30, 30, 2, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 2, 2, 2, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 2, 2, 2, 2, 2, 2, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 29, 29, + 29, 29, 29, 29, 2, 2, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 0, 0, 0, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 2, + 2, 2, 2, 2, 2, 2, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 2, 45, 45, 45, 45, 45, 45, 45, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 0, 0, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 2, 2, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 2, + 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 2, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, + 52, 52, 52, 52, 2, 2, 52, 52, 52, 52, 52, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 2, 2, 2, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 2, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 2, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 2, 2, 2, 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 2, 2, 2, 2, 2, 2, + 2, 2, 93, 93, 93, 93, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 2, 2, + 2, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 73, 6, 6, 6, 6, 6, 6, 6, 6, 6, 2, + 2, 2, 2, 2, 2, 2, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 2, 2, 8, 8, 8, 76, 76, 76, 76, 76, 76, 76, 76, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, + 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 9, 9, 9, 9, + 9, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 6, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, + 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, + 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 2, 9, 9, 9, 9, + 9, 9, 2, 9, 9, 9, 2, 2, 9, 9, 9, 2, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 2, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 2, 2, 2, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, + 19, 19, 0, 0, 0, 0, 0, 0, 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 56, 56, 56, 2, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 2, 2, 2, 2, 2, 55, + 55, 55, 55, 55, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, + 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 2, 2, + 2, 2, 2, 2, 2, 61, 61, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 61, 30, 30, 30, 30, 30, 30, 30, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, + 30, 30, 30, 30, 30, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 2, 2, 0, 0, 0, 0, 0, 13, 0, 13, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 1, 1, 1, 1, 12, 12, 0, 0, 0, 0, 0, 0, 0, 0, 13, 13, + 13, 13, 0, 0, 0, 0, 2, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 1, + 1, 0, 0, 15, 15, 15, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 2, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 0, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, + 39, 39, 39, 2, 2, 2, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, + 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, + 0, 19, 19, 19, 19, 19, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 60, 60, 60, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 2, 2, + 2, 2, 2, 2, 2, 2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, + 2, 2, 2, 2, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 2, 2, 2, 2, 2, 2, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, + 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 2, 2, 2, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 2, 0, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, + 33, 33, 33, 33, 33, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 68, 68, 68, 68, 2, 2, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, + 2, 2, 68, 68, 68, 68, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, 30, + 30, 30, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, 30, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, + 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 2, 2, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 12, 12, 12, 2, 2, 2, + 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 2, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 19, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, + 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 0, 0, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 0, 0, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2, + 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 12, 12, 12, 2, 2, + 12, 12, 12, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 2, 2, 9, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 2, 2, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, + 71, 71, 71, 2, 2, 2, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 42, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, + 41, 2, 2, 2, 2, 2,118,118,118,118,118,118,118,118,118,118, + 118,118,118,118,118,118,118,118,118,118,118,118,118,118,118,118, + 118, 2, 2, 2, 2, 2, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 53, 53, 2, 53, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 2, 2, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 2, 2, 2, 2, 2, 2,135,135,135,135,135,135,135,135,135,135, + 135,135,135,135,135,135,135,135,135,135, 2, 2, 2, 2,135,135, + 135,135,135,135,135,135,135,135,135,135,135,135,135,135,135,135, + 135,135, 2, 2, 2, 2,106,106,106,106,106,106,106,106,106,106, + 106,106,106,106,106,106,106,106,106,106,106,106,106,106, 2, 2, + 2, 2, 2, 2, 2, 2,104,104,104,104,104,104,104,104,104,104, + 104,104,104,104,104,104,104,104,104,104, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2,104,110,110,110,110,110,110,110,110,110,110, + 110,110,110,110,110,110,110,110,110,110,110,110,110, 2, 2, 2, + 2, 2, 2, 2, 2, 2,110,110,110,110,110,110, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,110,110,110,110,110,110,110,110, 2, 2, + 2, 2, 2, 2, 2, 2, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 2, 47, 47, 2, + 2, 2, 47, 2, 2, 47, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81, 81, 81, + 81, 81, 81, 81, 81, 81,120,120,120,120,120,120,120,120,120,120, + 120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116, + 116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116, + 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,116,116, + 116,116,116,116,116,116,128,128,128,128,128,128,128,128,128,128, + 128,128,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2, + 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, + 98, 98, 98, 98, 98, 98, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 2, 2, + 2, 2, 97, 97, 97, 97, 2, 2, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2, + 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, 2, 57, 57, + 57, 2, 2, 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 2, + 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, + 88, 88, 88, 88, 88, 88,117,117,117,117,117,117,117,117,117,117, + 117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112, + 112,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2, + 2,112,112,112,112,112,112,112,112,112,112,112,112, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78, + 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, 2, 2, 83, 83, + 83, 83, 83, 83, 83, 83, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 82, 82, 82, 82, 82, 82, 82, 82, 2, 2, 2, 2, 2, 82, 82, + 82, 82, 82, 82, 82, 82,122,122,122,122,122,122,122,122,122,122, + 122,122,122,122,122,122,122,122, 2, 2, 2, 2, 2, 2, 2,122, + 122,122,122, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,122, + 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2, + 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130, + 130,130,130,130,130,130,130,130,130, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,130,130,130, 2, 2, 2, 2, 2, 2, 2, + 130,130,130,130,130,130,144,144,144,144,144,144,144,144,144,144, + 144,144,144,144,144,144,144,144,144,144,144,144,144,144, 2, 2, + 2, 2, 2, 2, 2, 2,144,144,144,144,144,144,144,144,144,144, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 2,156,156,156,156,156,156,156,156,156,156, + 156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156, + 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,147,147,147,147,147,147,147,147,147,147, + 147,147,147,147,147,147,147,147,147,147,147,147,147,147, 2, 2, + 2, 2, 2, 2, 2, 2,148,148,148,148,148,148,148,148,148,148, + 148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148, + 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153, + 153,153,153,153,153,153,153,153,153,153,153,153,153,153,153,153, + 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149, + 149,149,149,149,149,149,149,149,149,149,149,149,149, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 85, 85, 85, 85, 85, 85, 85, 85, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 85, 2, 2,101,101,101,101,101,101,101,101,101,101, + 101,101,101,101,101,101,101,101,101,101,101,101,101,101,101, 2, + 2, 2, 2, 2, 2, 2,101,101,101,101,101,101,101,101,101,101, + 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 96, 96, 96, 96, + 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 2, 2, + 2, 2, 2, 2, 2, 2,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111, 2, 2, 2, + 2, 2, 2, 2, 2, 2,100,100,100,100,100,100,100,100,100,100, + 100,100,100,100,100,100, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,108,108,108,108,108,108,108,108,108,108, + 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108, + 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, + 108,108,108,108,108, 2,129,129,129,129,129,129,129, 2,129, 2, + 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129, + 2, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109, + 109,109,109,109,109,109,109,109,109,109,109,109,109,109,109,109, + 109, 2, 2, 2, 2, 2,109,109,109,109,109,109,109,109,109,109, + 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107, + 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107, + 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, 2, + 107,107,107,107,107,107,107, 2,107,107, 2,107,107,107,107,107, + 2, 1,107,107,107,107,107,107,107,107,107, 2, 2,107,107, 2, + 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, + 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107, + 107,107,107, 2, 2, 2,107,107,107,107,107, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,137,137,137,137,137,137,137,137,137,137, + 137,137,137,137,137,137,137,137,137,137,137,137,137,137,137,137, + 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124, + 124,124,124,124,124,124,124,124,124,124,124,124,124,124, 2, 2, + 2, 2, 2, 2, 2, 2,124,124,124,124,124,124,124,124,124,124, + 2, 2, 2, 2, 2, 2,123,123,123,123,123,123,123,123,123,123, + 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,123,123, + 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, + 123,123,123,123, 2, 2,114,114,114,114,114,114,114,114,114,114, + 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,114,114,114,114,114,114,114,114,114,114, + 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 2, 2, 2,102,102,102,102,102,102,102,102,102,102, + 102,102,102,102,102,102,102,102,102,102,102,102,102,102,102, 2, + 2, 2, 2, 2, 2, 2,102,102,102,102,102,102,102,102,102,102, + 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126, + 126,126,126,126,126,126,126,126,126,126,126,126,126,126,126,126, + 126, 2, 2,126,126,126,126,126,126,126,126,126,126,126,126,126, + 126,126, 2, 2, 2, 2,142,142,142,142,142,142,142,142,142,142, + 142,142,142,142,142,142,142,142,142,142,142,142,142,142,142,142, + 142,142, 2, 2, 2, 2,125,125,125,125,125,125,125,125,125,125, + 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154, + 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154, + 154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, + 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2, + 2,154,154,154,154,154,154,154,154,154,154,154,154, 2, 2, 2, + 2, 2, 2, 2, 2, 2,154,154,154,154,154,154,154,154,154,154, + 2, 2, 2, 2, 2, 2,150,150,150,150,150,150,150,150, 2, 2, + 150,150,150,150,150,150,150,150,150,150,150,150,150,150,150,150, + 150,150,150,150,150,150,150,150,150,150,150, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,141,141,141,141,141,141,141,141,141,141, + 141,141,141,141,141,141,141,141,141,141,141,141,141,141, 2, 2, + 2, 2, 2, 2, 2, 2,140,140,140,140,140,140,140,140,140,140, + 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,121,121,121,121,121,121,121,121,121,121, + 121,121,121,121,121,121,121,121,121,121,121,121,121,121,121, 2, + 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133, 2, + 133,133,133,133,133,133,133,133,133,133,133,133,133,133,133,133, + 133,133,133,133,133,133,133,133,133,133,133,133,133, 2,133,133, + 133,133,133,133,133,133,133,133,133,133,133,133, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,133,133,133,133,133,133,133,133,133,133, + 133,133,133, 2, 2, 2,134,134,134,134,134,134,134,134,134,134, + 134,134,134,134,134,134, 2, 2,134,134,134,134,134,134,134,134, + 134,134,134,134,134,134,134,134,134,134,134,134,134,134, 2,134, + 134,134,134,134,134,134,134,134,134,134,134,134,134, 2, 2, 2, + 2, 2, 2, 2, 2, 2,138,138,138,138,138,138,138, 2,138,138, + 2,138,138,138,138,138,138,138,138,138,138,138,138,138,138,138, + 138,138,138,138,138,138,138,138,138,138,138,138,138, 2, 2, 2, + 138, 2,138,138, 2,138,138,138,138,138,138,138,138,138, 2, 2, + 2, 2, 2, 2, 2, 2,138,138,138,138,138,138,138,138,138,138, + 2, 2, 2, 2, 2, 2,143,143,143,143,143,143, 2,143,143, 2, + 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, + 143,143,143,143,143,143,143,143,143,143,143,143,143,143,143,143, + 143,143,143,143,143, 2,143,143, 2,143,143,143,143,143,143, 2, + 2, 2, 2, 2, 2, 2,143,143,143,143,143,143,143,143,143,143, + 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145,145, + 145,145,145,145,145,145,145,145,145,145,145,145,145,145,145, 2, + 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 22, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 2, + 2, 2, 2, 2, 2, 2,127,127,127,127,127,127,127,127,127,127, + 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 79, 79, 79, 79, 79, 79, 79, 79, 79, 2, + 2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115, + 115,115,115,115,115,115,115,115,115,115,115,115,115,115,115,115, + 115,115,115,115,115, 2,115,115,115,115,115,115,115,115,115,115, + 2, 2, 2, 2,115,115,103,103,103,103,103,103,103,103,103,103, + 103,103,103,103,103,103,103,103,103,103,103,103,103,103,103,103, + 103,103,103,103, 2, 2,103,103,103,103,103,103, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,119,119,119,119,119,119,119,119,119,119, + 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,119,119,119,119,119,119,119,119,119,119, + 2,119,119,119,119,119,119,119, 2,119,119,119,119,119,119,119, + 119,119,119,119,119,119,119,119,119,119,119,119,119,119, 2, 2, + 2, 2, 2,119,119,119,146,146,146,146,146,146,146,146,146,146, + 146,146,146,146,146,146,146,146,146,146,146,146,146,146,146,146, + 146, 2, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 99, 2, 2, 2, 2, 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, + 2, 2, 2, 2, 2, 99,136,139, 0, 0,155, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,136,136,136,136,136,136,136,136,136,136, + 136,136,136,136,136,136,136,136,136,136,136,136,136,136, 2, 2, + 2, 2, 2, 2, 2, 2,155,155,155,155,155,155,155,155,155,155, + 155,155,155,155,155,155,155,155,155,155,155,155, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2,136,136,136,136,136,136,136,136,136, 2, + 2, 2, 2, 2, 2, 2, 17, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 2, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 17, 17, 17, 17, 2, 2, + 2, 2, 2, 2, 2, 2,139,139,139,139,139,139,139,139,139,139, + 139,139,139,139,139,139,139,139,139,139,139,139,139,139,139,139, + 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, + 105,105,105,105,105,105,105,105,105,105,105,105,105,105,105,105, + 105, 2, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, + 105,105,105, 2, 2, 2,105,105,105,105,105,105,105,105,105, 2, + 2, 2, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, + 2, 2,105,105,105,105, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 9, 9, 9, 9, 9, 9, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 2, 2, 0, 2, 2, 0, 0, 2, 2, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, + 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 0, 0,131,131,131,131,131,131,131,131,131,131, + 131,131,131,131,131,131,131,131,131,131,131,131,131,131,131,131, + 131,131, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2,131,131,131,131,131, 2,131,131,131,131,131,131,131,131,131, + 131,131,131,131,131,131, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 2, + 2, 56, 56, 56, 56, 56, 56, 56, 2, 56, 56, 2, 56, 56, 56, 56, + 56, 2, 2, 2, 2, 2,151,151,151,151,151,151,151,151,151,151, + 151,151,151,151,151,151,151,151,151,151,151,151,151,151,151,151, + 151,151,151, 2, 2, 2,151,151,151,151,151,151,151,151,151,151, + 151,151,151,151, 2, 2,151,151,151,151,151,151,151,151,151,151, + 2, 2, 2, 2,151,151,152,152,152,152,152,152,152,152,152,152, + 152,152,152,152,152,152,152,152,152,152,152,152,152,152,152,152, + 2, 2, 2, 2, 2,152,113,113,113,113,113,113,113,113,113,113, + 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113, + 113,113,113,113,113,113,113,113,113,113,113,113,113, 2, 2, 2, + 2, 2, 2, 2, 2, 2,132,132,132,132,132,132,132,132,132,132, + 132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132, + 132,132, 2, 2, 2, 2,132,132,132,132,132,132,132,132,132,132, + 2, 2, 2, 2,132,132, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2, 2, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, + 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, + 2, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, 3, 2, 2, 3, 3, 3, + 3, 2, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, + 3, 3, 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 3, 3, + 2, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 0, 0, + 0, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 1, 2, 3, 4, 5, 6, 0, + 0, 0, 0, 7, 8, 9, 10, 11, 0, 12, 0, 0, 0, 0, 13, 0, + 0, 14, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 0, 17, 18, 19, + 0, 0, 0, 20, 21, 22, 0, 23, 0, 24, 0, 25, 0, 26, 0, 0, + 0, 0, 0, 27, 28, 0, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 0, 0, 0, 41, 0, 42, 43, 44, 45, + 46, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 50, 51, 52, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 65, 0, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 69, 70, 71, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 72, 73, 74, 75, 76, 77, 78, 79, 80, 0, +}; +static const uint16_t +_hb_ucd_u16[11328] = +{ + 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, + 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, + 13, 13, 13, 24, 25, 11, 11, 11, 11, 26, 11, 27, 28, 29, 30, 31, + 32, 32, 32, 32, 32, 32, 32, 33, 34, 35, 36, 11, 37, 38, 13, 39, + 9, 9, 9, 11, 11, 11, 13, 13, 40, 13, 13, 13, 41, 13, 13, 13, + 13, 13, 13, 42, 9, 43, 11, 11, 44, 45, 32, 46, 47, 48, 49, 50, + 51, 52, 48, 48, 53, 32, 54, 55, 48, 48, 48, 48, 48, 56, 57, 58, + 59, 60, 48, 32, 61, 48, 48, 48, 48, 48, 62, 63, 64, 48, 65, 66, + 48, 67, 68, 69, 48, 70, 71, 72, 72, 72, 48, 73, 74, 75, 76, 32, + 77, 48, 48, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 84, 85, 92, 93, 94, 95, 96, 97, 98, 85, 99, 100, 101, 89, 102, + 103, 84, 85, 104, 105, 106, 89, 107, 108, 109, 110, 111, 112, 113, 95, 114, + 115, 116, 85, 117, 118, 119, 89, 120, 121, 116, 85, 122, 123, 124, 89, 125, + 126, 116, 48, 127, 128, 129, 89, 130, 131, 132, 48, 133, 134, 135, 95, 136, + 137, 48, 48, 138, 139, 140, 72, 72, 141, 48, 142, 143, 144, 145, 72, 72, + 146, 147, 148, 149, 150, 48, 151, 152, 153, 154, 32, 155, 156, 157, 72, 72, + 48, 48, 158, 159, 160, 161, 162, 163, 164, 165, 9, 9, 166, 11, 11, 167, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 168, 169, 48, 48, 168, 48, 48, 170, 171, 172, 48, 48, + 48, 171, 48, 48, 48, 173, 174, 175, 48, 176, 9, 9, 9, 9, 9, 177, + 178, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 179, 48, 180, 181, 48, 48, 48, 48, 182, 183, + 184, 185, 48, 186, 48, 187, 184, 188, 48, 48, 48, 189, 190, 191, 192, 193, + 194, 192, 48, 48, 195, 48, 48, 196, 197, 48, 198, 48, 48, 48, 48, 199, + 48, 200, 201, 202, 203, 48, 204, 205, 48, 48, 206, 48, 207, 208, 209, 209, + 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 216, 72, 72, 72, + 217, 48, 48, 218, 219, 160, 220, 221, 222, 48, 223, 64, 48, 48, 224, 225, + 48, 48, 226, 227, 228, 64, 48, 229, 230, 9, 9, 231, 232, 233, 234, 235, + 11, 11, 236, 27, 27, 27, 237, 238, 11, 239, 27, 27, 32, 32, 32, 240, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 241, 13, 13, 13, 13, 13, 13, + 242, 243, 242, 242, 243, 244, 242, 245, 246, 246, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 262, 72, 263, 264, 216, + 265, 266, 267, 268, 269, 270, 271, 271, 272, 273, 274, 209, 275, 276, 209, 277, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 279, 209, 280, 209, 209, 209, 209, 281, 209, 282, 278, 283, 209, 284, 285, 209, + 209, 209, 286, 72, 287, 72, 270, 270, 270, 288, 209, 209, 209, 209, 289, 270, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 290, 291, 209, 209, 292, + 209, 209, 209, 209, 209, 209, 293, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 294, 295, 270, 296, 209, 209, 297, 278, 298, 278, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 278, 278, 278, 278, 278, 278, 278, 278, 299, 300, 278, 278, 278, 301, 278, 302, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 209, 209, 209, 278, 303, 209, 209, 304, 209, 305, 209, 209, 209, 209, 209, 209, + 9, 9, 306, 11, 11, 307, 308, 309, 13, 13, 13, 13, 13, 13, 310, 311, + 11, 11, 312, 48, 48, 48, 313, 314, 48, 315, 316, 316, 316, 316, 32, 32, + 317, 318, 319, 320, 321, 322, 72, 72, 209, 323, 209, 209, 209, 209, 209, 324, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 325, 72, 326, + 327, 328, 329, 330, 137, 48, 48, 48, 48, 331, 178, 48, 48, 48, 48, 332, + 333, 48, 48, 137, 48, 48, 48, 48, 200, 334, 48, 48, 209, 209, 324, 48, + 209, 335, 336, 209, 337, 338, 209, 209, 336, 209, 209, 338, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 209, 209, 209, 209, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 151, + 48, 339, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 286, 48, 48, 229, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 340, 48, 341, 72, 13, 13, 342, 343, 13, 344, 48, 48, 48, 48, 345, 346, + 31, 347, 348, 349, 13, 13, 13, 350, 351, 352, 353, 354, 355, 72, 72, 356, + 357, 48, 358, 359, 48, 48, 48, 360, 361, 48, 48, 362, 363, 192, 32, 364, + 64, 48, 365, 48, 366, 367, 48, 151, 77, 48, 48, 368, 369, 370, 371, 372, + 48, 48, 373, 374, 375, 376, 48, 377, 48, 48, 48, 378, 379, 380, 381, 382, + 383, 384, 316, 11, 11, 385, 386, 11, 11, 11, 11, 11, 48, 48, 387, 192, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 388, 48, 389, 48, 48, 206, + 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, + 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, 390, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, 207, 72, 72, + 392, 393, 394, 395, 396, 48, 48, 48, 48, 48, 48, 397, 398, 399, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 400, 72, 48, 48, 48, 48, 401, 48, 48, 74, 72, 72, 402, + 32, 403, 32, 404, 405, 406, 407, 73, 48, 48, 48, 48, 48, 48, 48, 408, + 409, 2, 3, 4, 5, 410, 411, 412, 48, 413, 48, 200, 414, 415, 416, 417, + 418, 48, 172, 419, 204, 204, 72, 72, 48, 48, 48, 48, 48, 48, 48, 71, + 420, 270, 270, 421, 271, 271, 271, 422, 423, 424, 425, 72, 72, 209, 209, 426, + 72, 72, 72, 72, 72, 72, 72, 72, 48, 151, 48, 48, 48, 101, 427, 428, + 48, 48, 429, 48, 430, 48, 48, 431, 48, 432, 48, 48, 433, 434, 72, 72, + 9, 9, 435, 11, 11, 48, 48, 48, 48, 204, 192, 9, 9, 436, 11, 437, + 48, 48, 74, 48, 48, 48, 438, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 315, 48, 199, 74, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 439, 48, 48, 440, 48, 441, 48, 442, 48, 200, 443, 72, 72, 72, 48, 444, + 48, 445, 48, 446, 72, 72, 72, 72, 48, 48, 48, 447, 270, 448, 270, 270, + 449, 450, 48, 451, 452, 453, 48, 454, 48, 455, 72, 72, 456, 48, 457, 458, + 48, 48, 48, 459, 48, 460, 48, 461, 48, 462, 463, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 196, 72, 72, 72, 9, 9, 9, 464, 11, 11, 11, 465, + 48, 48, 466, 192, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 270, 467, 48, 48, 468, 469, 72, 72, 72, 72, + 48, 455, 470, 48, 62, 471, 72, 72, 72, 72, 72, 48, 472, 72, 48, 315, + 473, 48, 48, 474, 475, 448, 476, 477, 222, 48, 48, 478, 479, 48, 196, 192, + 480, 48, 481, 482, 483, 48, 48, 484, 222, 48, 48, 485, 486, 487, 488, 489, + 48, 98, 490, 491, 72, 72, 72, 72, 492, 493, 494, 48, 48, 495, 496, 192, + 497, 84, 85, 498, 499, 500, 501, 502, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 503, 504, 505, 469, 72, 48, 48, 48, 506, 507, 192, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 48, 48, 508, 509, 510, 511, 72, 72, + 48, 48, 48, 512, 513, 192, 514, 72, 48, 48, 515, 516, 192, 72, 72, 72, + 48, 173, 517, 518, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 490, 519, 72, 72, 72, 72, 72, 72, 9, 9, 11, 11, 148, 520, + 521, 522, 48, 523, 524, 192, 72, 72, 72, 72, 525, 48, 48, 526, 527, 72, + 528, 48, 48, 529, 530, 531, 48, 48, 532, 533, 534, 72, 48, 48, 48, 196, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 85, 48, 508, 535, 536, 148, 175, 537, 48, 538, 539, 540, 72, 72, 72, 72, + 541, 48, 48, 542, 543, 192, 544, 48, 545, 546, 192, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 547, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 101, 270, 548, 549, 550, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 207, 72, 72, 72, 72, 72, 72, + 271, 271, 271, 271, 271, 271, 551, 552, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 388, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 200, 553, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 315, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 196, 48, 200, 370, 72, 72, 72, 72, 72, 72, 48, 204, 554, + 48, 48, 48, 555, 556, 557, 558, 559, 48, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 9, 9, 11, 11, 270, 560, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 561, 562, 563, 563, 564, 565, 72, 72, 72, 72, 566, 567, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 74, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 199, 72, 72, + 196, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 200, 72, 72, 72, 568, 569, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 206, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 71, 151, 196, 570, 571, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 325, + 209, 209, 572, 209, 209, 209, 573, 574, 575, 209, 576, 209, 209, 209, 577, 72, + 209, 209, 209, 209, 578, 72, 72, 72, 72, 72, 72, 72, 72, 72, 270, 579, + 209, 209, 209, 209, 209, 286, 270, 452, 72, 72, 72, 72, 72, 72, 72, 72, + 9, 580, 11, 581, 582, 583, 242, 9, 584, 585, 586, 587, 588, 9, 580, 11, + 589, 590, 11, 591, 592, 593, 594, 9, 595, 11, 9, 580, 11, 581, 582, 11, + 242, 9, 584, 594, 9, 595, 11, 9, 580, 11, 596, 9, 597, 598, 599, 600, + 11, 601, 9, 602, 603, 604, 605, 11, 606, 9, 607, 11, 608, 609, 609, 609, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, + 32, 32, 32, 610, 32, 32, 611, 612, 613, 614, 45, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 615, 616, 617, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 151, 618, 619, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 48, 620, 621, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 622, 623, 72, 72, + 9, 9, 584, 11, 624, 370, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 488, 270, 270, 625, 626, 72, 72, 72, 72, + 488, 270, 627, 628, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 629, 48, 630, 631, 632, 633, 634, 635, 636, 206, 637, 206, 72, 72, 72, 638, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 209, 209, 326, 209, 209, 209, 209, 209, 209, 324, 335, 639, 639, 639, 209, 325, + 640, 209, 209, 209, 209, 209, 209, 209, 209, 209, 641, 72, 72, 72, 642, 209, + 643, 209, 209, 326, 577, 644, 325, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 645, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 646, 424, 424, + 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 209, 209, 209, 577, 326, 72, + 326, 209, 209, 209, 646, 176, 209, 209, 646, 209, 641, 644, 72, 72, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 647, 209, 209, 209, 209, 648, 209, 209, 209, + 209, 209, 209, 209, 209, 324, 641, 649, 286, 209, 577, 286, 643, 286, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 209, 209, 650, 209, 209, 287, 72, 72, 192, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 204, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 205, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 204, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 469, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 101, 72, + 48, 204, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 71, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 651, 72, 652, 652, 652, 652, 652, 652, 72, 72, 72, 72, 72, 72, 72, 72, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 72, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 653, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, + 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 391, 654, + 0, 0, 0, 0, 1, 2, 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 0, 0, 7, 0, + 8, 8, 8, 8, 8, 8, 8, 9, 10, 11, 12, 11, 11, 11, 13, 11, + 14, 14, 14, 14, 14, 14, 14, 14, 15, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 16, 17, 18, 17, 17, 19, 20, 21, 21, 22, 21, 23, 24, + 25, 26, 27, 27, 28, 29, 27, 30, 27, 27, 27, 27, 27, 31, 27, 27, + 32, 33, 33, 33, 34, 27, 27, 27, 35, 35, 35, 36, 37, 37, 37, 38, + 39, 39, 40, 41, 42, 43, 44, 45, 45, 45, 27, 46, 47, 48, 49, 27, + 50, 50, 50, 50, 50, 51, 52, 50, 53, 54, 55, 56, 57, 58, 59, 60, + 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, + 109, 110, 111, 111, 112, 113, 114, 111, 115, 116, 117, 118, 119, 120, 121, 122, + 123, 124, 124, 125, 124, 126, 45, 45, 127, 128, 129, 130, 131, 132, 45, 45, + 133, 133, 133, 133, 134, 133, 135, 136, 133, 134, 133, 137, 137, 138, 45, 45, + 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 140, 140, 141, 140, 140, 142, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 144, 144, 144, 144, 145, 146, 144, 144, 145, 144, 144, 147, 148, 149, 144, 144, + 144, 148, 144, 144, 144, 150, 144, 151, 144, 152, 153, 153, 153, 153, 153, 154, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, 155, + 155, 155, 155, 155, 155, 155, 155, 155, 156, 157, 158, 158, 158, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, 169, 169, 169, 169, 169, 170, 171, 171, + 172, 173, 174, 174, 174, 174, 174, 175, 174, 174, 176, 155, 155, 155, 155, 177, + 178, 179, 180, 180, 181, 182, 183, 184, 185, 185, 186, 185, 187, 188, 169, 169, + 189, 190, 191, 191, 191, 192, 191, 193, 194, 194, 195, 8, 196, 45, 45, 45, + 197, 197, 197, 197, 198, 197, 197, 199, 200, 200, 200, 200, 201, 201, 201, 202, + 203, 203, 203, 204, 205, 206, 206, 206, 207, 140, 140, 208, 209, 210, 211, 212, + 4, 4, 213, 4, 4, 214, 215, 216, 4, 4, 4, 217, 8, 8, 8, 218, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 11, 219, 11, 11, 219, 220, 11, 221, 11, 11, 11, 222, 222, 223, 11, 224, + 225, 0, 0, 0, 0, 0, 226, 227, 228, 229, 0, 0, 45, 8, 8, 196, + 0, 0, 230, 231, 232, 0, 4, 4, 233, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 234, 45, 235, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 237, 0, 238, 0, 0, 0, 0, 0, 0, + 239, 239, 240, 239, 239, 240, 4, 4, 241, 241, 241, 241, 241, 241, 241, 242, + 140, 140, 141, 243, 243, 243, 244, 245, 144, 246, 247, 247, 247, 247, 14, 14, + 0, 0, 0, 0, 0, 248, 45, 45, 249, 250, 249, 249, 249, 249, 249, 251, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 252, 45, 253, + 254, 0, 255, 256, 257, 258, 258, 258, 258, 259, 260, 261, 261, 261, 261, 262, + 263, 264, 264, 265, 143, 143, 143, 143, 266, 0, 264, 264, 0, 0, 267, 261, + 143, 266, 0, 0, 0, 0, 143, 268, 0, 0, 0, 0, 0, 261, 261, 269, + 261, 261, 261, 261, 261, 270, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 0, 0, 0, 0, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 271, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, 272, + 272, 272, 272, 272, 272, 272, 272, 272, 273, 272, 272, 272, 274, 275, 275, 275, + 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, + 276, 276, 277, 45, 14, 14, 14, 14, 14, 14, 278, 278, 278, 278, 278, 279, + 0, 0, 280, 4, 4, 4, 4, 4, 281, 4, 4, 4, 282, 45, 45, 283, + 284, 284, 285, 286, 287, 287, 287, 288, 289, 289, 289, 289, 290, 291, 50, 50, + 292, 292, 293, 294, 294, 295, 143, 296, 297, 297, 297, 297, 298, 299, 139, 300, + 301, 301, 301, 302, 303, 304, 139, 139, 305, 305, 305, 305, 306, 307, 308, 309, + 310, 311, 247, 4, 4, 312, 313, 153, 153, 153, 153, 153, 308, 308, 314, 315, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 143, 143, 143, 143, 143, 316, 143, 317, 143, 143, 318, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 319, 249, 249, 249, 249, 249, 249, 320, 45, 45, + 321, 322, 21, 323, 324, 27, 27, 27, 27, 27, 27, 27, 325, 48, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 326, 45, 27, 27, 27, 27, 327, 27, 27, 47, 45, 45, 328, + 8, 286, 329, 0, 0, 330, 331, 46, 27, 27, 27, 27, 27, 27, 27, 332, + 333, 0, 1, 2, 1, 2, 334, 260, 261, 335, 143, 266, 336, 337, 338, 339, + 340, 341, 342, 343, 344, 344, 45, 45, 341, 341, 341, 341, 341, 341, 341, 345, + 346, 0, 0, 347, 11, 11, 11, 11, 348, 349, 350, 45, 45, 0, 0, 351, + 45, 45, 45, 45, 45, 45, 45, 45, 352, 353, 354, 354, 354, 355, 356, 253, + 357, 357, 358, 359, 360, 361, 361, 362, 363, 364, 365, 365, 366, 367, 45, 45, + 368, 368, 368, 368, 368, 369, 369, 369, 370, 371, 372, 373, 373, 374, 373, 375, + 376, 376, 377, 378, 378, 378, 379, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, 380, + 380, 380, 380, 381, 380, 382, 383, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 384, 385, 385, 386, 387, 388, 389, 389, 390, 391, 392, 45, 45, 45, 393, 394, + 395, 396, 397, 398, 45, 45, 45, 45, 399, 399, 400, 401, 400, 402, 400, 400, + 403, 404, 405, 406, 407, 407, 408, 408, 409, 409, 45, 45, 410, 410, 411, 412, + 413, 413, 413, 414, 415, 416, 417, 418, 419, 420, 421, 45, 45, 45, 45, 45, + 422, 422, 422, 422, 423, 45, 45, 45, 424, 424, 424, 425, 424, 424, 424, 426, + 427, 427, 428, 429, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 27, 430, 431, 431, 432, 433, 45, 45, 45, 45, + 434, 434, 435, 436, 436, 437, 45, 45, 45, 45, 45, 438, 439, 45, 440, 441, + 442, 442, 442, 442, 443, 444, 442, 445, 446, 446, 446, 446, 447, 448, 449, 450, + 451, 451, 451, 452, 453, 454, 454, 455, 456, 456, 456, 456, 456, 456, 457, 458, + 459, 460, 459, 461, 45, 45, 45, 45, 462, 463, 464, 465, 465, 465, 466, 467, + 468, 469, 470, 471, 472, 473, 474, 475, 45, 45, 45, 45, 45, 45, 45, 45, + 476, 476, 476, 476, 476, 477, 478, 45, 479, 479, 479, 479, 480, 481, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 482, 482, 482, 483, 482, 484, 45, 45, + 485, 485, 485, 485, 486, 487, 488, 45, 489, 489, 489, 490, 491, 45, 45, 45, + 492, 493, 494, 492, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 495, 495, 495, 496, 45, 45, 45, 45, 45, 45, 497, 497, 497, 497, 497, 498, + 499, 500, 501, 502, 503, 504, 45, 45, 45, 45, 505, 506, 506, 505, 507, 45, + 508, 508, 508, 508, 509, 510, 510, 510, 510, 510, 511, 45, 512, 512, 512, 513, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 514, 515, 515, 516, 517, 515, 518, 519, 519, 520, 521, 522, 45, 45, 45, 45, + 523, 524, 524, 525, 526, 527, 528, 529, 530, 531, 532, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 533, 534, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 535, 536, 536, 536, 537, + 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, + 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, + 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, 538, + 538, 538, 538, 538, 538, 538, 538, 538, 538, 539, 45, 45, 45, 45, 45, 45, + 538, 538, 538, 538, 538, 538, 540, 541, 538, 538, 538, 538, 538, 538, 538, 538, + 538, 538, 538, 538, 542, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, + 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, 543, + 543, 543, 544, 545, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, + 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, + 546, 546, 546, 546, 547, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 548, 549, 550, 551, 45, 45, 45, 45, 45, 45, 552, 553, 554, + 555, 555, 555, 555, 556, 557, 558, 559, 555, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 560, 560, 560, 560, 560, 561, 45, 45, 45, 45, 45, 45, + 562, 562, 562, 562, 563, 562, 562, 562, 564, 562, 45, 45, 45, 45, 565, 566, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 568, + 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, 567, + 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, + 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 569, 570, 45, 45, + 571, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 572, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, 258, + 258, 573, 45, 45, 45, 574, 575, 576, 576, 576, 576, 576, 576, 576, 576, 576, + 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 577, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 578, 578, 578, 578, 578, 578, 579, 580, 581, 582, 267, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 583, + 0, 0, 584, 0, 0, 0, 585, 586, 587, 0, 588, 0, 0, 0, 589, 45, + 11, 11, 11, 11, 590, 45, 45, 45, 45, 45, 45, 45, 45, 45, 0, 267, + 0, 0, 0, 0, 0, 234, 0, 589, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 226, 0, 0, 0, 591, 592, 593, 594, 0, 0, 0, + 595, 596, 0, 597, 598, 599, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 600, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 601, 0, 0, 0, + 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, + 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, + 602, 602, 602, 602, 602, 602, 602, 602, 603, 604, 605, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 606, 607, 608, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 609, 609, 610, 611, 612, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 613, 613, 613, 614, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 615, 616, 617, 45, 45, + 618, 618, 618, 618, 619, 620, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 333, 0, 0, 0, 621, 45, 45, 45, 45, + 333, 0, 0, 622, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 623, 27, 624, 625, 626, 627, 628, 629, 630, 631, 632, 631, 45, 45, 45, 325, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 253, 0, 0, 0, 0, 0, 0, 267, 228, 333, 333, 333, 0, 583, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 622, 45, 45, 45, 633, 0, + 634, 0, 0, 253, 589, 635, 583, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 636, 349, 349, + 0, 0, 0, 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, 589, 253, 45, + 253, 0, 0, 0, 636, 286, 0, 0, 636, 0, 622, 635, 45, 45, 45, 45, + 0, 0, 0, 0, 0, 0, 0, 637, 0, 0, 0, 0, 638, 0, 0, 0, + 0, 0, 0, 0, 0, 267, 622, 639, 234, 0, 589, 234, 248, 234, 45, 45, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 235, 45, 45, 286, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 319, 45, 45, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 640, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 319, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 566, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 641, 45, + 249, 319, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, + 249, 249, 249, 249, 642, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 643, 45, 0, 0, 0, 0, 0, 0, 45, 45, 45, 45, 45, 45, 45, 45, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, + 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, + 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, + 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, + 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, + 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, + 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199, + 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, + 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231, + 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258, + 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275, + 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093, + 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010, + 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347, + 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424, + 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, + 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238, + 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, + 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232, + 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461, + 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486, + 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0, + 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, + 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560, + 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, + 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, + 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, + 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, + 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, + 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0, + 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, + 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, + 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356, + 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214, + 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363, + 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251, + 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266, + 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287, + 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302, + 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, + 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375, + 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353, + 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234, + 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403, + 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412, + 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0, + 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721, + 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0, + 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757, + 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776, + 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0, + 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793, + 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814, + 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0, + 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728, + 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764, + 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821, + 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, + 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828, + 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833, + 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, + 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938, + 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0, + 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0, + 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0, + 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0, + 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0, + 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0, + 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0, + 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, + 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, + 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, + 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, + 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, + 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, + 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, + 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, + 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, + 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, + 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, + 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, + 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, + 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, + 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, + 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, + 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, + 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, + 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, + 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, + 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, + 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, + 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, + 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, + 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, + 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, + 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, + 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, + 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, + 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, + 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575, + 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0, + 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950, + 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959, + 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, + 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, + 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, + 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, + 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, + 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, + 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, + 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, + 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, + 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, + 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, + 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, + 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, + 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, + 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, + 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, + 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, + 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, + 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, + 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, + 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, + 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, + 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, + 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, + 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, + 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, + 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, + 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, + 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, + 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, + 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, + 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, + 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, + 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; +static const int16_t +_hb_ucd_i16[196] = +{ + 0, 0, 0, 0, 1, -1, 0, 0, 2, 0, -2, 0, 0, 0, 0, 2, + 0, -2, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 0, 0, 1, -1, + 0, 0, 0, 1, -1, 0, 0, 0, 0, 1, -1, 0, 3, 3, 3, -3, + -3, -3, 0, 0, 0, 2016, 0, 0, 0, 0, 0, 2527, 1923, 1914, 1918, 0, + 2250, 0, 0, 0, 0, 0, 0, 138, 0, 7, 0, 0, -7, 0, 0, 0, + 1, -1, 1, -1, -1, 1, -1, 0, 1824, 0, 0, 0, 0, 0, 2104, 0, + 2108, 2106, 0, 2106, 1316, 0, 0, 0, 0, 1, -1, 1, -1, -138, 0, 0, + 1, -1, 8, 8, 8, 0, 7, 7, 0, 0, -8, -8, -8, -7, -7, 0, + 1, -1, 0, 2,-1316, 1, -1, 0, -1, 1, -1, 1, -1, 3, 1, -1, + -3, 1, -1, 1, -1, 0, 0,-1914,-1918, 0, 0,-1923,-1824, 0, 0, 0, + 0,-2016, 0, 0, 1, -1, 0, 1, 0, 0,-2104, 0, 0, 0, 0,-2106, + -2108,-2106, 0, 0, 1, -1,-2250, 0, 0, 0,-2527, 0, 0, -2, 0, 1, + -1, 0, 1, -1, +}; + +static inline uint_fast8_t +_hb_ucd_gc (unsigned u) +{ + return u<1114110u?_hb_ucd_u8[2176+(((_hb_ucd_u16[((_hb_ucd_u8[u>>4>>5])<<5)+((u>>4)&31u)])<<4)+((u)&15u))]:2; +} +static inline uint_fast8_t +_hb_ucd_ccc (unsigned u) +{ + return u<125259u?_hb_ucd_u8[15060+(((_hb_ucd_u8[13636+(((_hb_ucd_u8[12656+(u>>3>>4)])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:0; +} +static inline unsigned +_hb_ucd_b4 (const uint8_t* a, unsigned i) +{ + return (a[i>>1]>>((i&1u)<<2))&15u; +} +static inline int_fast16_t +_hb_ucd_bmg (unsigned u) +{ + return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[16372+(((_hb_ucd_b4(16244+_hb_ucd_u8,u>>2>>6))<<6)+((u>>2)&63u))])<<2)+((u)&3u)]:0; +} +static inline uint_fast8_t +_hb_ucd_sc (unsigned u) +{ + return u<918000u?_hb_ucd_u8[19126+(((_hb_ucd_u16[3040+(((_hb_ucd_u8[17332+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:2; +} +static inline uint_fast16_t +_hb_ucd_dm (unsigned u) +{ + return u<195102u?_hb_ucd_u16[6144+(((_hb_ucd_u8[29430+(u>>6)])<<6)+((u)&63u))]:0; +} + + +#elif !defined(HB_NO_UCD_UNASSIGNED) + +static const uint8_t +_hb_ucd_u8[17508] = +{ + 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 9, 10, 11, 7, 7, 7, 7, 12, 13, 14, 14, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 21, 23, 21, 21, 21, 21, 24, 7, 7, + 25, 26, 21, 21, 21, 21, 27, 28, 21, 21, 29, 30, 31, 32, 33, 34, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 35, 7, 36, 37, 7, 38, 7, 7, 7, 39, 21, 40, + 7, 7, 41, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 42, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 43, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 44, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 34, 35, 36, 37, 38, 39, 34, 34, 34, 40, 41, 42, 43, + 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 64, 65, 66, 67, 68, 69, 70, 71, 69, 72, 73, + 69, 69, 64, 74, 64, 64, 75, 76, 77, 78, 79, 80, 81, 82, 69, 83, + 84, 85, 86, 87, 88, 89, 69, 69, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, + 92, 34, 34, 34, 34, 34, 34, 34, 34, 93, 34, 34, 94, 95, 96, 97, + 98, 99,100,101,102,103,104,105, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,106, + 107,107,107,107,107,107,107,107,107,107,107,107,107,107,107,107, + 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108, + 108,108, 34, 34,109,110,111,112, 34, 34,113,114,115,116,117,118, + 119,120,121,122,123,124,125,126,127,128,129,123, 34, 34,130,123, + 131,132,133,134,135,136,137,138,139,140,141,123,142,143,144,145, + 146,147,148,149,150,151,152,123,153,154,123,155,156,157,158,123, + 159,160,161,162,163,164,123,123,165,166,167,168,123,169,123,170, + 34, 34, 34, 34, 34, 34, 34,171,172, 34,173,123,123,123,123,123, + 123,123,123,123,123,123,123,123,123,123,123,123,123,123,123,123, + 34, 34, 34, 34, 34, 34, 34, 34,174,123,123,123,123,123,123,123, + 123,123,123,123,123,123,123,123, 34, 34, 34, 34,175,123,123,123, + 34, 34, 34, 34,176,177,178,179,123,123,123,123,180,181,182,183, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,184, + 34, 34, 34, 34, 34, 34, 34, 34, 34,185,186,123,123,123,123,123, + 34, 34,187, 34, 34,188,123,123,123,123,123,123,123,123,123,123, + 123,123,123,123,123,123,123,123,189,190,123,123,123,123,123,123, + 69,191,192,193,194,195,196,123,197,198,199,200,201,202,203,204, + 69, 69, 69, 69,205,206,123,123,123,123,123,123,123,123,123,123, + 207,123,208,123,123,209,123,123,123,123,123,123,123,123,123,123, + 34,210,211,123,123,123,123,123,212,213,214,123,215,216,123,123, + 217,218,219,220,221,123, 69,222, 69, 69, 69, 69, 69,223,224,225, + 226,227,228,229,230,231, 69,232,123,123,123,123,123,123,123,123, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,233, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,234, 34, + 235, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,236, 34, 34, + 34, 34, 34, 34, 34, 34, 34,237,123,123,123,123,123,123,123,123, + 34, 34, 34, 34,238,123,123,123,123,123,123,123,123,123,123,123, + 34, 34, 34, 34, 34, 34,239,123,123,123,123,123,123,123,123,123, + 240,123,241,242,123,123,123,123,123,123,123,123,123,123,123,123, + 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,243, + 108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,244, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, + 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 17, 18, 19, 1, 20, 20, 21, 22, 23, 24, 25, + 26, 27, 15, 2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32, + 32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11, + 11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11, + 34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34, + 34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32, + 32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32, + 16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, + 40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, + 43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 44, 45, 16, 10, + 44, 44, 41, 46, 11, 47, 47, 11, 34, 11, 11, 11, 11, 11, 11, 11, + 11, 48, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34, + 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 49, 34, 32, 34, 11, + 32, 50, 43, 43, 51, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, + 48, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 47, 52, 2, 2, 2, + 16, 16, 16, 16, 53, 54, 55, 56, 57, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 43, 43, 43, 58, 59, 60, 43, 59, 44, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, 62, + 36, 63, 64, 44, 44, 44, 44, 44, 65, 65, 65, 8, 9, 66, 2, 67, + 43, 43, 43, 43, 43, 60, 68, 2, 69, 36, 36, 36, 36, 70, 43, 43, + 7, 7, 7, 7, 7, 2, 2, 36, 71, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 72, 43, 43, 43, 73, 50, 43, 43, 74, 75, 76, 43, 43, 36, + 7, 7, 7, 7, 7, 36, 77, 78, 2, 2, 2, 2, 2, 2, 2, 79, + 70, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 80, 62, 36, + 36, 36, 36, 43, 43, 43, 43, 43, 71, 44, 44, 44, 44, 44, 44, 44, + 7, 7, 7, 7, 7, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, + 43, 43, 40, 21, 2, 81, 57, 20, 36, 36, 36, 43, 43, 75, 43, 43, + 43, 43, 75, 43, 75, 43, 43, 44, 2, 2, 2, 2, 2, 2, 2, 64, + 36, 36, 36, 36, 70, 43, 44, 64, 36, 36, 36, 36, 36, 61, 44, 44, + 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 61, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 44, 44, 44, 44, 44, 57, 43, 43, 43, 43, 43, 43, + 43, 82, 43, 43, 43, 43, 43, 43, 43, 83, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 83, 71, 84, 85, 43, 43, 43, 83, 84, 85, 84, + 70, 43, 43, 43, 36, 36, 36, 36, 36, 43, 2, 7, 7, 7, 7, 7, + 86, 36, 36, 36, 36, 36, 36, 36, 70, 84, 62, 36, 36, 36, 61, 62, + 61, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 36, 36, 36, + 61, 61, 44, 36, 36, 44, 71, 84, 85, 43, 80, 87, 88, 87, 85, 61, + 44, 44, 44, 87, 44, 44, 36, 62, 36, 43, 44, 7, 7, 7, 7, 7, + 36, 20, 27, 27, 27, 56, 63, 80, 57, 83, 62, 36, 36, 61, 44, 62, + 61, 36, 62, 61, 36, 44, 80, 84, 85, 80, 44, 57, 80, 57, 43, 44, + 57, 44, 44, 44, 62, 36, 61, 61, 44, 44, 44, 7, 7, 7, 7, 7, + 43, 36, 70, 64, 44, 44, 44, 44, 57, 83, 62, 36, 36, 36, 36, 62, + 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62, 36, 36, 44, 71, 84, + 85, 43, 43, 57, 83, 87, 85, 44, 61, 44, 44, 44, 44, 44, 44, 44, + 66, 44, 44, 44, 62, 43, 43, 43, 57, 84, 62, 36, 36, 36, 61, 62, + 61, 36, 62, 36, 36, 44, 71, 85, 85, 43, 80, 87, 88, 87, 85, 44, + 44, 44, 57, 83, 44, 44, 36, 62, 78, 27, 27, 27, 44, 44, 44, 44, + 44, 71, 62, 36, 36, 61, 44, 36, 61, 36, 36, 44, 62, 61, 61, 36, + 44, 62, 61, 44, 36, 61, 44, 36, 36, 36, 36, 36, 36, 44, 44, 84, + 83, 88, 44, 84, 88, 84, 85, 44, 61, 44, 44, 87, 44, 44, 44, 44, + 27, 89, 67, 67, 56, 90, 44, 44, 83, 84, 71, 36, 36, 36, 61, 36, + 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 62, 43, + 83, 84, 88, 43, 80, 43, 43, 44, 44, 44, 57, 80, 36, 61, 44, 44, + 44, 44, 44, 91, 27, 27, 27, 89, 70, 84, 72, 36, 36, 36, 61, 36, + 36, 36, 62, 36, 36, 44, 71, 85, 84, 84, 88, 83, 88, 84, 43, 44, + 44, 44, 87, 88, 44, 44, 44, 61, 62, 61, 44, 44, 44, 44, 44, 44, + 43, 84, 36, 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 70, 71, 84, + 85, 43, 80, 84, 88, 84, 85, 77, 44, 44, 36, 92, 27, 27, 27, 93, + 27, 27, 27, 27, 89, 36, 36, 36, 57, 84, 62, 36, 36, 36, 36, 36, + 36, 36, 36, 61, 44, 36, 36, 36, 36, 62, 36, 36, 36, 36, 62, 44, + 36, 36, 36, 61, 44, 80, 44, 87, 84, 43, 80, 80, 84, 84, 84, 84, + 44, 84, 64, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36, 36, + 70, 36, 43, 43, 43, 80, 44, 94, 36, 36, 36, 75, 43, 43, 43, 60, + 7, 7, 7, 7, 7, 2, 44, 44, 62, 61, 61, 36, 36, 61, 36, 36, + 36, 36, 62, 62, 36, 36, 36, 36, 70, 36, 43, 43, 43, 43, 71, 44, + 36, 36, 61, 81, 43, 43, 43, 44, 7, 7, 7, 7, 7, 44, 36, 36, + 77, 67, 2, 2, 2, 2, 2, 2, 2, 95, 95, 67, 43, 67, 67, 67, + 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 50, 50, 50, 4, 4, 84, + 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 44, + 57, 43, 43, 43, 43, 43, 43, 83, 43, 43, 60, 43, 36, 36, 70, 43, + 43, 43, 43, 43, 57, 43, 43, 43, 43, 43, 43, 43, 43, 43, 80, 67, + 67, 67, 67, 76, 67, 67, 90, 67, 2, 2, 95, 67, 21, 64, 44, 44, + 36, 36, 36, 36, 36, 92, 85, 43, 83, 43, 43, 43, 85, 83, 85, 71, + 7, 7, 7, 7, 7, 2, 2, 2, 36, 36, 36, 84, 43, 36, 36, 43, + 71, 84, 96, 92, 84, 84, 84, 36, 70, 43, 71, 36, 36, 36, 36, 36, + 36, 83, 85, 83, 84, 84, 85, 92, 7, 7, 7, 7, 7, 84, 85, 67, + 11, 11, 11, 48, 44, 44, 48, 44, 16, 16, 16, 16, 16, 53, 45, 16, + 36, 36, 36, 36, 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, + 61, 36, 36, 44, 36, 36, 36, 61, 61, 36, 36, 44, 36, 36, 36, 36, + 36, 36, 36, 61, 36, 36, 36, 36, 36, 36, 36, 36, 36, 61, 57, 43, + 2, 2, 2, 2, 97, 27, 27, 27, 27, 27, 27, 27, 27, 27, 98, 44, + 67, 67, 67, 67, 67, 44, 44, 44, 11, 11, 11, 44, 16, 16, 16, 44, + 99, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 77, 72, + 100, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,101,102, 44, + 36, 36, 36, 36, 36, 63, 2,103,104, 36, 36, 36, 61, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 61, 36, 36, 43, 80, 44, 44, 44, 44, 44, + 36, 43, 60, 64, 44, 44, 44, 44, 36, 43, 44, 44, 44, 44, 44, 44, + 61, 43, 44, 44, 44, 44, 44, 44, 36, 36, 43, 85, 43, 43, 43, 84, + 84, 84, 84, 83, 85, 43, 43, 43, 43, 43, 2, 86, 2, 66, 70, 44, + 7, 7, 7, 7, 7, 44, 44, 44, 27, 27, 27, 27, 27, 44, 44, 44, + 2, 2, 2,105, 2, 59, 43, 68, 36,106, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 61, 44, 44, 44, 36, 36, 70, 71, 36, 36, 36, 36, + 36, 36, 36, 36, 70, 61, 44, 44, 36, 36, 36, 44, 44, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 36, 61, 43, 83, 84, 85, 83, 84, 44, 44, + 84, 83, 84, 84, 85, 43, 44, 44, 90, 44, 2, 7, 7, 7, 7, 7, + 36, 36, 36, 36, 36, 36, 36, 44, 36, 36, 61, 44, 44, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 44, 44, 36, 36, 36, 36, 36, 44, 44, 44, + 7, 7, 7, 7, 7, 98, 44, 67, 67, 67, 67, 67, 67, 67, 67, 67, + 36, 36, 36, 70, 83, 85, 44, 2, 36, 36, 92, 83, 43, 43, 43, 80, + 83, 83, 85, 43, 43, 43, 83, 84, 84, 85, 43, 43, 43, 43, 80, 57, + 2, 2, 2, 86, 2, 2, 2, 44, 43, 43, 43, 43, 43, 43, 43,107, + 80, 44, 44, 44, 44, 44, 44, 44, 43, 43, 96, 36, 36, 36, 36, 36, + 36, 36, 83, 43, 43, 83, 83, 84, 84, 83, 96, 36, 36, 36, 44, 44, + 95, 67, 67, 67, 67, 50, 43, 43, 43, 43, 67, 67, 67, 67, 90, 44, + 43, 96, 36, 36, 36, 36, 36, 36, 92, 43, 43, 84, 43, 85, 43, 36, + 36, 36, 36, 83, 43, 84, 85, 85, 43, 84, 44, 44, 44, 44, 2, 2, + 36, 36, 84, 84, 84, 84, 43, 43, 43, 43, 84, 43, 44, 91, 2, 2, + 7, 7, 7, 7, 7, 44, 62, 36, 36, 36, 36, 36, 40, 40, 40, 2, + 16, 16, 16, 16,108, 44, 44, 44, 11, 11, 11, 11, 11, 47, 48, 11, + 2, 2, 2, 2, 44, 44, 44, 44, 43, 60, 43, 43, 43, 43, 43, 43, + 83, 43, 43, 43, 71, 36, 70, 36, 36, 36, 71, 92, 43, 61, 44, 44, + 16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 45, 16, 16, + 16, 16, 16, 16, 45, 16, 16, 16, 16, 16, 16, 16, 16,109, 40, 40, + 43, 43, 43, 43, 43, 57, 43, 43, 32, 32, 32, 16, 16, 16, 16, 32, + 16, 16, 16, 16, 11, 11, 11, 11, 16, 16, 16, 44, 11, 11, 11, 44, + 16, 16, 16, 16, 48, 48, 48, 48, 16, 16, 16, 16, 16, 16, 16, 44, + 16, 16, 16, 16,110,110,110,110, 16, 16,108, 16, 11, 11,111,112, + 41, 16,108, 16, 11, 11,111, 41, 16, 16, 44, 16, 11, 11,113, 41, + 16, 16, 16, 16, 11, 11,114, 41, 44, 16,108, 16, 11, 11,111,115, + 116,116,116,116,116,117, 65, 65,118,118,118, 2,119,120,119,120, + 2, 2, 2, 2,121, 65, 65,122, 2, 2, 2, 2,123,124, 2,125, + 126, 2,127,128, 2, 2, 2, 2, 2, 9,126, 2, 2, 2, 2,129, + 65, 65, 68, 65, 65, 65, 65, 65,130, 44, 27, 27, 27, 8,127,131, + 27, 27, 27, 27, 27, 8,127,102, 40, 40, 40, 40, 40, 40, 81, 44, + 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,132, 51, + 107, 51,107, 43, 43, 43, 43, 43, 67,133, 67,134, 67, 34, 11, 16, + 11, 32,134, 67, 49, 11, 11, 67, 67, 67,133,133,133, 11, 11,135, + 11, 11, 35, 36, 39, 67, 16, 11, 8, 8, 49, 16, 16, 26, 67,136, + 27, 27, 27, 27, 27, 27, 27, 27,103,103,103,103,103,103,103,103, + 103,137,138,103,139, 67, 44, 44, 8, 8,140, 67, 67, 8, 67, 67, + 140, 26, 67,140, 67, 67, 67,140, 67, 67, 67, 67, 67, 67, 67, 8, + 67,140,140, 67, 67, 67, 67, 67, 67, 67, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 67, 67, 67, 67, 4, 4, 67, 67, + 8, 67, 67, 67,141,142, 67, 67, 67, 67, 67, 67, 67, 67,140, 67, + 67, 67, 67, 67, 67, 26, 8, 8, 8, 8, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 8, 8, 8, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 90, 44, 44, 44, 44, 67, 67, 67, 67, 67, 90, 44, 44, + 27, 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, + 67, 67, 67, 26, 67, 67, 67, 67, 26, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 8, 8, 8, 8, 67, 67, 67, 67, 67, 67, 67, 26, + 67, 67, 67, 67, 4, 4, 4, 4, 4, 4, 4, 27, 27, 27, 27, 27, + 27, 27, 67, 67, 67, 67, 67, 67, 8, 8,127,143, 8, 8, 8, 8, + 8, 8, 8, 4, 4, 4, 4, 4, 8,127,144,144,144,144,144,144, + 144,144,144,144,143, 8, 8, 8, 8, 8, 8, 8, 4, 4, 8, 8, + 8, 8, 8, 8, 8, 8, 4, 8, 8, 8,140, 26, 8, 8,140, 67, + 67, 67, 44, 67, 67, 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 67, + 11, 11, 11, 11, 11, 11, 11, 47, 16, 16, 16, 16, 16, 16, 16,108, + 32, 11, 32, 34, 34, 34, 34, 11, 32, 32, 34, 16, 16, 16, 40, 11, + 32, 32,136, 67, 67,134, 34,145, 43, 32, 44, 44, 91, 2, 97, 2, + 16, 16, 16,146, 44, 44,146, 44, 36, 36, 36, 36, 44, 44, 44, 52, + 64, 44, 44, 44, 44, 44, 44, 57, 36, 36, 36, 61, 44, 44, 44, 44, + 36, 36, 36, 61, 36, 36, 36, 61, 2,119,119, 2,123,124,119, 2, + 2, 2, 2, 6, 2,105,119, 2,119, 4, 4, 4, 4, 2, 2, 86, + 2, 2, 2, 2, 2,118, 2, 2,105,147, 2, 2, 2, 2, 2, 2, + 67, 64, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 55, 67, 67, + 67, 67, 44, 44, 44, 44, 44, 44, 67, 67, 67, 44, 44, 44, 44, 44, + 67, 67, 67, 67, 67, 67, 44, 44, 1, 2,148,149, 4, 4, 4, 4, + 4, 67, 4, 4, 4, 4,150,151,152,103,103,103,103, 43, 43, 84, + 153, 40, 40, 67,103,154, 63, 67, 36, 36, 36, 61, 57,155,156, 69, + 36, 36, 36, 36, 36, 63, 40, 69, 44, 44, 62, 36, 36, 36, 36, 36, + 67, 27, 27, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 90, + 27, 27, 27, 27, 27, 67, 67, 67, 67, 67, 67, 67, 27, 27, 27, 27, + 157, 27, 27, 27, 27, 27, 27, 27, 36, 36,106, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36,158, 2, 7, 7, 7, 7, 7, 36, 44, 44, + 32, 32, 32, 32, 32, 32, 32, 70, 51,159, 43, 43, 43, 43, 43, 86, + 32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36,103,103,103,103,103, + 43, 2, 2, 2, 44, 44, 44, 44, 41, 41, 41,156, 40, 40, 40, 40, + 41, 32, 32, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, + 45, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,160, 34, 35, + 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32, + 11, 11, 32, 32, 32, 32, 32, 32, 44, 32, 11, 11, 34,108, 44, 44, + 44, 44, 48, 35, 40, 35, 36, 36, 36, 71, 36, 71, 36, 70, 36, 36, + 36, 92, 85, 83, 67, 67, 80, 44, 27, 27, 27, 67,161, 44, 44, 44, + 36, 36, 2, 2, 44, 44, 44, 44, 84, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 84, 84, 84, 84, 84, 84, 84, 84, 43, 44, 44, 44, 44, 2, + 43, 36, 36, 36, 2, 72, 72, 70, 36, 36, 36, 43, 43, 43, 43, 2, + 36, 36, 36, 70, 43, 43, 43, 43, 43, 84, 44, 44, 44, 44, 44, 91, + 36, 70, 84, 43, 43, 84, 43, 84,162, 2, 2, 2, 2, 2, 2, 52, + 7, 7, 7, 7, 7, 44, 44, 2, 36, 36, 70, 69, 36, 36, 36, 36, + 7, 7, 7, 7, 7, 36, 36, 61, 36, 36, 36, 36, 70, 43, 43, 83, + 85, 83, 85, 80, 44, 44, 44, 44, 36, 70, 36, 36, 36, 36, 83, 44, + 7, 7, 7, 7, 7, 44, 2, 2, 69, 36, 36, 77, 67, 92, 83, 36, + 71, 43, 71, 70, 71, 36, 36, 43, 70, 61, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 44, 44, 62,106, 2, 36, 36, 36, 36, 36, 92, 43, 84, + 2,106,163, 80, 44, 44, 44, 44, 62, 36, 36, 61, 62, 36, 36, 61, + 62, 36, 36, 61, 44, 44, 44, 44, 16, 16, 16, 16, 16,112, 40, 40, + 16, 16, 16, 16,109, 41, 44, 44, 36, 92, 85, 84, 83,162, 85, 44, + 36, 36, 44, 44, 44, 44, 44, 44, 36, 36, 36, 61, 44, 62, 36, 36, + 164,164,164,164,164,164,164,164,165,165,165,165,165,165,165,165, + 16, 16, 16,108, 44, 44, 44, 44, 44,146, 16, 16, 44, 44, 62, 71, + 36, 36, 36, 36,166, 36, 36, 36, 36, 36, 36, 61, 36, 36, 61, 61, + 36, 62, 61, 36, 36, 36, 36, 36, 36, 41, 41, 41, 41, 41, 41, 41, + 41, 44, 44, 44, 44, 44, 44, 44, 44, 62, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36,144, 44, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36,161, 44, 2, 2, 2,167,128, 44, 44, 44, + 6,168,169,144,144,144,144,144,144,144,128,167,128, 2,125,170, + 2, 64, 2, 2,150,144,144,128, 2,171, 8,172, 66, 2, 44, 44, + 36, 36, 36, 36, 36, 36, 61, 79, 91, 2, 3, 2, 4, 5, 6, 2, + 16, 16, 16, 16, 16, 17, 18,127,128, 4, 2, 36, 36, 36, 36, 36, + 69, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40, + 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 36, 36, 44, 36, 61, 44, + 20,173, 56,174, 26, 8,140, 90, 44, 44, 44, 44, 79, 65, 67, 44, + 36, 36, 36, 36, 36, 36, 62, 36, 36, 36, 36, 36, 36, 61, 36, 62, + 2, 64, 44,175, 27, 27, 27, 27, 27, 27, 44, 55, 67, 67, 67, 67, + 103,103,139, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 27, 67, 90, + 67, 67, 67, 67, 67, 67, 90, 44, 90, 44, 44, 44, 44, 44, 44, 44, + 67, 67, 67, 67, 67, 67, 50, 44,176, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 44, 44, 27, 27, 44, 44, 44, 44, 62, 36, + 149, 36, 36, 36, 36,177, 44, 44, 36, 36, 36, 43, 43, 80, 44, 44, + 36, 36, 36, 36, 36, 36, 36, 91, 36, 36, 44, 44, 36, 36, 36, 36, + 178,103,103, 44, 44, 44, 44, 44, 11, 11, 11, 11, 16, 16, 16, 16, + 11, 11, 44, 44, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 44, 44, + 36, 36, 44, 44, 44, 44, 44, 91, 36, 36, 36, 44, 61, 36, 36, 36, + 36, 36, 36, 62, 61, 44, 61, 62, 36, 36, 36, 91, 27, 27, 27, 27, + 36, 36, 36, 77,157, 27, 27, 27, 44, 44, 44,175, 27, 27, 27, 27, + 36, 61, 36, 44, 44,175, 27, 27, 36, 36, 36, 27, 27, 27, 44, 91, + 36, 36, 36, 36, 36, 44, 44, 91, 36, 36, 36, 36, 44, 44, 27, 36, + 44, 27, 27, 27, 27, 27, 27, 27, 70, 43, 57, 80, 44, 44, 43, 43, + 36, 36, 62, 36, 62, 36, 36, 36, 36, 36, 36, 44, 43, 80, 44, 57, + 27, 27, 27, 27, 98, 44, 44, 44, 2, 2, 2, 2, 64, 44, 44, 44, + 36, 36, 36, 36, 36, 36,179, 30, 36, 36, 36, 36, 36, 36,179, 27, + 36, 36, 36, 36, 78, 36, 36, 36, 36, 36, 70, 80, 44,175, 27, 27, + 2, 2, 2, 64, 44, 44, 44, 44, 36, 36, 36, 44, 91, 2, 2, 2, + 36, 36, 36, 44, 27, 27, 27, 27, 36, 61, 44, 44, 27, 27, 27, 27, + 36, 44, 44, 44, 91, 2, 64, 44, 44, 44, 44, 44,175, 27, 27, 27, + 11, 47, 44, 44, 44, 44, 44, 44, 16,108, 44, 44, 44, 27, 27, 27, + 36, 36, 43, 43, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27, 98, + 36, 36, 36, 36, 36, 57,180, 44, 36, 44, 44, 44, 44, 44, 44, 44, + 27, 27, 27, 93, 44, 44, 44, 44,176, 27, 30, 2, 2, 44, 44, 44, + 36, 36,179, 27, 27, 27, 44, 44, 85, 96, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 43, 60, 2, 2, 2, 44, + 27, 27, 27, 7, 7, 7, 7, 7, 44, 44, 44, 44, 44, 44, 44, 57, + 84, 85, 43, 83, 85, 60,181, 2, 2, 44, 44, 44, 44, 44, 79, 44, + 43, 71, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 43, 43, 85, 43, + 43, 43, 80, 7, 7, 7, 7, 7, 2, 2, 92, 96, 44, 44, 44, 44, + 36, 70, 2, 61, 44, 44, 44, 44, 36, 92, 84, 43, 43, 43, 43, 83, + 96, 36, 63, 2, 59, 43, 60, 85, 7, 7, 7, 7, 7, 63, 63, 2, + 175, 27, 27, 27, 27, 27, 27, 27, 27, 27, 98, 44, 44, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 84, 85, 43, 84, 83, 43, 2, 2, 2, 80, + 36, 36, 36, 61, 61, 36, 36, 62, 36, 36, 36, 36, 36, 36, 36, 62, + 36, 36, 36, 36, 63, 44, 44, 44, 36, 36, 36, 36, 36, 36, 36, 70, + 84, 85, 43, 43, 43, 80, 44, 44, 43, 84, 62, 36, 36, 36, 61, 62, + 61, 36, 62, 36, 36, 57, 71, 84, 83, 84, 88, 87, 88, 87, 84, 44, + 61, 44, 44, 87, 44, 44, 62, 36, 36, 84, 44, 43, 43, 43, 80, 44, + 43, 43, 80, 44, 44, 44, 44, 44, 36, 36, 92, 84, 43, 43, 43, 43, + 84, 43, 83, 71, 36, 63, 2, 2, 7, 7, 7, 7, 7, 2, 91, 71, + 84, 85, 43, 43, 83, 83, 84, 85, 83, 43, 36, 72, 44, 44, 44, 44, + 36, 36, 36, 36, 36, 36, 36, 92, 84, 43, 43, 44, 84, 84, 43, 85, + 60, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 43, 44, + 84, 85, 43, 43, 43, 83, 85, 85, 60, 2, 61, 44, 44, 44, 44, 44, + 2, 2, 2, 2, 2, 2, 64, 44, 36, 36, 36, 36, 36, 70, 85, 84, + 43, 43, 43, 85, 61, 44, 44, 44, 84, 43, 43, 85, 43, 43, 44, 44, + 7, 7, 7, 7, 7, 27, 2, 95, 43, 43, 43, 43, 85, 60, 44, 44, + 27, 98, 44, 44, 44, 44, 44, 62, 36, 36, 36, 61, 62, 44, 36, 36, + 36, 36, 62, 61, 36, 36, 36, 36, 84, 84, 84, 87, 88, 57, 83, 71, + 96, 85, 2, 64, 44, 44, 44, 44, 36, 36, 36, 36, 44, 36, 36, 36, + 92, 84, 43, 43, 44, 43, 84, 84, 71, 72, 88, 44, 44, 44, 44, 44, + 70, 43, 43, 43, 43, 71, 36, 36, 36, 70, 43, 43, 83, 70, 43, 60, + 2, 2, 2, 59, 44, 44, 44, 44, 70, 43, 43, 83, 85, 43, 36, 36, + 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 83, 43, 2, 72, 2, + 2, 64, 44, 44, 44, 44, 44, 44, 43, 43, 43, 80, 43, 43, 43, 85, + 63, 2, 2, 44, 44, 44, 44, 44, 2, 36, 36, 36, 36, 36, 36, 36, + 44, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 87, 43, 43, 43, + 83, 43, 85, 80, 44, 44, 44, 44, 36, 36, 36, 61, 36, 62, 36, 36, + 70, 43, 43, 80, 44, 80, 43, 57, 43, 43, 43, 70, 44, 44, 44, 44, + 36, 36, 36, 62, 61, 36, 36, 36, 36, 36, 36, 36, 36, 84, 84, 88, + 43, 87, 85, 85, 61, 44, 44, 44, 36, 70, 83,162, 64, 44, 44, 44, + 27, 27, 89, 67, 67, 67, 56, 20,161, 67, 67, 67, 67, 67, 67, 67, + 67, 44, 44, 44, 44, 44, 44, 91,103,103,103,103,103,103,103,177, + 2, 2, 64, 44, 44, 44, 44, 44, 65, 65, 65, 65, 68, 44, 44, 44, + 43, 43, 60, 44, 44, 44, 44, 44, 43, 43, 43, 60, 2, 2, 67, 67, + 40, 40, 95, 44, 44, 44, 44, 44, 7, 7, 7, 7, 7,175, 27, 27, + 27, 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 44, 44, 62, 36, + 27, 27, 27, 30, 2, 64, 44, 44, 36, 36, 36, 36, 36, 61, 44, 57, + 92, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 84, 84, 84, 84, 44, 44, 44, 57, 43, 74, 40, 40, 40, 40, 40, 40, + 40, 86, 80, 44, 44, 44, 44, 44, 84, 44, 44, 44, 44, 44, 44, 44, + 36, 61, 44, 44, 44, 44, 44, 44, 44, 44, 36, 36, 44, 44, 44, 44, + 36, 36, 36, 36, 36, 44, 50, 60, 65, 65, 44, 44, 44, 44, 44, 44, + 67, 67, 67, 90, 55, 67, 67, 67, 67, 67,182, 85, 43, 67,182, 84, + 84,183, 65, 65, 65, 82, 43, 43, 43, 76, 50, 43, 43, 43, 67, 67, + 67, 67, 67, 67, 67, 43, 43, 67, 67, 67, 67, 67, 90, 44, 44, 44, + 67, 43, 76, 44, 44, 44, 44, 44, 27, 27, 44, 44, 44, 44, 44, 44, + 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 16, 16, 16,108, 16, 16, 16, 16, 16, + 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 47, 11, + 44, 47, 48, 47, 48, 11, 47, 11, 11, 11, 11, 16, 16,146,146, 16, + 16, 16,146, 16, 16, 16, 16, 16, 16, 16, 11, 48, 11, 47, 48, 11, + 11, 11, 47, 11, 11, 11, 47, 16, 16, 16, 16, 16, 11, 48, 11, 47, + 11, 11, 47, 47, 44, 11, 11, 11, 47, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, + 16, 16, 16, 44, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, + 11, 11, 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, + 16, 16, 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, + 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, + 16, 33, 16, 16, 16, 32, 44, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 43, 43, 43, 76, 67, 50, 43, 43, 43, 43, 43, 43, 43, 43, 76, 67, + 67, 67, 50, 67, 67, 67, 67, 67, 67, 67, 76, 21, 2, 2, 44, 44, + 44, 44, 44, 44, 44, 57, 43, 43, 43, 43, 43, 80, 43, 43, 43, 43, + 43, 43, 43, 43, 80, 57, 43, 43, 43, 57, 80, 43, 43, 80, 44, 44, + 43, 43, 43, 74, 40, 40, 40, 44, 7, 7, 7, 7, 7, 44, 44, 77, + 36, 36, 36, 36, 36, 36, 43, 43, 7, 7, 7, 7, 7, 44, 44, 94, + 36, 36, 61,175, 27, 27, 27, 27, 43, 43, 43, 80, 44, 44, 44, 44, + 16, 16, 43, 43, 43, 74, 44, 44, 27, 27, 27, 27, 27, 27,157, 27, + 184, 27, 98, 44, 44, 44, 44, 44, 27, 27, 27, 27, 27, 27, 27,157, + 27, 27, 27, 27, 27, 27, 27, 44, 36, 36, 62, 36, 36, 36, 36, 36, + 62, 61, 61, 62, 62, 36, 36, 36, 36, 61, 36, 36, 62, 62, 44, 44, + 44, 61, 44, 62, 62, 62, 62, 36, 62, 61, 61, 62, 62, 62, 62, 62, + 62, 61, 61, 62, 36, 61, 36, 36, 36, 61, 36, 36, 62, 36, 61, 61, + 36, 36, 36, 36, 36, 62, 36, 36, 62, 36, 62, 36, 36, 62, 36, 36, + 8, 44, 44, 44, 44, 44, 44, 44, 55, 67, 67, 67, 67, 67, 67, 67, + 27, 27, 27, 27, 27, 27, 89, 67, 67, 67, 67, 67, 67, 67, 67, 44, + 44, 44, 44, 67, 67, 67, 67, 67, 67, 90, 44, 44, 44, 44, 44, 44, + 67, 44, 44, 44, 44, 44, 44, 44, 67, 67, 67, 67, 67, 25, 41, 41, + 67, 67, 67, 67, 44, 44, 44, 44, 67, 67, 67, 67, 90, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 55, 67, 67, 67, 90, 44, 67, 90, 44, 44, + 67, 90, 67, 67, 67, 67, 67, 67, 79, 44, 44, 44, 44, 44, 44, 44, + 65, 65, 65, 65, 65, 65, 65, 65,165,165,165,165,165,165,165, 44, + 165,165,165,165,165,165,165, 0, 0, 0, 29, 21, 21, 21, 23, 21, + 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, + 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, + 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15, + 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7, + 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12, + 2, 2, 6, 5, 9, 21, 9, 2, 2, 9, 25, 9, 26, 12, 11, 11, + 2, 6, 5, 21, 17, 2, 2, 26, 26, 23, 2, 12, 17, 12, 21, 12, + 12, 21, 7, 2, 2, 7, 7, 21, 21, 2, 1, 1, 21, 23, 26, 26, + 1, 2, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, 6, 12, + 12, 26, 7, 26, 26, 7, 2, 1, 12, 2, 6, 2, 1, 12, 12, 10, + 10, 10, 10, 12, 21, 6, 2, 10, 10, 2, 15, 26, 26, 2, 2, 21, + 7, 10, 15, 7, 2, 23, 21, 26, 10, 7, 21, 15, 15, 2, 17, 7, + 29, 7, 7, 22, 18, 2, 14, 14, 14, 7, 17, 21, 7, 6, 11, 12, + 5, 2, 5, 6, 8, 8, 8, 24, 5, 24, 2, 24, 9, 24, 24, 2, + 29, 29, 29, 1, 17, 17, 20, 19, 22, 20, 27, 28, 1, 29, 21, 20, + 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15, 6, 18, 6, + 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, 14, 15, + 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 2, 5, 22, 21, + 26, 6, 7, 14, 17, 22, 18, 18, 26, 14, 17, 6, 14, 6, 12, 24, + 24, 6, 26, 15, 6, 21, 11, 21, 24, 9, 23, 26, 10, 21, 6, 10, + 4, 4, 3, 3, 7, 25, 21, 22, 17, 16, 16, 22, 16, 16, 25, 17, + 25, 2, 25, 24, 23, 2, 2, 15, 12, 15, 14, 2, 21, 14, 7, 15, + 12, 17, 21, 1, 26, 10, 10, 1, 23, 15, 0, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, 0, 0, 0, 0, + 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 18, 19, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, 0, 0, 0, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, + 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 41, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, + 9, 0, 10, 11, 0, 0, 12, 13, 14, 15, 16, 0, 0, 0, 0, 17, + 18, 19, 20, 0, 0, 0, 21, 22, 0, 23, 24, 0, 0, 23, 25, 26, + 0, 23, 25, 0, 0, 23, 25, 0, 0, 23, 25, 0, 0, 0, 25, 0, + 0, 0, 27, 0, 0, 23, 25, 0, 0, 28, 25, 0, 0, 0, 29, 0, + 0, 30, 31, 0, 0, 32, 33, 0, 34, 35, 0, 36, 37, 0, 38, 0, + 0, 39, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 42, 42, 0, 0, 0, 0, 43, 0, + 0, 0, 0, 0, 0, 44, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, + 46, 0, 0, 47, 0, 48, 49, 0, 0, 50, 51, 52, 0, 53, 0, 54, + 0, 55, 0, 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 0, 58, 59, + 0, 0, 0, 0, 0, 0, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 0, 0, 0, 64, + 0, 65, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 67, 68, 0, 0, 69, 0, 0, 0, 0, 0, 0, 0, 0, + 70, 71, 0, 0, 0, 0, 51, 72, 0, 73, 74, 0, 0, 75, 76, 0, + 0, 0, 0, 0, 0, 77, 78, 79, 0, 0, 0, 0, 0, 0, 0, 25, + 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 83, 0, 0, 0, 0, + 84, 85, 0, 0, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 88, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, + 0, 0, 70, 63, 0, 90, 0, 0, 91, 92, 0, 75, 0, 0, 93, 0, + 0, 94, 0, 0, 0, 0, 0, 95, 0, 96, 25, 97, 0, 0, 0, 0, + 0, 0, 98, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 63,100, 0, + 0, 63, 0, 0, 0,101, 0, 0, 0,102, 0, 0, 0, 0, 0, 0, + 0, 90, 0, 0, 0, 0, 0, 0, 0,103,104, 0, 0, 0, 0, 76, + 0, 42,105, 0,106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 63, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,108, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,109, 0,110, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,111, + 0, 0, 0, 0,112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,113,114,115, 0, 0, + 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 117,118, 0, 0, 0, 0, 0, 0, 0,110, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,119, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,120, 0, 0, 0,121, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, + 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, + 18, 1, 1, 1, 0, 0, 0, 0, 19, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, 25, 26, 27, 28, + 29, 30, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 31, 0, + 0, 0, 32, 33, 34, 35, 1, 36, 0, 0, 0, 0, 37, 0, 0, 0, + 0, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, 0, 0, 0, 0, + 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 43, 36, 44, 45, + 21, 45, 46, 0, 0, 0, 0, 0, 0, 0, 19, 1, 21, 0, 0, 47, + 0, 0, 0, 0, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 51, 0, 0, 0, 0, 0, 52, 1, 1, 1, + 53, 21, 43, 54, 55, 21, 35, 1, 0, 0, 0, 0, 0, 0, 0, 56, + 0, 0, 0, 57, 58, 59, 0, 0, 0, 0, 0, 57, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 57, 0, 61, 0, 0, + 0, 0, 0, 0, 0, 0, 62, 63, 0, 0, 64, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 66, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 69, 0, 0, 0, 0, 0, 0, 70, 71, 0, + 0, 0, 0, 0, 72, 73, 74, 75, 76, 77, 0, 0, 0, 0, 0, 0, + 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79, 80, 0, + 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, + 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 64, 0, 0, 81, + 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, + 0, 0, 0, 0, 0, 19, 84, 0, 63, 0, 0, 0, 0, 49, 1, 85, + 0, 0, 0, 0, 1, 54, 15, 86, 84, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 56, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, + 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, + 0, 88, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, + 0, 0, 0, 0, 89, 9, 12, 4, 90, 8, 91, 47, 0, 59, 50, 0, + 21, 1, 21, 92, 93, 1, 1, 1, 1, 1, 1, 1, 1, 94, 95, 96, + 0, 0, 0, 0, 97, 1, 98, 59, 81, 99,100, 4, 59, 0, 0, 0, + 0, 0, 0, 19, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,101,102, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,103, 0, 0, 0, 0, 19, 0, 1, 1, 50, + 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 50, 0, 0, 0, + 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, 0, 0, + 1, 1, 1, 1, 50, 0, 0, 0, 0, 0, 52, 69, 0, 0, 0, 0, + 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 79, 0, 0, 0, + 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,104,105, 59, 38, + 81, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, + 0, 0, 0, 0, 0, 0, 0,106, 1, 14, 4, 12, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 38, 89, 0, + 0, 0, 0,107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,108, 62, + 0,109, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 19, 59, 0, 0, 0, 0, 0,110, 14, 54, 84, 0, 0, 0, + 0, 0, 0, 0, 0, 0,111, 0, 89, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 62, 63, 0, 0, 63, 0, 88, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,111, 0, 0, 0, 0,112, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 79, 56, 0, 38, 1, 59, 1, 59, 0, 0, + 64, 88, 0, 0, 0, 0, 0, 60,113, 0, 0, 0, 0, 0, 0, 0, + 56, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,113, 0, 0, + 0, 0, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, + 79, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 57, 0, 88,114, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 62, 0, 0, 0, 0, 0, 0, 8, 91, 0, 0, + 0, 0, 0, 0, 1, 89, 0, 0, 0, 0, 0, 0,115, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,116, 0,117,118,119,120, 0, 52, 4, + 121, 49, 23, 0, 0, 0, 0, 0, 0, 0, 38, 50, 0, 0, 0, 0, + 38, 59, 0, 0, 0, 0, 0, 0, 1, 89, 1, 1, 1, 1, 39, 1, + 48,104, 89, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 4,121, 0, 0, 0, 1,122, 0, 0, 0, 0, 0, + 0, 0, 0, 0,230,230,230,230,230,232,220,220,220,220,232,216, + 220,220,220,220,220,202,202,220,220,220,220,202,202,220,220,220, + 1, 1, 1, 1, 1,220,220,220,220,230,230,230,230,240,230,220, + 220,220,230,230,230,220,220, 0,230,230,230,220,220,220,220,230, + 232,220,220,230,233,234,234,233,234,234,233,230, 0, 0, 0,230, + 0,220,230,230,230,230,220,230,230,230,222,220,230,230,220,220, + 230,222,228,230, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, + 21, 22, 0, 23, 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, + 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230, + 220,230,230,220, 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230, + 230, 0,220,230,230,220, 0, 0, 0, 36, 0, 0,230,220,230,230, + 220,220,230,220,220,230,220,230,220,230,230, 0, 0,220, 0, 0, + 230,230, 0,230, 0,230,230,230,230,230, 0, 0, 0,220,220,220, + 0, 0, 0,220,230,230, 0,220,230,220,220,220, 27, 28, 29,230, + 7, 0, 0, 0, 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, + 0, 0,230, 0, 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, + 0, 0, 9, 0,103,103, 9, 0,107,107,107,107,118,118, 9, 0, + 122,122,122,122,220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, + 0,129,130, 0,132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0, + 130, 0,230,230, 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, + 0, 9, 9, 0, 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220, + 220, 0, 0, 0,230, 0, 0,220,230,220, 0,220, 0, 0, 9, 9, + 0, 0, 7, 0,230,230,230, 0,230, 0, 1, 1, 1, 0, 0, 0, + 230,234,214,220,202,230,230,230,230,230,232,228,228,220, 0,230, + 233,220,230,220,230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230, + 220,230, 1, 1, 0, 0,218,228,232,222,224,224, 0, 8, 8, 0, + 230, 0,230,230,220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230, + 230, 1,220, 0, 0,230,220, 0, 0, 0,220,220, 0, 9, 7, 0, + 0, 7, 9, 0, 0, 0, 9, 7, 9, 9, 0, 0, 6, 6, 0, 0, + 0, 0, 1, 0, 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216, + 216,216,216, 0,220,220,220, 0,230,230, 7, 0, 16, 17, 17, 17, + 17, 17, 17, 33, 17, 17, 17, 19, 17, 17, 17, 17, 20,101, 17,113, + 129,169, 17, 27, 28, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,237, 0, 1, 2, 2, + 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 6, 7, 8, + 9, 0, 0, 0, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 21, 22, 0, 0, 0, 0, + 23, 24, 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 0, 0, 0, 0, + 0, 0, 0, 33, 34, 35, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 1, 2, 39, 40, + 0, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 0, 5, 0, + 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 1, 0, 0, 0, 0, + 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 11, 12, 0, 13, 0, 14, 15, 16, 0, 0, + 0, 0, 0, 1, 17, 18, 0, 19, 7, 1, 0, 0, 0, 20, 20, 7, + 20, 20, 20, 20, 20, 20, 20, 8, 21, 0, 22, 0, 7, 23, 24, 0, + 20, 20, 25, 0, 0, 0, 26, 27, 1, 7, 20, 20, 20, 20, 20, 1, + 28, 29, 30, 31, 0, 0, 20, 0, 0, 0, 0, 0, 0, 0, 10, 0, + 0, 0, 0, 0, 0, 0, 20, 20, 20, 1, 0, 0, 8, 21, 32, 4, + 0, 10, 0, 33, 7, 20, 20, 20, 0, 0, 0, 0, 8, 34, 34, 35, + 36, 34, 37, 0, 38, 1, 20, 20, 0, 0, 39, 0, 1, 1, 0, 8, + 21, 1, 20, 0, 0, 0, 1, 0, 0, 40, 1, 1, 0, 0, 8, 21, + 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 26, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 21, 7, 20, 41, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 21, 0, 42, 43, 44, 0, 45, 0, 8, 21, 0, 0, 0, 0, 0, + 0, 0, 0, 46, 7, 1, 10, 1, 0, 0, 0, 1, 20, 20, 1, 0, + 0, 0, 0, 0, 0, 0, 20, 20, 1, 20, 20, 0, 0, 0, 0, 0, + 0, 0, 26, 21, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 3, 47, 48, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, + 4, 5, 6, 7, 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, + 10, 11, 12, 12, 12, 12, 13, 14, 14, 14, 14, 15, 16, 17, 18, 19, + 20, 14, 21, 14, 22, 14, 14, 14, 14, 23, 24, 24, 25, 26, 14, 14, + 14, 14, 27, 28, 14, 14, 29, 30, 31, 32, 33, 34, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 35, 7, 36, 37, 7, 38, 7, 7, 7, 39, 14, 40, 7, 7, 41, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 42, 0, 0, 1, + 2, 2, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 32, 33, 34, 35, 36, 37, 37, 37, 37, 37, 38, 39, 40, 41, 42, + 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 2, 2, 53, 54, 55, 56, + 57, 58, 59, 59, 59, 59, 60, 59, 59, 59, 59, 59, 59, 59, 61, 61, + 59, 59, 59, 59, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, + 74, 75, 76, 77, 78, 59, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 79, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 80, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 82, 83, 83, 84, 85, 86, 87, 88, 89, + 90, 91, 92, 93, 94, 95, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 96, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 70, 70, 98, 99,100,101,102,102,103,104,105,106,107,108,109,110, + 111,112, 97,113,114,115,116,117,118, 97,119,119,120, 97,121,122, + 123,124,125,126,127,128,129,130,131, 97,132,133,134,135,136,137, + 138,139,140,141,142, 97,143,144, 97,145,146,147,148, 97,149,150, + 151,152,153,154, 97, 97,155,156,157,158, 97,159, 97,160,161,161, + 161,161,161,161,161,162,163,161,164, 97, 97, 97, 97, 97,165,165, + 165,165,165,165,165,165,166, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97,167,167,167,167,168, 97, 97, 97,169,169, + 169,169,170,171,172,173, 97, 97, 97, 97,174,175,176,177,178,178, + 178,178,178,178,178,178,178,178,178,178,178,178,178,178,178,178, + 178,178,178,178,178,178,178,178,178,178,178,178,178,179,178,178, + 178,178,178,178,180,180,180,181,182, 97, 97, 97, 97, 97,183,184, + 185,186,186,187, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97,188,189, 97, 97, 97, 97, 97, 97, 59,190, + 191,192,193,194,195, 97,196,197,198, 59, 59,199, 59,200,201,201, + 201,201,201,202, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,203, 97, + 204, 97, 97,205, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97,206,207, + 208, 97, 97, 97, 97, 97,209,210,211, 97,212,213, 97, 97,214,215, + 59,216,217, 97, 59, 59, 59, 59, 59, 59, 59,218,219,220,221,222, + 223,224,225,226, 59,227, 97, 97, 97, 97, 97, 97, 97, 97, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,228, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,229, 70,230, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, + 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70,231, 70, 70, 70, 70, + 70, 70, 70, 70, 70,232, 97, 97, 97, 97, 97, 97, 97, 97, 70, 70, + 70, 70,233, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 70, 70, + 70, 70, 70, 70,234, 97, 97, 97, 97, 97, 97, 97, 97, 97,235, 97, + 236,237, 0, 1, 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 19, 19, 0, 19, 0, + 0, 0, 0, 0, 0, 0, 19, 19, 19, 19, 19, 0, 0, 0, 0, 0, + 26, 26, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, + 9, 9, 0, 9, 9, 9, 2, 2, 9, 9, 9, 9, 0, 9, 2, 2, + 2, 2, 9, 0, 9, 0, 9, 9, 9, 2, 9, 2, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, + 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 6, 2, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 2, 4, 4, 4, 2, 2, 4, 4, 4, 2, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 2, + 2, 2, 2, 2, 2, 2, 14, 14, 14, 2, 2, 2, 2, 14, 14, 14, + 14, 14, 14, 2, 2, 2, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, + 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 0, 3, 2, 3, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 1, 3, + 3, 3, 3, 3, 3, 3, 37, 37, 37, 37, 37, 37, 37, 37, 37, 37, + 37, 37, 37, 37, 2, 37, 37, 37, 37, 2, 2, 37, 37, 37, 38, 38, + 38, 38, 38, 38, 38, 38, 38, 38, 2, 2, 2, 2, 2, 2, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 2, 2, 64, 64, 64, 90, 90, + 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 2, 2, 90, 90, + 90, 90, 90, 90, 90, 2, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, + 95, 95, 2, 2, 95, 2, 37, 37, 37, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 2, 3, 3, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, + 0, 3, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, + 1, 1, 1, 7, 7, 7, 7, 7, 7, 7, 0, 0, 7, 7, 5, 5, + 5, 5, 2, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 5, 5, 2, + 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, + 5, 5, 5, 5, 5, 5, 5, 2, 5, 2, 2, 2, 5, 5, 5, 5, + 2, 2, 5, 5, 5, 5, 5, 2, 2, 5, 5, 5, 5, 2, 2, 2, + 2, 2, 2, 2, 2, 5, 2, 2, 2, 2, 5, 5, 2, 5, 5, 5, + 5, 5, 2, 2, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 2, 11, + 11, 11, 2, 11, 11, 11, 11, 11, 11, 2, 2, 2, 2, 11, 11, 2, + 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, + 11, 11, 11, 11, 11, 11, 11, 2, 11, 11, 2, 11, 11, 2, 11, 11, + 2, 2, 11, 2, 11, 11, 11, 2, 2, 11, 11, 11, 2, 2, 2, 11, + 2, 2, 2, 2, 2, 2, 2, 11, 11, 11, 11, 2, 11, 2, 2, 2, + 2, 2, 2, 2, 11, 11, 11, 11, 11, 11, 11, 11, 11, 2, 2, 10, + 10, 10, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, + 2, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 2, + 10, 10, 10, 10, 10, 10, 10, 2, 10, 10, 2, 10, 10, 10, 10, 10, + 2, 2, 10, 10, 10, 10, 10, 10, 2, 10, 10, 10, 2, 2, 10, 2, + 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 2, 2, 10, 10, 10, 10, + 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 2, 21, + 21, 21, 2, 21, 21, 21, 21, 21, 21, 21, 21, 2, 2, 21, 21, 2, + 2, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 2, + 21, 21, 21, 21, 21, 21, 21, 2, 21, 21, 2, 21, 21, 21, 21, 21, + 2, 2, 21, 21, 21, 21, 21, 2, 2, 21, 21, 21, 2, 2, 2, 2, + 2, 2, 2, 21, 21, 21, 2, 2, 2, 2, 21, 21, 2, 21, 21, 21, + 21, 21, 2, 2, 21, 21, 2, 2, 22, 22, 2, 22, 22, 22, 22, 22, + 22, 2, 2, 2, 22, 22, 22, 2, 22, 22, 22, 22, 2, 2, 2, 22, + 22, 2, 22, 2, 22, 22, 2, 2, 2, 22, 22, 2, 2, 2, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 2, 2, 2, 2, 22, 22, 22, 2, + 2, 2, 2, 2, 2, 22, 2, 2, 2, 2, 2, 2, 22, 22, 22, 22, + 22, 2, 2, 2, 2, 2, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 2, 23, 23, 23, 2, 23, 23, 23, 23, 23, 23, 23, 23, + 2, 2, 2, 23, 23, 23, 23, 2, 23, 23, 23, 23, 2, 2, 2, 2, + 2, 2, 2, 23, 23, 2, 23, 23, 23, 2, 2, 2, 2, 2, 23, 23, + 23, 23, 2, 2, 23, 23, 2, 2, 2, 2, 2, 2, 2, 23, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 2, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 16, + 2, 2, 16, 16, 16, 16, 16, 2, 16, 16, 16, 16, 2, 2, 2, 2, + 2, 2, 2, 16, 16, 2, 2, 2, 2, 2, 2, 2, 16, 2, 16, 16, + 16, 16, 2, 2, 16, 16, 2, 16, 16, 2, 2, 2, 2, 2, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 2, 20, 20, 20, 2, + 20, 20, 20, 20, 20, 20, 2, 2, 2, 2, 20, 20, 20, 20, 20, 20, + 20, 20, 2, 2, 20, 20, 2, 36, 36, 36, 2, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 36, 36, 2, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 2, 36, 2, 2, 2, 2, 36, 2, 2, 2, 2, 36, 36, 36, + 36, 36, 36, 2, 36, 2, 2, 2, 2, 2, 2, 2, 36, 36, 2, 2, + 36, 36, 36, 2, 2, 2, 2, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 2, 2, 2, 2, 0, 24, 24, + 24, 24, 2, 2, 2, 2, 2, 18, 18, 2, 18, 2, 18, 18, 18, 18, + 18, 2, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 2, 18, 2, 18, 18, 18, 18, 18, 18, 18, 2, 2, 18, 18, + 18, 18, 18, 2, 18, 2, 18, 18, 2, 2, 18, 18, 18, 18, 25, 25, + 25, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, 25, 25, 25, 25, 25, + 25, 25, 25, 2, 2, 2, 25, 25, 25, 25, 25, 2, 25, 25, 25, 25, + 25, 25, 25, 0, 0, 0, 0, 25, 25, 2, 2, 2, 2, 2, 33, 33, + 33, 33, 33, 33, 33, 33, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 2, 8, 2, 2, 2, 2, 2, 8, 2, 2, 8, 8, + 8, 0, 8, 8, 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 2, 30, 30, 30, 30, 2, 2, 30, 30, + 30, 30, 30, 30, 30, 2, 30, 30, 30, 2, 2, 30, 30, 30, 30, 30, + 30, 30, 30, 2, 2, 2, 30, 30, 2, 2, 2, 2, 2, 2, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 2, 2, 28, 28, + 28, 28, 28, 28, 28, 28, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 2, 2, 2, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 0, 0, 0, 35, 35, 35, 2, 2, 2, 2, 2, 2, 2, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 2, 45, 45, 45, 45, + 45, 45, 45, 2, 2, 2, 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 0, 0, 2, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 43, 2, 2, 2, 2, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 2, 46, 46, 46, 2, 46, 46, 2, 2, 2, 2, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 2, 2, 31, 31, + 2, 2, 2, 2, 2, 2, 32, 32, 0, 0, 32, 0, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 2, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, 2, 2, 2, 32, 32, + 32, 2, 2, 2, 2, 2, 28, 28, 28, 28, 28, 28, 2, 2, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 2, 48, 48, + 48, 48, 2, 2, 2, 2, 48, 2, 2, 2, 48, 48, 48, 48, 52, 52, + 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 2, 2, 52, 52, + 52, 52, 52, 2, 2, 2, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 2, 2, 2, 2, 58, 58, 2, 2, 2, 2, 2, 2, 58, 58, + 58, 2, 2, 2, 58, 58, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 2, 2, 54, 54, 91, 91, 91, 91, 91, 91, 91, 91, 91, 91, + 91, 91, 91, 91, 91, 2, 91, 91, 91, 91, 91, 2, 2, 91, 91, 91, + 2, 2, 2, 2, 2, 2, 91, 91, 91, 91, 91, 91, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 2, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 2, 2, 2, 2, 62, 62, 62, 62, 62, 2, 2, 2, 76, 76, + 76, 76, 76, 76, 76, 76, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, + 93, 93, 2, 2, 2, 2, 2, 2, 2, 2, 93, 93, 93, 93, 70, 70, + 70, 70, 70, 70, 70, 70, 2, 2, 2, 70, 70, 70, 70, 70, 70, 70, + 2, 2, 2, 70, 70, 70, 73, 73, 73, 73, 73, 73, 73, 73, 6, 2, + 2, 2, 2, 2, 2, 2, 8, 8, 8, 2, 2, 8, 8, 8, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, + 0, 2, 2, 2, 2, 2, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, + 9, 6, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 9, 9, 9, 9, + 19, 19, 19, 19, 9, 9, 9, 9, 9, 19, 19, 19, 19, 19, 6, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 1, 1, + 2, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 2, 2, 2, 9, + 2, 9, 2, 9, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 9, + 9, 9, 2, 2, 9, 9, 9, 9, 9, 9, 2, 9, 9, 9, 2, 2, + 9, 9, 9, 2, 9, 9, 9, 9, 9, 9, 9, 9, 9, 2, 0, 0, + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 19, + 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 0, 2, 19, 19, 19, 19, 19, 2, 2, 2, 0, 0, + 0, 0, 0, 0, 9, 0, 0, 0, 19, 19, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 19, 0, 19, 0, 0, 0, 2, 2, 2, 2, 0, 0, + 0, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, 27, 0, 0, + 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 2, 55, 55, + 55, 55, 2, 2, 2, 2, 2, 55, 55, 55, 55, 55, 55, 55, 61, 61, + 61, 61, 61, 61, 61, 61, 2, 2, 2, 2, 2, 2, 2, 61, 61, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 2, 13, 13, 13, 13, 13, 13, 13, 13, 13, 2, 2, 2, 2, 13, 13, + 13, 13, 13, 13, 2, 2, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, + 0, 0, 0, 13, 0, 13, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 1, 1, 1, 1, 12, 12, 13, 13, 13, 13, 0, 0, 0, 0, 2, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 2, 2, 1, 1, 0, 0, 15, 15, 15, 0, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 0, 0, 17, 17, 17, 2, 2, 2, 2, 2, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 2, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 2, 12, 12, 12, 12, 12, 12, 12, 0, 17, 17, + 17, 17, 17, 17, 17, 0, 13, 13, 13, 13, 13, 2, 2, 2, 39, 39, + 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 2, 2, 2, 39, 39, + 39, 39, 39, 39, 39, 2, 86, 86, 86, 86, 86, 86, 86, 86, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 2, 2, 2, 2, 79, 79, + 79, 79, 79, 79, 79, 79, 0, 0, 19, 19, 19, 19, 19, 19, 0, 0, + 0, 19, 19, 19, 19, 19, 2, 2, 19, 19, 19, 19, 19, 19, 19, 19, + 19, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 19, 19, 19, 60, 60, + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 2, 2, 2, 0, 0, + 2, 2, 2, 2, 2, 2, 65, 65, 65, 65, 65, 65, 65, 65, 75, 75, + 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 2, 2, 2, 2, + 2, 2, 2, 2, 75, 75, 75, 75, 2, 2, 2, 2, 2, 2, 69, 69, + 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 0, 69, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 74, 12, 12, 12, 12, 12, 2, 2, 2, 84, 84, + 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 2, 0, 84, 84, + 2, 2, 2, 2, 84, 84, 33, 33, 33, 33, 33, 33, 33, 2, 68, 68, + 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 2, 68, 68, + 68, 68, 68, 68, 2, 2, 68, 68, 2, 2, 68, 68, 68, 68, 92, 92, + 92, 92, 92, 92, 92, 92, 92, 92, 92, 2, 2, 2, 2, 2, 2, 2, + 2, 92, 92, 92, 92, 92, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 2, 2, 30, 30, 30, 30, 30, 30, 2, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, 19, 19, 19, 9, 19, 19, 19, 19, + 0, 0, 2, 2, 2, 2, 87, 87, 87, 87, 87, 87, 2, 2, 87, 87, + 2, 2, 2, 2, 2, 2, 12, 12, 12, 12, 2, 2, 2, 2, 2, 2, + 2, 12, 12, 12, 12, 12, 13, 13, 2, 2, 2, 2, 2, 2, 19, 19, + 19, 19, 19, 19, 19, 2, 2, 2, 2, 4, 4, 4, 4, 4, 2, 2, + 2, 2, 2, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 2, 14, 14, + 14, 14, 14, 2, 14, 2, 14, 14, 2, 14, 14, 2, 14, 14, 3, 3, + 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 0, 0, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 1, 1, + 1, 1, 1, 1, 6, 6, 0, 0, 0, 2, 0, 0, 0, 0, 3, 3, + 3, 3, 3, 2, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17, 17, 0, 0, 2, 2, + 12, 12, 12, 12, 12, 12, 2, 2, 12, 12, 12, 2, 2, 2, 2, 0, + 0, 0, 0, 0, 2, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 2, 49, 49, + 49, 2, 49, 49, 2, 49, 49, 49, 49, 49, 49, 49, 2, 2, 49, 49, + 49, 2, 2, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, + 0, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 2, 2, 2, 9, 2, + 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 1, 2, 2, 71, 71, + 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 71, 2, 2, 2, 67, 67, + 67, 67, 67, 67, 67, 67, 67, 2, 2, 2, 2, 2, 2, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, + 42, 42, 2, 2, 2, 2, 2, 2, 2, 2, 2, 42, 42, 42, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 41, 41, 2, 2, 2, 2, 2,118,118, + 118,118,118,118,118,118,118,118,118, 2, 2, 2, 2, 2, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 2, 53, 59, 59, + 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 2, 2, 2, 2, 59, 59, + 59, 59, 59, 59, 2, 2, 40, 40, 40, 40, 40, 40, 40, 40, 51, 51, + 51, 51, 51, 51, 51, 51, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, + 50, 50, 50, 50, 2, 2, 50, 50, 2, 2, 2, 2, 2, 2,135,135, + 135,135,135,135,135,135,135,135,135,135, 2, 2, 2, 2,106,106, + 106,106,106,106,106,106,104,104,104,104,104,104,104,104,104,104, + 104,104, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,104,110,110, + 110,110,110,110,110,110,110,110,110,110,110,110,110, 2,110,110, + 110,110,110,110, 2, 2, 47, 47, 47, 47, 47, 47, 2, 2, 47, 2, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 2, 47, 47, 2, 2, 2, 47, 2, 2, 47, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 2, 81,120,120, + 120,120,120,120,120,120,116,116,116,116,116,116,116,116,116,116, + 116,116,116,116,116, 2, 2, 2, 2, 2, 2, 2, 2,116,128,128, + 128,128,128,128,128,128,128,128,128, 2,128,128, 2, 2, 2, 2, + 2,128,128,128,128,128, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 66, 2, 2, 2, 66, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, + 2, 2, 2, 2, 2, 72, 98, 98, 98, 98, 98, 98, 98, 98, 97, 97, + 97, 97, 97, 97, 97, 97, 2, 2, 2, 2, 97, 97, 97, 97, 2, 2, + 97, 97, 97, 97, 97, 97, 57, 57, 57, 57, 2, 57, 57, 2, 2, 2, + 2, 2, 57, 57, 57, 57, 57, 57, 57, 57, 2, 57, 57, 57, 2, 57, + 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, + 57, 57, 57, 57, 2, 2, 57, 57, 57, 2, 2, 2, 2, 57, 57, 2, + 2, 2, 2, 2, 2, 2, 88, 88, 88, 88, 88, 88, 88, 88,117,117, + 117,117,117,117,117,117,112,112,112,112,112,112,112,112,112,112, + 112,112,112,112,112, 2, 2, 2, 2,112,112,112,112,112, 78, 78, + 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, 2, 2, 2, 78, + 78, 78, 78, 78, 78, 78, 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 2, 2, 82, 82, 82, 82, 82, 82, 82, 82, 82, 82, + 82, 2, 2, 2, 2, 2,122,122,122,122,122,122,122,122,122,122, + 2, 2, 2, 2, 2, 2, 2,122,122,122,122, 2, 2, 2, 2,122, + 122,122,122,122,122,122, 89, 89, 89, 89, 89, 89, 89, 89, 89, 2, + 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,130,130,130,130, + 130, 2, 2, 2, 2, 2, 2, 2,130,130,130,130,130,130,144,144, + 144,144,144,144,144,144,144,144, 2, 2, 2, 2, 2, 2, 3, 3, + 3, 3, 3, 3, 3, 2,156,156,156,156,156,156,156,156,156,156, + 2,156,156,156, 2, 2,156,156, 2, 2, 2, 2, 2, 2,147,147, + 147,147,147,147,147,147,148,148,148,148,148,148,148,148,148,148, + 2, 2, 2, 2, 2, 2,153,153,153,153,153,153,153,153,153,153, + 153,153, 2, 2, 2, 2,149,149,149,149,149,149,149,149,149,149, + 149,149,149,149,149, 2, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 2, 2, 2, 2, 94, 94, 94, 94, 94, 94, 2, 2, + 2, 2, 2, 2, 2, 94, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 85, 2, 2,101,101, + 101,101,101,101,101,101,101, 2, 2, 2, 2, 2, 2, 2,101,101, + 2, 2, 2, 2, 2, 2, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, + 96, 96, 96, 2, 96, 96,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111, 2,100,100,100,100,100,100,100,100, 2, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 2, 2, 2,108,108, + 108,108,108,108,108,108,108,108, 2,108,108,108,108,108,108,108, + 108,108,108,108,108, 2,129,129,129,129,129,129,129, 2,129, 2, + 129,129,129,129, 2,129,129,129,129,129,129,129,129,129,129,129, + 129,129,129,129, 2,129,129,129, 2, 2, 2, 2, 2, 2,109,109, + 109,109,109,109,109,109,109,109,109, 2, 2, 2, 2, 2,109,109, + 2, 2, 2, 2, 2, 2,107,107,107,107, 2,107,107,107,107,107, + 107,107,107, 2, 2,107,107, 2, 2,107,107,107,107,107,107,107, + 107,107,107,107,107,107,107, 2,107,107,107,107,107,107,107, 2, + 107,107, 2,107,107,107,107,107, 2, 1,107,107,107,107,107, 2, + 2,107,107,107, 2, 2,107, 2, 2, 2, 2, 2, 2,107, 2, 2, + 2, 2, 2,107,107,107,107,107,107,107, 2, 2,107,107,107,107, + 107,107,107, 2, 2, 2,137,137,137,137,137,137,137,137,137,137, + 137,137, 2,137,137,137,137,137, 2, 2, 2, 2, 2, 2,124,124, + 124,124,124,124,124,124,124,124, 2, 2, 2, 2, 2, 2,123,123, + 123,123,123,123,123,123,123,123,123,123,123,123, 2, 2,114,114, + 114,114,114,114,114,114,114,114,114,114,114, 2, 2, 2,114,114, + 2, 2, 2, 2, 2, 2, 32, 32, 32, 32, 32, 2, 2, 2,102,102, + 102,102,102,102,102,102,102, 2, 2, 2, 2, 2, 2, 2,102,102, + 2, 2, 2, 2, 2, 2,126,126,126,126,126,126,126,126,126,126, + 126, 2, 2,126,126,126,126,126,126,126, 2, 2, 2, 2,142,142, + 142,142,142,142,142,142,142,142,142,142, 2, 2, 2, 2,125,125, + 125,125,125,125,125,125,125,125,125, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2,125,154,154,154,154,154,154,154, 2, 2,154, + 2, 2,154,154,154,154,154,154,154,154, 2,154,154, 2,154,154, + 154,154,154,154,154,154,154,154,154,154,154,154, 2,154,154, 2, + 2,154,154,154,154,154,154,154, 2, 2, 2, 2, 2, 2,150,150, + 150,150,150,150,150,150, 2, 2,150,150,150,150,150,150,150,150, + 150,150,150, 2, 2, 2,141,141,141,141,141,141,141,141,140,140, + 140,140,140,140,140,140,140,140,140, 2, 2, 2, 2, 2,121,121, + 121,121,121,121,121,121,121, 2, 2, 2, 2, 2, 2, 2,133,133, + 133,133,133,133,133,133,133, 2,133,133,133,133,133,133,133,133, + 133,133,133,133,133, 2,133,133,133,133,133,133, 2, 2,133,133, + 133,133,133, 2, 2, 2,134,134,134,134,134,134,134,134, 2, 2, + 134,134,134,134,134,134, 2,134,134,134,134,134,134,134,134,134, + 134,134,134,134,134, 2,138,138,138,138,138,138,138, 2,138,138, + 2,138,138,138,138,138,138,138,138,138,138,138,138,138, 2, 2, + 138, 2,138,138, 2,138,138,138, 2, 2, 2, 2, 2, 2,143,143, + 143,143,143,143, 2,143,143, 2,143,143,143,143,143,143,143,143, + 143,143,143,143,143,143,143,143,143,143,143,143,143, 2,143,143, + 2,143,143,143,143,143,143, 2, 2, 2, 2, 2, 2, 2,143,143, + 2, 2, 2, 2, 2, 2,145,145,145,145,145,145,145,145,145, 2, + 2, 2, 2, 2, 2, 2, 86, 2, 2, 2, 2, 2, 2, 2, 22, 22, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 22, 63, 63, + 63, 63, 63, 63, 63, 63, 63, 63, 2, 2, 2, 2, 2, 2, 63, 63, + 63, 63, 63, 63, 63, 2, 63, 63, 63, 63, 63, 2, 2, 2, 63, 63, + 63, 63, 2, 2, 2, 2, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 2, 80, 2, 2, 2, 2, 2, 2, 2,127,127, + 127,127,127,127,127,127,127,127,127,127,127,127,127, 2, 79, 2, + 2, 2, 2, 2, 2, 2,115,115,115,115,115,115,115,115,115,115, + 115,115,115,115,115, 2,115,115, 2, 2, 2, 2,115,115,103,103, + 103,103,103,103,103,103,103,103,103,103,103,103, 2, 2,119,119, + 119,119,119,119,119,119,119,119,119,119,119,119, 2, 2,119,119, + 2,119,119,119,119,119, 2, 2, 2, 2, 2,119,119,119,146,146, + 146,146,146,146,146,146,146,146,146, 2, 2, 2, 2, 2, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 2, 2, 2, 2, 99, 2, 2, + 2, 2, 2, 2, 2, 99,136,139, 0, 0,155, 2, 2, 2,136,136, + 136,136,136,136,136,136,155,155,155,155,155,155,155,155,155,155, + 155,155,155,155, 2, 2,136, 2, 2, 2, 2, 2, 2, 2, 17, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 17, 17, 17, 17,139,139,139,139,139,139,139,139,139,139, + 139,139, 2, 2, 2, 2,105,105,105,105,105,105,105,105,105,105, + 105, 2, 2, 2, 2, 2,105,105,105,105,105, 2, 2, 2,105, 2, + 2, 2, 2, 2, 2, 2,105,105, 2, 2,105,105,105,105, 0, 0, + 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, + 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, + 0, 2, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, + 0, 0, 0, 2, 0, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0,131,131,131,131,131,131,131,131,131,131, + 131,131, 2, 2, 2, 2, 2, 2, 2,131,131,131,131,131, 2,131, + 131,131,131,131,131,131, 56, 2, 2, 56, 56, 56, 56, 56, 56, 56, + 2, 56, 56, 2, 56, 56, 56, 56, 56, 2, 2, 2, 2, 2,151,151, + 151,151,151,151,151,151,151,151,151,151,151, 2, 2, 2,151,151, + 151,151,151,151, 2, 2,151,151, 2, 2, 2, 2,151,151,152,152, + 152,152,152,152,152,152,152,152, 2, 2, 2, 2, 2,152,113,113, + 113,113,113,113,113,113,113,113,113,113,113, 2, 2,113,113,113, + 113,113,113,113,113, 2,132,132,132,132,132,132,132,132,132,132, + 132,132, 2, 2, 2, 2,132,132, 2, 2, 2, 2,132,132, 3, 3, + 3, 3, 2, 3, 3, 3, 2, 3, 3, 2, 3, 2, 2, 3, 2, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 2, 3, + 2, 3, 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, 3, 2, 3, + 2, 3, 2, 3, 3, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 3, 3, 3, 2, 3, 2, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, + 2, 2, 2, 2, 0, 0, 15, 0, 0, 2, 2, 2, 2, 2, 13, 2, + 2, 2, 2, 2, 2, 2, 13, 13, 13, 2, 2, 2, 2, 2, 2, 0, + 2, 2, 2, 2, 2, 2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 9, 9, 9, 10, 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 16, 17, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, + 20, 9, 21, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, + 29, 30, 0, 0, 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, + 36, 37, 38, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, + 46, 47, 0, 0, 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, + 53, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, + 55, 0, 0, 0, 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, + 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, + 0, 0, 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, + 99,100,101,102,103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0, + 107, 0, 0, 0,108, 0,109, 0,110, 0,111,112,113, 0,114, 0, + 0, 0,115, 0, 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,118,119,120,121, 0,122,123,124, + 125,126, 0,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,128,129,130,131,132,133,134,135,136,137,138,139, + 140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155, + 156,157, 0, 0, 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, + 0, 0, 0, 0, 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171, + 172, 0, 0, 0,173,174,175,176,177,178,179,180,181,182,183,184, + 185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200, + 201,202,203,204,205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 3, 4, +}; +static const uint16_t +_hb_ucd_u16[9080] = +{ + 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, + 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, + 13, 13, 13, 24, 25, 11, 11, 11, 11, 26, 11, 27, 28, 29, 30, 31, + 32, 32, 32, 32, 32, 32, 32, 33, 34, 35, 36, 11, 37, 38, 13, 39, + 9, 9, 9, 11, 11, 11, 13, 13, 40, 13, 13, 13, 41, 13, 13, 13, + 13, 13, 13, 42, 9, 43, 11, 11, 44, 45, 32, 46, 47, 48, 49, 50, + 51, 52, 48, 48, 53, 32, 54, 55, 48, 48, 48, 48, 48, 56, 57, 58, + 59, 60, 48, 32, 61, 48, 48, 48, 48, 48, 62, 63, 64, 48, 65, 66, + 48, 67, 68, 69, 48, 70, 71, 72, 72, 72, 48, 73, 74, 75, 76, 32, + 77, 48, 48, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, + 91, 84, 85, 92, 93, 94, 95, 96, 97, 98, 85, 99, 100, 101, 89, 102, + 103, 84, 85, 104, 105, 106, 89, 107, 108, 109, 110, 111, 112, 113, 95, 114, + 115, 116, 85, 117, 118, 119, 89, 120, 121, 116, 85, 122, 123, 124, 89, 125, + 126, 116, 48, 127, 128, 129, 89, 130, 131, 132, 48, 133, 134, 135, 95, 136, + 137, 48, 48, 138, 139, 140, 72, 72, 141, 48, 142, 143, 144, 145, 72, 72, + 146, 147, 148, 149, 150, 48, 151, 152, 153, 154, 32, 155, 156, 157, 72, 72, + 48, 48, 158, 159, 160, 161, 162, 163, 164, 165, 9, 9, 166, 11, 11, 167, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 168, 169, 48, 48, + 168, 48, 48, 170, 171, 172, 48, 48, 48, 171, 48, 48, 48, 173, 174, 175, + 48, 176, 9, 9, 9, 9, 9, 177, 178, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 179, 48, 180, 181, 48, 48, 48, 48, 182, 183, + 184, 185, 48, 186, 48, 187, 184, 188, 48, 48, 48, 189, 190, 191, 192, 193, + 194, 192, 48, 48, 195, 48, 48, 196, 197, 48, 198, 48, 48, 48, 48, 199, + 48, 200, 201, 202, 203, 48, 204, 205, 48, 48, 206, 48, 207, 208, 209, 209, + 48, 210, 48, 48, 48, 211, 212, 213, 192, 192, 214, 215, 216, 72, 72, 72, + 217, 48, 48, 218, 219, 160, 220, 221, 222, 48, 223, 64, 48, 48, 224, 225, + 48, 48, 226, 227, 228, 64, 48, 229, 230, 9, 9, 231, 232, 233, 234, 235, + 11, 11, 236, 27, 27, 27, 237, 238, 11, 239, 27, 27, 32, 32, 32, 240, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 241, 13, 13, 13, 13, 13, 13, + 242, 243, 242, 242, 243, 244, 242, 245, 246, 246, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 262, 72, 263, 264, 216, + 265, 266, 267, 268, 269, 270, 271, 271, 272, 273, 274, 209, 275, 276, 209, 277, + 278, 278, 278, 278, 278, 278, 278, 278, 279, 209, 280, 209, 209, 209, 209, 281, + 209, 282, 278, 283, 209, 284, 285, 209, 209, 209, 286, 72, 287, 72, 270, 270, + 270, 288, 209, 209, 209, 209, 289, 270, 209, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 209, 290, 291, 209, 209, 292, 209, 209, 209, 209, 209, 209, 293, 209, + 209, 209, 209, 209, 209, 209, 294, 295, 270, 296, 209, 209, 297, 278, 298, 278, + 299, 300, 278, 278, 278, 301, 278, 302, 209, 209, 209, 278, 303, 209, 209, 304, + 209, 305, 209, 209, 209, 209, 209, 209, 9, 9, 306, 11, 11, 307, 308, 309, + 13, 13, 13, 13, 13, 13, 310, 311, 11, 11, 312, 48, 48, 48, 313, 314, + 48, 315, 316, 316, 316, 316, 32, 32, 317, 318, 319, 320, 321, 322, 72, 72, + 209, 323, 209, 209, 209, 209, 209, 324, 209, 209, 209, 209, 209, 325, 72, 326, + 327, 328, 329, 330, 137, 48, 48, 48, 48, 331, 178, 48, 48, 48, 48, 332, + 333, 48, 48, 137, 48, 48, 48, 48, 200, 334, 48, 48, 209, 209, 324, 48, + 209, 335, 336, 209, 337, 338, 209, 209, 336, 209, 209, 338, 209, 209, 209, 209, + 48, 48, 48, 48, 209, 209, 209, 209, 48, 48, 48, 48, 48, 48, 48, 151, + 48, 339, 48, 48, 48, 48, 48, 48, 151, 209, 209, 209, 286, 48, 48, 229, + 340, 48, 341, 72, 13, 13, 342, 343, 13, 344, 48, 48, 48, 48, 345, 346, + 31, 347, 348, 349, 13, 13, 13, 350, 351, 352, 353, 354, 355, 72, 72, 356, + 357, 48, 358, 359, 48, 48, 48, 360, 361, 48, 48, 362, 363, 192, 32, 364, + 64, 48, 365, 48, 366, 367, 48, 151, 77, 48, 48, 368, 369, 370, 371, 372, + 48, 48, 373, 374, 375, 376, 48, 377, 48, 48, 48, 378, 379, 380, 381, 382, + 383, 384, 316, 11, 11, 385, 386, 11, 11, 11, 11, 11, 48, 48, 387, 192, + 48, 48, 388, 48, 389, 48, 48, 206, 390, 390, 390, 390, 390, 390, 390, 390, + 391, 391, 391, 391, 391, 391, 391, 391, 48, 48, 48, 48, 48, 48, 204, 48, + 48, 48, 48, 48, 48, 207, 72, 72, 392, 393, 394, 395, 396, 48, 48, 48, + 48, 48, 48, 397, 398, 399, 48, 48, 48, 48, 48, 400, 72, 48, 48, 48, + 48, 401, 48, 48, 74, 72, 72, 402, 32, 403, 32, 404, 405, 406, 407, 73, + 48, 48, 48, 48, 48, 48, 48, 408, 409, 2, 3, 4, 5, 410, 411, 412, + 48, 413, 48, 200, 414, 415, 416, 417, 418, 48, 172, 419, 204, 204, 72, 72, + 48, 48, 48, 48, 48, 48, 48, 71, 420, 270, 270, 421, 271, 271, 271, 422, + 423, 424, 425, 72, 72, 209, 209, 426, 72, 72, 72, 72, 72, 72, 72, 72, + 48, 151, 48, 48, 48, 101, 427, 428, 48, 48, 429, 48, 430, 48, 48, 431, + 48, 432, 48, 48, 433, 434, 72, 72, 9, 9, 435, 11, 11, 48, 48, 48, + 48, 204, 192, 9, 9, 436, 11, 437, 48, 48, 74, 48, 48, 48, 438, 72, + 48, 48, 48, 315, 48, 199, 74, 72, 439, 48, 48, 440, 48, 441, 48, 442, + 48, 200, 443, 72, 72, 72, 48, 444, 48, 445, 48, 446, 72, 72, 72, 72, + 48, 48, 48, 447, 270, 448, 270, 270, 449, 450, 48, 451, 452, 453, 48, 454, + 48, 455, 72, 72, 456, 48, 457, 458, 48, 48, 48, 459, 48, 460, 48, 461, + 48, 462, 463, 72, 72, 72, 72, 72, 48, 48, 48, 48, 196, 72, 72, 72, + 9, 9, 9, 464, 11, 11, 11, 465, 48, 48, 466, 192, 72, 72, 72, 72, + 72, 72, 72, 72, 72, 72, 270, 467, 48, 48, 468, 469, 72, 72, 72, 72, + 48, 455, 470, 48, 62, 471, 72, 72, 72, 72, 72, 48, 472, 72, 48, 315, + 473, 48, 48, 474, 475, 448, 476, 477, 222, 48, 48, 478, 479, 48, 196, 192, + 480, 48, 481, 482, 483, 48, 48, 484, 222, 48, 48, 485, 486, 487, 488, 489, + 48, 98, 490, 491, 72, 72, 72, 72, 492, 493, 494, 48, 48, 495, 496, 192, + 497, 84, 85, 498, 499, 500, 501, 502, 48, 48, 48, 503, 504, 505, 469, 72, + 48, 48, 48, 506, 507, 192, 72, 72, 48, 48, 508, 509, 510, 511, 72, 72, + 48, 48, 48, 512, 513, 192, 514, 72, 48, 48, 515, 516, 192, 72, 72, 72, + 48, 173, 517, 518, 72, 72, 72, 72, 48, 48, 490, 519, 72, 72, 72, 72, + 72, 72, 9, 9, 11, 11, 148, 520, 521, 522, 48, 523, 524, 192, 72, 72, + 72, 72, 525, 48, 48, 526, 527, 72, 528, 48, 48, 529, 530, 531, 48, 48, + 532, 533, 534, 72, 48, 48, 48, 196, 85, 48, 508, 535, 536, 148, 175, 537, + 48, 538, 539, 540, 72, 72, 72, 72, 541, 48, 48, 542, 543, 192, 544, 48, + 545, 546, 192, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 48, 547, + 72, 72, 72, 101, 270, 548, 549, 550, 48, 207, 72, 72, 72, 72, 72, 72, + 271, 271, 271, 271, 271, 271, 551, 552, 48, 48, 48, 48, 388, 72, 72, 72, + 48, 48, 200, 553, 72, 72, 72, 72, 48, 48, 48, 48, 315, 72, 72, 72, + 48, 48, 48, 196, 48, 200, 370, 72, 72, 72, 72, 72, 72, 48, 204, 554, + 48, 48, 48, 555, 556, 557, 558, 559, 48, 72, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 72, 9, 9, 11, 11, 270, 560, 72, 72, 72, 72, 72, 72, + 48, 48, 48, 48, 561, 562, 563, 563, 564, 565, 72, 72, 72, 72, 566, 567, + 48, 48, 48, 48, 48, 48, 48, 74, 48, 48, 48, 48, 48, 199, 72, 72, + 196, 72, 72, 72, 72, 72, 72, 72, 48, 200, 72, 72, 72, 568, 569, 48, + 48, 48, 48, 48, 48, 48, 48, 206, 48, 48, 48, 48, 48, 48, 71, 151, + 196, 570, 571, 72, 72, 72, 72, 72, 209, 209, 209, 209, 209, 209, 209, 325, + 209, 209, 572, 209, 209, 209, 573, 574, 575, 209, 576, 209, 209, 209, 577, 72, + 209, 209, 209, 209, 578, 72, 72, 72, 72, 72, 72, 72, 72, 72, 270, 579, + 209, 209, 209, 209, 209, 286, 270, 452, 9, 580, 11, 581, 582, 583, 242, 9, + 584, 585, 586, 587, 588, 9, 580, 11, 589, 590, 11, 591, 592, 593, 594, 9, + 595, 11, 9, 580, 11, 581, 582, 11, 242, 9, 584, 594, 9, 595, 11, 9, + 580, 11, 596, 9, 597, 598, 599, 600, 11, 601, 9, 602, 603, 604, 605, 11, + 606, 9, 607, 11, 608, 609, 609, 609, 32, 32, 32, 610, 32, 32, 611, 612, + 613, 614, 45, 72, 72, 72, 72, 72, 615, 616, 617, 72, 72, 72, 72, 72, + 48, 48, 151, 618, 619, 72, 72, 72, 72, 72, 72, 72, 48, 48, 620, 621, + 48, 48, 48, 48, 622, 623, 72, 72, 9, 9, 584, 11, 624, 370, 72, 72, + 72, 72, 72, 72, 72, 72, 72, 488, 270, 270, 625, 626, 72, 72, 72, 72, + 488, 270, 627, 628, 72, 72, 72, 72, 629, 48, 630, 631, 632, 633, 634, 635, + 636, 206, 637, 206, 72, 72, 72, 638, 209, 209, 326, 209, 209, 209, 209, 209, + 209, 324, 335, 639, 639, 639, 209, 325, 640, 209, 209, 209, 209, 209, 209, 209, + 209, 209, 641, 72, 72, 72, 642, 209, 643, 209, 209, 326, 577, 644, 325, 72, + 209, 209, 209, 209, 209, 209, 209, 645, 209, 209, 209, 209, 209, 646, 424, 424, + 209, 209, 209, 209, 209, 209, 209, 324, 209, 209, 209, 209, 209, 577, 326, 72, + 326, 209, 209, 209, 646, 176, 209, 209, 646, 209, 641, 644, 72, 72, 72, 72, + 209, 209, 209, 209, 209, 209, 209, 647, 209, 209, 209, 209, 648, 209, 209, 209, + 209, 209, 209, 209, 209, 324, 641, 649, 286, 209, 577, 286, 643, 286, 72, 72, + 209, 650, 209, 209, 287, 72, 72, 192, 48, 48, 48, 48, 48, 204, 72, 72, + 48, 48, 48, 205, 48, 48, 48, 48, 48, 204, 48, 48, 48, 48, 48, 48, + 48, 48, 469, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 101, 72, + 48, 204, 72, 72, 72, 72, 72, 72, 48, 48, 48, 48, 71, 72, 72, 72, + 651, 72, 652, 652, 652, 652, 652, 652, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 72, 391, 391, 391, 391, 391, 391, 391, 653, + 391, 391, 391, 391, 391, 391, 391, 654, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 2, 3, 1, 2, 2, 3, 0, 0, 0, 0, 0, 4, 0, 4, + 2, 2, 5, 2, 2, 2, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, + 0, 0, 0, 0, 7, 8, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 10, 11, 12, 13, 14, 14, 15, 14, 14, 14, + 14, 14, 14, 14, 16, 17, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 19, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 20, 21, + 21, 21, 22, 20, 21, 21, 21, 21, 21, 23, 24, 25, 25, 25, 25, 25, + 25, 26, 25, 25, 25, 27, 28, 26, 29, 30, 31, 32, 31, 31, 31, 31, + 33, 34, 35, 31, 31, 31, 36, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 29, 31, 31, 31, 31, 37, 38, 37, 37, 37, 37, 37, 37, + 37, 39, 31, 31, 31, 31, 31, 31, 40, 40, 40, 40, 40, 40, 41, 26, + 42, 42, 42, 42, 42, 42, 42, 43, 44, 44, 44, 44, 44, 45, 44, 46, + 47, 47, 47, 48, 37, 49, 26, 26, 26, 26, 26, 26, 31, 31, 50, 31, + 31, 26, 51, 31, 52, 31, 31, 31, 53, 53, 53, 53, 53, 53, 53, 53, + 53, 53, 54, 53, 55, 53, 53, 53, 56, 57, 58, 59, 59, 60, 61, 62, + 57, 63, 64, 65, 66, 59, 59, 67, 68, 69, 70, 71, 71, 72, 73, 74, + 69, 75, 76, 77, 78, 71, 79, 26, 80, 81, 82, 83, 83, 84, 85, 86, + 81, 87, 88, 26, 89, 83, 90, 91, 92, 93, 94, 95, 95, 96, 97, 98, + 93, 99, 100, 101, 102, 95, 95, 26, 103, 104, 105, 106, 107, 104, 108, 109, + 104, 105, 110, 26, 111, 108, 108, 112, 113, 114, 115, 113, 113, 115, 113, 116, + 114, 117, 118, 119, 120, 113, 121, 113, 122, 123, 124, 122, 122, 124, 125, 126, + 123, 127, 128, 129, 130, 122, 131, 26, 132, 133, 134, 132, 132, 132, 132, 132, + 133, 134, 135, 132, 136, 132, 132, 132, 137, 138, 139, 140, 138, 138, 141, 142, + 139, 143, 144, 138, 145, 138, 146, 26, 147, 148, 148, 148, 148, 148, 148, 149, + 148, 148, 148, 150, 26, 26, 26, 26, 151, 152, 153, 153, 154, 153, 153, 155, + 156, 155, 153, 157, 26, 26, 26, 26, 158, 158, 158, 158, 158, 158, 158, 158, + 158, 159, 158, 158, 158, 160, 159, 158, 158, 158, 158, 159, 158, 158, 158, 161, + 158, 161, 162, 163, 26, 26, 26, 26, 164, 164, 164, 164, 164, 164, 164, 164, + 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 164, 165, 165, 165, 165, + 166, 167, 165, 165, 165, 165, 165, 168, 169, 169, 169, 169, 169, 169, 169, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 170, 170, 170, 170, 170, 170, 170, 170, + 170, 171, 172, 171, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 171, 172, + 171, 170, 172, 170, 170, 170, 170, 170, 170, 170, 171, 170, 170, 170, 170, 170, + 170, 170, 170, 173, 170, 170, 170, 174, 170, 170, 170, 175, 176, 176, 176, 176, + 176, 176, 176, 176, 176, 176, 177, 177, 178, 178, 178, 178, 178, 178, 178, 178, + 178, 178, 178, 178, 178, 178, 178, 178, 179, 179, 179, 180, 181, 181, 181, 181, + 181, 181, 181, 181, 181, 182, 181, 183, 184, 185, 186, 26, 187, 187, 188, 26, + 189, 189, 190, 26, 191, 192, 193, 26, 194, 194, 194, 194, 194, 194, 194, 194, + 194, 194, 194, 195, 194, 196, 194, 196, 197, 198, 199, 200, 199, 199, 199, 199, + 199, 199, 199, 199, 199, 199, 199, 201, 199, 199, 199, 199, 199, 202, 178, 178, + 178, 178, 178, 178, 178, 178, 203, 26, 204, 204, 204, 205, 204, 206, 204, 206, + 207, 204, 208, 208, 208, 209, 210, 26, 211, 211, 211, 211, 211, 212, 211, 211, + 211, 213, 211, 214, 194, 194, 194, 194, 215, 215, 215, 216, 217, 217, 217, 217, + 217, 217, 217, 218, 217, 217, 217, 219, 217, 220, 217, 220, 217, 221, 9, 9, + 222, 26, 26, 26, 26, 26, 26, 26, 223, 223, 223, 223, 223, 223, 223, 223, + 223, 224, 223, 223, 223, 223, 223, 225, 226, 226, 226, 226, 226, 226, 226, 226, + 227, 227, 227, 227, 227, 227, 228, 229, 230, 230, 230, 230, 230, 230, 230, 231, + 230, 232, 233, 233, 233, 233, 233, 233, 18, 234, 165, 165, 165, 165, 165, 235, + 226, 26, 236, 9, 237, 238, 239, 240, 2, 2, 2, 2, 241, 242, 2, 2, + 2, 2, 2, 243, 244, 245, 2, 246, 2, 2, 2, 2, 2, 2, 2, 247, + 9, 9, 9, 9, 9, 9, 9, 248, 14, 14, 249, 249, 14, 14, 14, 14, + 249, 249, 14, 250, 14, 14, 14, 249, 14, 14, 14, 14, 14, 14, 251, 14, + 251, 14, 252, 253, 14, 14, 254, 255, 0, 256, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 257, 0, 258, 259, 0, 260, 2, 261, 0, 0, 0, 0, + 26, 26, 9, 9, 9, 9, 222, 26, 0, 0, 0, 0, 262, 263, 4, 0, + 0, 264, 0, 0, 2, 2, 2, 2, 2, 265, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 260, 26, 26, 26, + 0, 266, 26, 26, 0, 0, 0, 0, 267, 267, 267, 267, 267, 267, 267, 267, + 267, 267, 267, 267, 267, 267, 267, 267, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 268, 0, 0, 0, 269, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 270, 270, 270, 270, 270, 271, 270, 270, + 270, 270, 270, 271, 2, 2, 2, 2, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 272, 273, 165, 165, 165, 165, 166, 167, 274, 274, + 274, 274, 274, 274, 274, 275, 276, 275, 170, 170, 172, 26, 172, 172, 172, 172, + 172, 172, 172, 172, 18, 18, 18, 18, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 266, 26, 26, 26, 26, 26, 277, 277, 277, 278, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 279, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 280, 26, 26, 26, 0, 281, 282, 0, 0, 0, 283, 284, 0, 285, + 286, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 289, 290, 291, 291, 291, + 291, 291, 291, 291, 291, 291, 291, 292, 293, 294, 294, 294, 294, 294, 295, 169, + 169, 169, 169, 169, 169, 169, 169, 169, 169, 296, 0, 0, 294, 294, 294, 294, + 0, 0, 0, 0, 281, 26, 291, 291, 169, 169, 169, 296, 0, 0, 0, 0, + 0, 0, 0, 0, 169, 169, 169, 297, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 291, 291, 291, 291, 291, 298, 291, 291, 291, 291, 291, 291, 291, 291, + 291, 291, 291, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277, + 0, 0, 0, 0, 0, 0, 0, 0, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 299, 300, 300, 300, 300, 300, 300, 300, 300, + 300, 300, 300, 300, 300, 300, 300, 300, 300, 301, 300, 300, 300, 300, 300, 300, + 302, 26, 303, 303, 303, 303, 303, 303, 304, 304, 304, 304, 304, 304, 304, 304, + 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 304, 305, 26, 26, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 306, 306, 306, 306, + 306, 306, 306, 306, 306, 306, 306, 26, 0, 0, 0, 0, 307, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 308, 2, 2, 2, 2, 2, 2, + 309, 310, 26, 26, 26, 26, 311, 2, 312, 312, 312, 312, 312, 313, 0, 314, + 315, 315, 315, 315, 315, 315, 315, 26, 316, 316, 316, 316, 316, 316, 316, 316, + 317, 318, 316, 319, 53, 53, 53, 53, 320, 320, 320, 320, 320, 321, 322, 322, + 322, 322, 323, 324, 169, 169, 169, 325, 326, 326, 326, 326, 326, 326, 326, 326, + 326, 327, 326, 328, 164, 164, 164, 329, 330, 330, 330, 330, 330, 330, 331, 26, + 330, 332, 330, 333, 164, 164, 164, 164, 334, 334, 334, 334, 334, 334, 334, 334, + 335, 26, 26, 336, 337, 337, 338, 26, 339, 339, 339, 26, 172, 172, 2, 2, + 2, 2, 2, 340, 341, 342, 176, 176, 176, 176, 176, 176, 176, 176, 176, 176, + 337, 337, 337, 337, 337, 343, 337, 344, 169, 169, 169, 169, 345, 26, 169, 169, + 296, 346, 169, 169, 169, 169, 169, 345, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 347, 26, 26, 26, 26, 348, 26, 349, 350, 25, 25, 351, 352, + 353, 25, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 354, 26, 51, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 355, + 26, 26, 31, 31, 31, 31, 31, 31, 31, 31, 356, 31, 31, 31, 31, 31, + 31, 26, 26, 26, 26, 26, 31, 357, 9, 9, 0, 314, 9, 358, 0, 0, + 0, 0, 359, 0, 260, 281, 50, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 360, 361, 0, 0, 0, 1, 2, 2, 3, + 1, 2, 2, 3, 362, 291, 290, 291, 291, 291, 291, 363, 169, 169, 169, 296, + 364, 364, 364, 365, 260, 260, 26, 366, 367, 368, 367, 367, 369, 367, 367, 370, + 367, 371, 367, 371, 26, 26, 26, 26, 367, 367, 367, 367, 367, 367, 367, 367, + 367, 367, 367, 367, 367, 367, 367, 372, 373, 0, 0, 0, 0, 0, 374, 0, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 255, 0, 375, 376, 26, 26, 26, + 26, 26, 0, 0, 0, 0, 0, 377, 378, 378, 378, 379, 380, 380, 380, 380, + 380, 380, 381, 26, 382, 0, 0, 281, 383, 383, 383, 383, 384, 385, 386, 386, + 386, 387, 388, 388, 388, 388, 388, 389, 390, 390, 390, 391, 392, 392, 392, 392, + 393, 392, 394, 26, 26, 26, 26, 26, 395, 395, 395, 395, 395, 395, 395, 395, + 395, 395, 396, 396, 396, 396, 396, 396, 397, 397, 397, 398, 397, 399, 400, 400, + 400, 400, 401, 400, 400, 400, 400, 401, 402, 402, 402, 402, 402, 26, 403, 403, + 403, 403, 403, 403, 404, 405, 26, 26, 406, 406, 406, 406, 406, 406, 406, 406, + 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 406, 407, 26, + 406, 406, 408, 26, 406, 26, 26, 26, 409, 410, 411, 411, 411, 411, 412, 413, + 414, 414, 415, 414, 416, 416, 416, 416, 417, 417, 417, 418, 419, 417, 26, 26, + 26, 26, 26, 26, 420, 420, 421, 422, 423, 423, 423, 424, 425, 425, 425, 426, + 26, 26, 26, 26, 26, 26, 26, 26, 427, 427, 427, 427, 428, 428, 428, 429, + 428, 428, 430, 428, 428, 428, 428, 428, 431, 432, 433, 434, 435, 435, 436, 437, + 435, 438, 435, 438, 439, 439, 439, 439, 440, 440, 440, 440, 26, 26, 26, 26, + 441, 441, 441, 441, 442, 443, 442, 26, 444, 444, 444, 444, 444, 444, 445, 446, + 447, 447, 448, 447, 449, 449, 450, 449, 451, 451, 452, 453, 26, 454, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 455, 455, 455, 455, 455, 455, 455, 455, + 455, 456, 26, 26, 26, 26, 26, 26, 457, 457, 457, 457, 457, 457, 458, 26, + 457, 457, 457, 457, 457, 457, 458, 459, 460, 460, 460, 460, 460, 26, 460, 461, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 31, 31, 31, 462, 463, 463, 463, 463, 463, 464, 465, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 466, 466, 466, 466, 466, 26, 467, 467, + 467, 467, 467, 468, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 469, 469, + 469, 470, 26, 26, 471, 471, 472, 26, 473, 473, 473, 473, 473, 473, 473, 473, + 473, 474, 475, 473, 473, 473, 26, 476, 477, 477, 477, 477, 477, 477, 477, 477, + 478, 479, 480, 480, 480, 481, 480, 482, 483, 483, 483, 483, 483, 483, 484, 483, + 483, 26, 485, 485, 485, 485, 486, 26, 487, 487, 487, 487, 487, 487, 487, 487, + 487, 487, 487, 487, 488, 138, 489, 26, 490, 490, 491, 490, 490, 490, 490, 492, + 26, 26, 26, 26, 26, 26, 26, 26, 493, 494, 495, 496, 495, 497, 498, 498, + 498, 498, 498, 498, 498, 499, 498, 500, 501, 502, 503, 504, 504, 505, 506, 507, + 502, 508, 509, 510, 511, 512, 512, 26, 513, 513, 513, 513, 513, 513, 513, 513, + 513, 513, 513, 514, 515, 26, 26, 26, 516, 516, 516, 516, 516, 516, 516, 516, + 516, 26, 516, 517, 26, 26, 26, 26, 518, 518, 518, 518, 518, 518, 519, 518, + 518, 518, 518, 519, 26, 26, 26, 26, 520, 520, 520, 520, 520, 520, 520, 520, + 521, 26, 520, 522, 199, 523, 26, 26, 524, 524, 524, 524, 524, 524, 524, 525, + 524, 526, 26, 26, 26, 26, 26, 26, 527, 527, 527, 528, 527, 529, 527, 527, + 26, 26, 26, 26, 26, 26, 26, 26, 530, 530, 530, 530, 530, 530, 530, 531, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 532, 532, 532, 532, + 532, 532, 532, 532, 532, 532, 533, 534, 535, 536, 537, 538, 538, 538, 539, 540, + 535, 26, 538, 541, 26, 26, 26, 26, 26, 26, 26, 26, 542, 543, 542, 542, + 542, 542, 542, 543, 544, 26, 26, 26, 545, 545, 545, 545, 545, 545, 545, 545, + 545, 26, 546, 546, 546, 546, 546, 546, 546, 546, 546, 546, 547, 26, 26, 26, + 548, 548, 548, 548, 548, 548, 548, 549, 550, 551, 550, 550, 550, 550, 552, 550, + 553, 26, 550, 550, 550, 554, 555, 555, 555, 555, 556, 555, 555, 557, 558, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 559, 560, 561, 561, 561, 561, 559, 562, + 561, 26, 561, 563, 564, 565, 566, 566, 566, 567, 568, 569, 566, 570, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 571, 571, 571, 572, 26, 26, 26, 26, 26, 26, 573, 26, + 108, 108, 108, 108, 108, 108, 574, 575, 576, 576, 576, 576, 576, 576, 576, 576, + 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, 577, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 576, 576, 576, 576, 576, 576, 576, 576, + 576, 576, 576, 576, 576, 578, 579, 26, 576, 576, 576, 576, 576, 576, 576, 576, + 580, 26, 26, 26, 26, 26, 26, 26, 581, 581, 581, 581, 581, 581, 581, 581, + 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 581, 582, 581, 583, + 26, 26, 26, 26, 26, 26, 26, 26, 584, 584, 584, 584, 584, 584, 584, 584, + 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, + 585, 26, 26, 26, 26, 26, 26, 26, 306, 306, 306, 306, 306, 306, 306, 306, + 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 306, 586, + 587, 587, 587, 588, 587, 589, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 590, 590, 590, 591, 591, 26, 592, 592, 592, 592, 592, 592, 592, 592, + 593, 26, 592, 594, 594, 592, 592, 595, 592, 592, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 597, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 598, 598, 598, 598, 598, 598, 598, 598, + 598, 599, 598, 598, 598, 598, 598, 598, 598, 600, 598, 598, 26, 26, 26, 26, + 26, 26, 26, 26, 601, 26, 347, 26, 602, 602, 602, 602, 602, 602, 602, 602, + 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, 602, + 602, 602, 602, 602, 602, 602, 602, 26, 603, 603, 603, 603, 603, 603, 603, 603, + 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, 603, + 603, 603, 604, 26, 26, 26, 26, 26, 602, 605, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 606, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, + 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 287, 288, 26, 26, 26, 26, + 26, 26, 607, 26, 608, 26, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, + 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, 609, + 609, 609, 609, 609, 609, 609, 609, 610, 611, 611, 611, 611, 611, 611, 611, 611, + 611, 611, 611, 611, 611, 612, 611, 613, 611, 614, 611, 615, 281, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 616, 26, 0, 0, 0, 0, 260, 361, 0, 0, + 0, 0, 0, 0, 617, 618, 0, 619, 620, 621, 0, 0, 0, 622, 0, 0, + 0, 0, 0, 0, 0, 623, 26, 26, 14, 14, 14, 14, 14, 14, 14, 14, + 249, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 260, 26, 0, 0, 0, 623, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 257, 0, 0, 0, 0, 0, 0, 0, 0, 257, 624, 625, 0, 626, + 627, 0, 0, 0, 0, 0, 0, 0, 269, 628, 257, 257, 0, 0, 0, 629, + 630, 631, 632, 0, 0, 0, 0, 0, 0, 0, 0, 0, 616, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 268, 0, 0, 0, 0, 0, 0, 633, 633, 633, 633, 633, 633, 633, 633, + 633, 633, 633, 633, 633, 633, 633, 633, 633, 634, 26, 635, 636, 633, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 271, 270, 270, 637, 638, 639, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 640, 640, 640, 640, 640, 641, 640, 642, + 640, 643, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 644, 644, 644, 644, 644, 644, 644, 645, 646, 646, 646, 646, 646, 646, 646, 646, + 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, 646, + 647, 646, 648, 26, 26, 26, 26, 26, 649, 649, 649, 649, 649, 649, 649, 649, + 649, 650, 649, 651, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 361, 0, 0, 0, 0, 0, 0, 0, 375, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 361, 0, 0, 0, 0, 0, 0, 616, + 26, 26, 26, 26, 26, 26, 26, 26, 652, 31, 31, 31, 653, 654, 655, 656, + 657, 658, 653, 659, 653, 655, 655, 660, 31, 661, 31, 662, 663, 661, 31, 662, + 26, 26, 26, 26, 26, 26, 354, 26, 0, 0, 0, 0, 0, 281, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 281, 26, 0, 260, 361, 0, + 361, 0, 361, 0, 0, 0, 616, 26, 0, 0, 0, 0, 0, 616, 26, 26, + 26, 26, 26, 26, 664, 0, 0, 0, 665, 26, 0, 0, 0, 0, 0, 281, + 0, 623, 314, 26, 616, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 0, 375, 0, 375, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 281, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 623, 0, 281, 26, 26, 0, 281, 0, 0, 0, 0, 0, 0, + 0, 26, 0, 314, 0, 0, 0, 0, 0, 26, 0, 0, 0, 616, 314, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 632, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 281, 26, 0, 616, 375, 266, 260, 26, 0, 0, 0, 623, 260, 26, + 266, 26, 260, 26, 26, 26, 26, 26, 0, 0, 359, 0, 0, 0, 0, 0, + 0, 266, 26, 26, 26, 26, 0, 314, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 280, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 299, 26, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 280, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 347, 26, 277, 277, + 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 666, 26, 26, 26, 277, 277, 277, 280, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 667, 26, 26, 26, 26, 26, 26, 668, 26, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 939, 940, 941, 942, 946, 948, 0, 962, + 969, 970, 971, 976,1001,1002,1003,1008, 0,1033,1040,1041,1042,1043,1047, 0, + 0,1080,1081,1082,1086,1110, 0, 0,1124,1125,1126,1127,1131,1133, 0,1147, + 1154,1155,1156,1161,1187,1188,1189,1193, 0,1219,1226,1227,1228,1229,1233, 0, + 0,1267,1268,1269,1273,1298, 0,1303, 943,1128, 944,1129, 954,1139, 958,1143, + 959,1144, 960,1145, 961,1146, 964,1149, 0, 0, 973,1158, 974,1159, 975,1160, + 983,1168, 978,1163, 988,1173, 990,1175, 991,1176, 993,1178, 994,1179, 0, 0, + 1004,1190,1005,1191,1006,1192,1014,1199,1007, 0, 0, 0,1016,1201,1020,1206, + 0,1022,1208,1025,1211,1023,1209, 0, 0, 0, 0,1032,1218,1037,1223,1035, + 1221, 0, 0, 0,1044,1230,1045,1231,1049,1235, 0, 0,1058,1244,1064,1250, + 1060,1246,1066,1252,1067,1253,1072,1258,1069,1255,1077,1264,1074,1261, 0, 0, + 1083,1270,1084,1271,1085,1272,1088,1275,1089,1276,1096,1283,1103,1290,1111,1299, + 1115,1118,1307,1120,1309,1121,1310, 0,1053,1239, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0,1093,1280, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 949,1134,1010,1195,1050,1236,1090,1277,1341,1368,1340, + 1367,1342,1369,1339,1366, 0,1320,1347,1418,1419,1323,1350, 0, 0, 992,1177, + 1018,1204,1055,1241,1416,1417,1415,1424,1202, 0, 0, 0, 987,1172, 0, 0, + 1031,1217,1321,1348,1322,1349,1338,1365, 950,1135, 951,1136, 979,1164, 980,1165, + 1011,1196,1012,1197,1051,1237,1052,1238,1061,1247,1062,1248,1091,1278,1092,1279, + 1071,1257,1076,1263, 0, 0, 997,1182, 0, 0, 0, 0, 0, 0, 945,1130, + 982,1167,1337,1364,1335,1362,1046,1232,1422,1423,1113,1301, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 8, 9, 0, 10,1425, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,1314,1427, 5, + 1434,1438,1443, 0,1450, 0,1455,1461,1514, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1446,1458,1468,1476,1480,1486,1517, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1489,1503,1494,1500,1508, 0, 0, 0, 0,1520,1521, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1526,1528, 0,1525, 0, 0, 0,1522, + 0, 0, 0, 0,1536,1532,1539, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1556, 0, 0, 0, 0, 0, 0,1548,1550, 0,1547, 0, 0, 0,1567, + 0, 0, 0, 0,1558,1554,1561, 0, 0, 0, 0, 0, 0, 0,1568,1569, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1529,1551, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1523,1545,1524,1546, 0, 0,1527,1549, + 0, 0,1570,1571,1530,1552,1531,1553, 0, 0,1533,1555,1535,1557,1537,1559, + 0, 0,1572,1573,1544,1566,1538,1560,1540,1562,1541,1563,1542,1564, 0, 0, + 1543,1565, 0, 0, 0, 0, 0, 0, 0, 0,1606,1607,1609,1608,1610, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1613, 0,1611, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1612, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1620, 0, 0, 0, 0, 0, 0, 0,1623, 0, 0,1624, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1614,1615,1616,1617,1618,1619,1621,1622, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1628,1629, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1625,1626, 0,1627, 0, 0, 0,1634, 0, 0,1635, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1630,1631,1632, 0, 0,1633, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1639, 0, 0,1638,1640, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1636,1637, 0, 0, 0, 0, 0, 0,1641, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1642,1644,1643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1645, 0, 0, 0, 0, 0, 0, 0,1646, 0, 0, 0, 0, 0, 0,1648, + 1649, 0,1647,1650, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1651,1653,1652, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1654, 0,1655,1657,1656, 0, 0, 0, 0,1659, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1660, 0, 0, 0, 0,1661, 0, 0, 0, 0,1662, + 0, 0, 0, 0,1663, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1658, 0, 0, 0, 0, 0, 0, 0, 0, 0,1664, 0,1665,1673, 0, + 1674, 0, 0, 0, 0, 0, 0, 0, 0,1666, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1668, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1669, 0, 0, 0, 0,1670, 0, 0, 0, 0,1671, + 0, 0, 0, 0,1672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1667, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1675, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1676, 0, + 1677, 0,1678, 0,1679, 0,1680, 0, 0, 0,1681, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1682, 0,1683, 0, 0,1684,1685, 0,1686, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 953,1138, 955,1140, 956,1141, 957,1142, + 1324,1351, 963,1148, 965,1150, 968,1153, 966,1151, 967,1152,1378,1380,1379,1381, + 984,1169, 985,1170,1420,1421, 986,1171, 989,1174, 995,1180, 998,1183, 996,1181, + 999,1184,1000,1185,1015,1200,1329,1356,1017,1203,1019,1205,1021,1207,1024,1210, + 1687,1688,1027,1213,1026,1212,1028,1214,1029,1215,1030,1216,1034,1220,1036,1222, + 1039,1225,1038,1224,1334,1361,1336,1363,1382,1384,1383,1385,1056,1242,1057,1243, + 1059,1245,1063,1249,1689,1690,1065,1251,1068,1254,1070,1256,1386,1387,1388,1389, + 1691,1692,1073,1259,1075,1262,1079,1266,1078,1265,1095,1282,1098,1285,1097,1284, + 1390,1391,1392,1393,1099,1286,1100,1287,1101,1288,1102,1289,1105,1292,1104,1291, + 1106,1294,1107,1295,1108,1296,1114,1302,1119,1308,1122,1311,1123,1312,1186,1260, + 1293,1305, 0,1394, 0, 0, 0, 0, 952,1137, 947,1132,1317,1344,1316,1343, + 1319,1346,1318,1345,1693,1695,1371,1375,1370,1374,1373,1377,1372,1376,1694,1696, + 981,1166, 977,1162, 972,1157,1326,1353,1325,1352,1328,1355,1327,1354,1697,1698, + 1009,1194,1013,1198,1054,1240,1048,1234,1331,1358,1330,1357,1333,1360,1332,1359, + 1699,1700,1396,1401,1395,1400,1398,1403,1397,1402,1399,1404,1094,1281,1087,1274, + 1406,1411,1405,1410,1408,1413,1407,1412,1409,1414,1109,1297,1117,1306,1116,1304, + 1112,1300, 0, 0, 0, 0, 0, 0,1471,1472,1701,1705,1702,1706,1703,1707, + 1430,1431,1715,1719,1716,1720,1717,1721,1477,1478,1729,1731,1730,1732, 0, 0, + 1435,1436,1733,1735,1734,1736, 0, 0,1481,1482,1737,1741,1738,1742,1739,1743, + 1439,1440,1751,1755,1752,1756,1753,1757,1490,1491,1765,1768,1766,1769,1767,1770, + 1447,1448,1771,1774,1772,1775,1773,1776,1495,1496,1777,1779,1778,1780, 0, 0, + 1451,1452,1781,1783,1782,1784, 0, 0,1504,1505,1785,1788,1786,1789,1787,1790, + 0,1459, 0,1791, 0,1792, 0,1793,1509,1510,1794,1798,1795,1799,1796,1800, + 1462,1463,1808,1812,1809,1813,1810,1814,1467, 21,1475, 22,1479, 23,1485, 24, + 1493, 27,1499, 28,1507, 29, 0, 0,1704,1708,1709,1710,1711,1712,1713,1714, + 1718,1722,1723,1724,1725,1726,1727,1728,1740,1744,1745,1746,1747,1748,1749,1750, + 1754,1758,1759,1760,1761,1762,1763,1764,1797,1801,1802,1803,1804,1805,1806,1807, + 1811,1815,1816,1817,1818,1819,1820,1821,1470,1469,1822,1474,1465, 0,1473,1825, + 1429,1428,1426, 12,1432, 0, 26, 0, 0,1315,1823,1484,1466, 0,1483,1829, + 1433, 13,1437, 14,1441,1826,1827,1828,1488,1487,1513, 19, 0, 0,1492,1515, + 1445,1444,1442, 15, 0,1831,1832,1833,1502,1501,1516, 25,1497,1498,1506,1518, + 1457,1456,1454, 17,1453,1313, 11, 3, 0, 0,1824,1512,1519, 0,1511,1830, + 1449, 16,1460, 18,1464, 4, 0, 0, 30, 31, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, + 0, 0, 2, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1834,1835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1836, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1837,1839,1838, 0, 0, 0, 0,1840, 0, 0, 0, + 0,1841, 0, 0,1842, 0, 0, 0, 0, 0, 0, 0,1843, 0,1844, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1845, 0, 0,1846, 0, 0,1847, + 0,1848, 0, 0, 0, 0, 0, 0, 937, 0,1850, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1849, 936, 938,1851,1852, 0, 0,1853,1854, 0, 0, + 1855,1856, 0, 0, 0, 0, 0, 0,1857,1858, 0, 0,1861,1862, 0, 0, + 1863,1864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1867,1868,1869,1870,1859,1860,1865,1866, 0, 0, 0, 0, + 0, 0,1871,1872,1873,1874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1875, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1877, 0,1878, 0,1879, 0,1880, 0,1881, 0,1882, 0, + 1883, 0,1884, 0,1885, 0,1886, 0,1887, 0,1888, 0, 0,1889, 0,1890, + 0,1891, 0, 0, 0, 0, 0, 0,1892,1893, 0,1894,1895, 0,1896,1897, + 0,1898,1899, 0,1900,1901, 0, 0, 0, 0, 0, 0,1876, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1902, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,1904, 0,1905, 0,1906, 0,1907, 0,1908, 0,1909, 0, + 1910, 0,1911, 0,1912, 0,1913, 0,1914, 0,1915, 0, 0,1916, 0,1917, + 0,1918, 0, 0, 0, 0, 0, 0,1919,1920, 0,1921,1922, 0,1923,1924, + 0,1925,1926, 0,1927,1928, 0, 0, 0, 0, 0, 0,1903, 0, 0,1929, + 1930,1931,1932, 0, 0, 0,1933, 0, 710, 385, 724, 715, 455, 103, 186, 825, + 825, 242, 751, 205, 241, 336, 524, 601, 663, 676, 688, 738, 411, 434, 474, 500, + 649, 746, 799, 108, 180, 416, 482, 662, 810, 275, 462, 658, 692, 344, 618, 679, + 293, 388, 440, 492, 740, 116, 146, 168, 368, 414, 481, 527, 606, 660, 665, 722, + 781, 803, 809, 538, 553, 588, 642, 758, 811, 701, 233, 299, 573, 612, 487, 540, + 714, 779, 232, 267, 412, 445, 457, 585, 594, 766, 167, 613, 149, 148, 560, 589, + 648, 768, 708, 345, 411, 704, 105, 259, 313, 496, 518, 174, 542, 120, 307, 101, + 430, 372, 584, 183, 228, 529, 650, 697, 424, 732, 428, 349, 632, 355, 517, 110, + 135, 147, 403, 580, 624, 700, 750, 170, 193, 245, 297, 374, 463, 543, 763, 801, + 812, 815, 162, 384, 420, 730, 287, 330, 337, 366, 459, 476, 509, 558, 591, 610, + 726, 652, 734, 759, 154, 163, 198, 473, 683, 697, 292, 311, 353, 423, 572, 494, + 113, 217, 259, 280, 314, 499, 506, 603, 608, 752, 778, 782, 788, 117, 557, 748, + 774, 320, 109, 126, 260, 265, 373, 411, 479, 523, 655, 737, 823, 380, 765, 161, + 395, 398, 438, 451, 502, 516, 537, 583, 791, 136, 340, 769, 122, 273, 446, 727, + 305, 322, 400, 496, 771, 155, 190, 269, 377, 391, 406, 432, 501, 519, 599, 684, + 687, 749, 776, 175, 452, 191, 480, 510, 659, 772, 805, 813, 397, 444, 619, 566, + 568, 575, 491, 471, 707, 111, 636, 156, 153, 288, 346, 578, 256, 435, 383, 729, + 680, 767, 694, 295, 128, 210, 0, 0, 227, 0, 379, 0, 0, 150, 493, 525, + 544, 551, 552, 556, 783, 576, 604, 0, 661, 0, 703, 0, 0, 735, 743, 0, + 0, 0, 793, 794, 795, 808, 741, 773, 118, 127, 130, 166, 169, 177, 207, 213, + 215, 226, 229, 268, 270, 317, 327, 329, 335, 369, 375, 381, 404, 441, 448, 458, + 477, 484, 503, 539, 545, 547, 546, 548, 549, 550, 554, 555, 561, 564, 569, 591, + 593, 595, 598, 607, 620, 625, 625, 651, 690, 695, 705, 706, 716, 717, 733, 735, + 777, 786, 790, 315, 869, 623, 0, 0, 102, 145, 134, 115, 129, 138, 165, 171, + 207, 202, 206, 212, 227, 231, 240, 243, 250, 254, 294, 296, 303, 308, 319, 325, + 321, 329, 326, 335, 341, 357, 360, 362, 370, 379, 388, 389, 393, 421, 424, 438, + 456, 454, 458, 465, 477, 535, 485, 490, 493, 507, 512, 514, 521, 522, 525, 526, + 528, 533, 532, 541, 565, 569, 574, 586, 591, 597, 607, 637, 647, 674, 691, 693, + 695, 698, 703, 699, 705, 704, 702, 706, 709, 717, 728, 736, 747, 754, 770, 777, + 783, 784, 786, 787, 790, 802, 825, 848, 847, 857, 55, 65, 66, 883, 892, 916, + 822, 824, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,1586, 0,1605, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1602,1603,1934,1935,1574,1575,1576,1577,1579,1580,1581,1583,1584, 0, + 1585,1587,1588,1589,1591, 0,1592, 0,1593,1594, 0,1595,1596, 0,1598,1599, + 1600,1601,1604,1582,1578,1590,1597, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1936, 0,1937, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1938, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1939,1940, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1941,1942, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1944,1943, 0,1945, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,1946,1947, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1949,1950,1951,1952,1953,1954,1955, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1956,1957,1958,1960,1959,1961, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 106, 104, 107, 826, 114, 118, 119, 121, + 123, 124, 127, 125, 34, 830, 130, 131, 132, 137, 827, 35, 133, 139, 829, 142, + 143, 112, 144, 145, 924, 151, 152, 37, 157, 158, 159, 160, 38, 165, 166, 169, + 171, 172, 173, 174, 176, 177, 178, 179, 181, 182, 182, 182, 833, 468, 184, 185, + 834, 187, 188, 189, 196, 192, 194, 195, 197, 199, 200, 201, 203, 204, 204, 206, + 208, 209, 211, 218, 213, 219, 214, 216, 153, 234, 221, 222, 223, 220, 225, 224, + 230, 835, 235, 236, 237, 238, 239, 244, 836, 837, 247, 248, 249, 246, 251, 39, + 40, 253, 255, 255, 838, 257, 258, 259, 261, 839, 262, 263, 301, 264, 41, 266, + 270, 272, 271, 841, 274, 842, 277, 276, 278, 281, 282, 42, 283, 284, 285, 286, + 43, 843, 44, 289, 290, 291, 293, 934, 298, 845, 845, 621, 300, 300, 45, 852, + 894, 302, 304, 46, 306, 309, 310, 312, 316, 48, 47, 317, 846, 318, 323, 324, + 325, 324, 328, 329, 333, 331, 332, 334, 335, 336, 338, 339, 342, 343, 347, 351, + 849, 350, 348, 352, 354, 359, 850, 361, 358, 356, 49, 363, 365, 367, 364, 50, + 369, 371, 851, 376, 386, 378, 53, 381, 52, 51, 140, 141, 387, 382, 614, 78, + 388, 389, 390, 394, 392, 856, 54, 399, 396, 402, 404, 858, 405, 401, 407, 55, + 408, 409, 410, 413, 859, 415, 56, 417, 860, 418, 57, 419, 422, 424, 425, 861, + 840, 862, 426, 863, 429, 431, 427, 433, 437, 441, 438, 439, 442, 443, 864, 436, + 449, 450, 58, 454, 453, 865, 447, 460, 866, 867, 461, 466, 465, 464, 59, 467, + 470, 469, 472, 828, 475, 868, 478, 870, 483, 485, 486, 871, 488, 489, 872, 873, + 495, 497, 60, 498, 61, 61, 504, 505, 507, 508, 511, 62, 513, 874, 515, 875, + 518, 844, 520, 876, 877, 878, 63, 64, 528, 880, 879, 881, 882, 530, 531, 531, + 533, 66, 534, 67, 68, 884, 536, 538, 541, 69, 885, 549, 886, 887, 556, 559, + 70, 561, 562, 563, 888, 889, 889, 567, 71, 890, 570, 571, 72, 891, 577, 73, + 581, 579, 582, 893, 587, 74, 590, 592, 596, 75, 895, 896, 76, 897, 600, 898, + 602, 605, 607, 899, 900, 609, 901, 611, 853, 77, 615, 616, 79, 617, 252, 902, + 903, 854, 855, 621, 622, 731, 80, 627, 626, 628, 164, 629, 630, 631, 633, 904, + 632, 634, 639, 640, 635, 641, 646, 651, 638, 643, 644, 645, 905, 907, 906, 81, + 653, 654, 656, 911, 657, 908, 82, 83, 909, 910, 84, 664, 665, 666, 667, 669, + 668, 671, 670, 674, 672, 673, 675, 85, 677, 678, 86, 681, 682, 912, 685, 686, + 87, 689, 36, 913, 914, 88, 89, 696, 702, 709, 711, 915, 712, 713, 718, 719, + 917, 831, 721, 720, 723, 832, 725, 728, 918, 919, 739, 742, 744, 920, 745, 753, + 756, 757, 755, 760, 761, 921, 762, 90, 764, 922, 91, 775, 279, 780, 923, 925, + 92, 93, 785, 926, 94, 927, 787, 787, 789, 928, 792, 95, 796, 797, 798, 800, + 96, 929, 802, 804, 806, 97, 98, 807, 930, 99, 931, 932, 933, 814, 100, 816, + 817, 818, 819, 820, 821, 935, 0, 0, +}; +static const int16_t +_hb_ucd_i16[196] = +{ + 0, 0, 0, 0, 1, -1, 0, 0, 2, 0, -2, 0, 0, 0, 0, 2, + 0, -2, 0, 0, 0, 0, 0, 16, 0, 0, 0, -16, 0, 0, 1, -1, + 0, 0, 0, 1, -1, 0, 0, 0, 0, 1, -1, 0, 3, 3, 3, -3, + -3, -3, 0, 0, 0, 2016, 0, 0, 0, 0, 0, 2527, 1923, 1914, 1918, 0, + 2250, 0, 0, 0, 0, 0, 0, 138, 0, 7, 0, 0, -7, 0, 0, 0, + 1, -1, 1, -1, -1, 1, -1, 0, 1824, 0, 0, 0, 0, 0, 2104, 0, + 2108, 2106, 0, 2106, 1316, 0, 0, 0, 0, 1, -1, 1, -1, -138, 0, 0, + 1, -1, 8, 8, 8, 0, 7, 7, 0, 0, -8, -8, -8, -7, -7, 0, + 1, -1, 0, 2,-1316, 1, -1, 0, -1, 1, -1, 1, -1, 3, 1, -1, + -3, 1, -1, 1, -1, 0, 0,-1914,-1918, 0, 0,-1923,-1824, 0, 0, 0, + 0,-2016, 0, 0, 1, -1, 0, 1, 0, 0,-2104, 0, 0, 0, 0,-2106, + -2108,-2106, 0, 0, 1, -1,-2250, 0, 0, 0,-2527, 0, 0, -2, 0, 1, + -1, 0, 1, -1, +}; + +static inline uint_fast8_t +_hb_ucd_gc (unsigned u) +{ + return u<1114110u?_hb_ucd_u8[6504+(((_hb_ucd_u8[1264+(((_hb_ucd_u16[((_hb_ucd_u8[544+(((_hb_ucd_u8[u>>1>>3>>3>>4])<<4)+((u>>1>>3>>3)&15u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; +} +static inline uint_fast8_t +_hb_ucd_ccc (unsigned u) +{ + return u<125259u?_hb_ucd_u8[8768+(((_hb_ucd_u8[7792+(((_hb_ucd_u8[7120+(((_hb_ucd_u8[6874+(u>>2>>3>>4)])<<4)+((u>>2>>3)&15u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u))]:0; +} +static inline unsigned +_hb_ucd_b4 (const uint8_t* a, unsigned i) +{ + return (a[i>>1]>>((i&1u)<<2))&15u; +} +static inline int_fast16_t +_hb_ucd_bmg (unsigned u) +{ + return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[9508+(((_hb_ucd_u8[9388+(((_hb_ucd_b4(9260+_hb_ucd_u8,u>>2>>3>>3))<<3)+((u>>2>>3)&7u))])<<3)+((u>>2)&7u))])<<2)+((u)&3u)]:0; +} +static inline uint_fast8_t +_hb_ucd_sc (unsigned u) +{ + return u<918000u?_hb_ucd_u8[10974+(((_hb_ucd_u16[1960+(((_hb_ucd_u8[10286+(((_hb_ucd_u8[9836+(u>>3>>4>>4)])<<4)+((u>>3>>4)&15u))])<<4)+((u>>3)&15u))])<<3)+((u)&7u))]:2; +} +static inline uint_fast16_t +_hb_ucd_dm (unsigned u) +{ + return u<195102u?_hb_ucd_u16[5768+(((_hb_ucd_u8[16708+(((_hb_ucd_u8[16326+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; +} + + +#else + +static const uint8_t +_hb_ucd_u8[13344] = +{ + 0, 1, 2, 3, 4, 5, 5, 5, 5, 5, 6, 5, 5, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 5, 17, 15, 15, 18, 15, 19, 20, 21, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 22, 23, + 5, 24, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 25, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 34, 34, 34, 35, 36, 37, 34, 34, 34, 38, 39, 40, 41, + 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 67, 68, 69, 67, 70, 71, + 67, 67, 62, 72, 62, 62, 73, 67, 74, 75, 76, 77, 78, 67, 67, 67, + 79, 80, 34, 81, 82, 83, 67, 67, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 84, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 85, 34, 34, 34, 34, 34, 34, 34, 34, 86, 34, 34, 87, 88, 89, 90, + 91, 92, 93, 94, 95, 96, 97, 98, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100, + 100,100, 34, 34, 34, 34,101,102, 34, 34,103,104,105,106,107,108, + 34, 34,109,110,111,112,113,114,115,116,117,111, 34, 34, 34,111, + 118,119,120,121,122,123,124,125, 34,126,127,111,128,129,130,131, + 132,133,134,135,136,137,138,111,139,140,111,141,142,143,144,111, + 145,146,147,148,149,150,111,111,151,152,153,154,111,155,111,156, + 34, 34, 34, 34, 34, 34, 34, 34,157, 34, 34,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 34, 34, 34, 34, 34, 34, 34, 34,158,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111, 34, 34, 34, 34, 34,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 34, 34, 34, 34,159,160,161, 34,111,111,111,111,162,163,164,165, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111, + 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111, 34,166,111,111,111,111,111,111, + 67, 67,167,168,169,128, 65,111,170,171,172,173,174,175,176,177, + 67, 67, 67, 67,178,179,111,111,111,111,111,111,111,111,111,111, + 180,111,181,111,111,182,111,111,111,111,111,111,111,111,111,111, + 34,183,184,111,111,111,111,111,128,185,186,111, 34,187,111,111, + 67, 67,188, 67, 67,111, 67,189, 67, 67, 67, 67, 67, 67, 67, 67, + 67, 67, 67, 67, 67, 67, 67,190,111,111,111,111,111,111,111,111, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111,111,111, + 34, 34, 34, 34, 34, 34, 34,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 191,111,180,180,111,111,111,111,111,111,111,111,111,111,111,111, + 111,111,111,111,111,111,111,111,111,111,111,111,111,111,111,111, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 2, 4, 5, 6, 2, + 7, 7, 7, 7, 7, 2, 8, 9, 10, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 12, 13, 14, 15, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 17, 18, 19, 1, 20, 20, 21, 22, 23, 24, 25, + 26, 27, 15, 2, 28, 29, 27, 30, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 31, 11, 11, 11, 32, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 33, 16, 16, 16, 16, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 34, 34, 34, 34, 34, 34, 34, 34, 16, 32, 32, 32, + 32, 32, 32, 32, 11, 34, 34, 16, 34, 32, 32, 11, 34, 11, 16, 11, + 11, 34, 32, 11, 32, 16, 11, 34, 32, 32, 32, 11, 34, 16, 32, 11, + 34, 11, 34, 34, 32, 35, 32, 16, 36, 36, 37, 34, 38, 37, 34, 34, + 34, 34, 34, 34, 34, 34, 16, 32, 34, 38, 32, 11, 32, 32, 32, 32, + 32, 32, 16, 16, 16, 11, 34, 32, 34, 34, 11, 32, 32, 32, 32, 32, + 16, 16, 39, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 41, 41, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, + 40, 40, 42, 41, 41, 41, 42, 42, 41, 41, 41, 41, 41, 41, 41, 41, + 43, 43, 43, 43, 43, 43, 43, 43, 32, 32, 42, 32, 16, 44, 16, 10, + 41, 41, 41, 45, 11, 11, 11, 11, 34, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 16, 16, 16, 16, 34, + 16, 11, 32, 16, 32, 32, 32, 32, 16, 16, 32, 46, 34, 32, 34, 11, + 32, 47, 43, 43, 48, 32, 32, 32, 11, 34, 34, 34, 34, 34, 34, 16, + 11, 11, 11, 11, 49, 2, 2, 2, 16, 16, 16, 16, 50, 51, 52, 53, + 54, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 55, + 56, 57, 43, 56, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 58, 2, 2, 2, 2, 2, 2, 59, 59, 59, 8, 9, 60, 2, 61, + 43, 43, 43, 43, 43, 57, 59, 2, 62, 36, 36, 36, 36, 63, 43, 43, + 7, 7, 7, 7, 7, 2, 2, 36, 64, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 65, 43, 43, 43, 66, 47, 43, 43, 67, 68, 69, 43, 43, 36, + 7, 7, 7, 7, 7, 36, 70, 71, 2, 2, 2, 2, 2, 2, 2, 72, + 63, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 64, 36, + 36, 36, 36, 43, 43, 43, 43, 43, 7, 7, 7, 7, 7, 36, 36, 36, + 36, 36, 36, 36, 36, 63, 43, 43, 43, 43, 40, 21, 2, 40, 68, 20, + 36, 36, 36, 43, 43, 68, 43, 43, 43, 43, 68, 43, 68, 43, 43, 43, + 2, 2, 2, 2, 2, 2, 2, 2, 36, 36, 36, 36, 63, 43, 43, 2, + 36, 63, 43, 43, 43, 43, 43, 43, 43, 73, 43, 43, 43, 43, 43, 43, + 43, 74, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 74, 64, 75, + 76, 43, 43, 43, 74, 75, 76, 75, 63, 43, 43, 43, 36, 36, 36, 36, + 36, 43, 2, 7, 7, 7, 7, 7, 77, 36, 36, 36, 36, 36, 36, 36, + 63, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 75, + 76, 43, 43, 74, 75, 75, 76, 36, 36, 36, 36, 79, 75, 75, 36, 36, + 36, 43, 43, 7, 7, 7, 7, 7, 36, 20, 27, 27, 27, 53, 58, 43, + 43, 74, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 43, 75, + 76, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, 64, 36, 36, 36, + 36, 36, 36, 7, 7, 7, 7, 7, 43, 36, 63, 2, 2, 2, 2, 2, + 76, 43, 43, 43, 74, 75, 76, 43, 60, 20, 20, 20, 80, 43, 43, 43, + 43, 75, 78, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 64, 76, + 76, 43, 43, 74, 75, 75, 76, 43, 43, 43, 43, 74, 75, 75, 36, 36, + 71, 27, 27, 27, 27, 27, 27, 27, 43, 64, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 75, 74, 75, 75, 75, 75, 75, 76, 43, + 36, 36, 36, 79, 75, 75, 75, 75, 75, 75, 75, 7, 7, 7, 7, 7, + 27, 81, 61, 61, 53, 61, 61, 61, 74, 75, 64, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 43, 74, 75, 75, 43, 43, 43, 43, 43, + 43, 43, 43, 43, 36, 36, 36, 36, 7, 7, 7, 82, 27, 27, 27, 81, + 63, 75, 65, 36, 36, 36, 36, 36, 75, 75, 75, 74, 75, 75, 43, 43, + 43, 43, 74, 75, 75, 75, 75, 36, 83, 36, 36, 36, 36, 36, 36, 36, + 43, 75, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 64, 75, + 76, 43, 43, 75, 75, 75, 76, 70, 61, 61, 36, 79, 27, 27, 27, 84, + 27, 27, 27, 27, 81, 36, 36, 36, 36, 36, 36, 36, 36, 43, 43, 74, + 75, 43, 43, 43, 75, 75, 75, 75, 7, 75, 2, 2, 2, 2, 2, 2, + 63, 36, 43, 43, 43, 43, 43, 85, 36, 36, 36, 68, 43, 43, 43, 57, + 7, 7, 7, 7, 7, 2, 2, 2, 63, 36, 43, 43, 43, 43, 64, 36, + 36, 36, 36, 40, 43, 43, 43, 43, 7, 7, 7, 7, 7, 7, 36, 36, + 70, 61, 2, 2, 2, 2, 2, 2, 2, 86, 86, 61, 43, 61, 61, 61, + 7, 7, 7, 7, 7, 27, 27, 27, 27, 27, 47, 47, 47, 4, 4, 75, + 63, 43, 43, 43, 43, 43, 43, 74, 43, 43, 57, 43, 36, 36, 63, 43, + 43, 43, 43, 43, 43, 43, 43, 61, 61, 61, 61, 69, 61, 61, 61, 61, + 2, 2, 86, 61, 21, 2, 2, 2, 36, 36, 36, 36, 36, 79, 76, 43, + 74, 43, 43, 43, 76, 74, 76, 64, 36, 36, 36, 75, 43, 36, 36, 43, + 64, 75, 78, 79, 75, 75, 75, 36, 63, 43, 64, 36, 36, 36, 36, 36, + 36, 74, 76, 74, 75, 75, 76, 79, 7, 7, 7, 7, 7, 75, 76, 61, + 16, 16, 16, 16, 16, 50, 44, 16, 36, 36, 36, 36, 36, 36, 63, 43, + 2, 2, 2, 2, 87, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 61, 61, 61, 61, 61, 61, 61, 61, 11, 11, 11, 11, 16, 16, 16, 16, + 88, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 70, 65, + 89, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 90, 91, 91, + 36, 36, 36, 36, 36, 58, 2, 92, 93, 36, 36, 36, 36, 36, 36, 36, + 36, 43, 43, 43, 43, 43, 43, 43, 36, 43, 57, 2, 2, 2, 2, 2, + 36, 36, 43, 76, 43, 43, 43, 75, 75, 75, 75, 74, 76, 43, 43, 43, + 43, 43, 2, 77, 2, 60, 63, 43, 7, 7, 7, 7, 7, 7, 7, 7, + 2, 2, 2, 94, 2, 56, 43, 59, 36, 95, 36, 36, 36, 36, 36, 36, + 36, 36, 63, 64, 36, 36, 36, 36, 36, 36, 36, 36, 63, 36, 36, 36, + 43, 74, 75, 76, 74, 75, 75, 75, 75, 74, 75, 75, 76, 43, 43, 43, + 61, 61, 2, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 27, 27, 61, + 36, 36, 36, 63, 74, 76, 43, 2, 36, 36, 79, 74, 43, 43, 43, 43, + 74, 74, 76, 43, 43, 43, 74, 75, 75, 76, 43, 43, 43, 43, 43, 43, + 2, 2, 2, 77, 2, 2, 2, 2, 43, 43, 43, 43, 43, 43, 43, 96, + 43, 43, 78, 36, 36, 36, 36, 36, 36, 36, 74, 43, 43, 74, 74, 75, + 75, 74, 78, 36, 36, 36, 36, 36, 86, 61, 61, 61, 61, 47, 43, 43, + 43, 43, 61, 61, 61, 61, 61, 61, 43, 78, 36, 36, 36, 36, 36, 36, + 79, 43, 43, 75, 43, 76, 43, 36, 36, 36, 36, 74, 43, 75, 76, 76, + 43, 75, 75, 75, 75, 75, 2, 2, 36, 36, 75, 75, 75, 75, 43, 43, + 43, 43, 75, 43, 43, 57, 2, 2, 7, 7, 7, 7, 7, 7, 83, 36, + 36, 36, 36, 36, 40, 40, 40, 2, 43, 57, 43, 43, 43, 43, 43, 43, + 74, 43, 43, 43, 64, 36, 63, 36, 36, 36, 64, 79, 43, 36, 36, 36, + 16, 16, 16, 16, 16, 16, 40, 40, 40, 40, 40, 40, 40, 44, 16, 16, + 16, 16, 16, 16, 44, 16, 16, 16, 16, 16, 16, 16, 16, 97, 40, 40, + 32, 32, 32, 16, 16, 16, 16, 32, 16, 16, 16, 16, 11, 11, 11, 11, + 16, 16, 16, 16, 34, 11, 11, 11, 16, 16, 16, 16, 98, 98, 98, 98, + 16, 16, 16, 16, 11, 11, 99,100, 41, 16, 16, 16, 11, 11, 99, 41, + 16, 16, 16, 16, 11, 11,101, 41,102,102,102,102,102,103, 59, 59, + 51, 51, 51, 2,104,105,104,105, 2, 2, 2, 2,106, 59, 59,107, + 2, 2, 2, 2,108,109, 2,110,111, 2,112,113, 2, 2, 2, 2, + 2, 9,111, 2, 2, 2, 2,114, 59, 59, 59, 59, 59, 59, 59, 59, + 115, 40, 27, 27, 27, 8,112,116, 27, 27, 27, 27, 27, 8,112, 91, + 20, 20, 20, 20, 20, 20, 20, 20, 43, 43, 43, 43, 43, 43,117, 48, + 96, 48, 96, 43, 43, 43, 43, 43, 61,118, 61,119, 61, 34, 11, 16, + 11, 32,119, 61, 46, 11, 11, 61, 61, 61,118,118,118, 11, 11,120, + 11, 11, 35, 36, 39, 61, 16, 11, 8, 8, 46, 16, 16, 26, 61,121, + 92, 92, 92, 92, 92, 92, 92, 92, 92,122,123, 92,124, 61, 61, 61, + 8, 8,125, 61, 61, 8, 61, 61,125, 26, 61,125, 61, 61, 61,125, + 61, 61, 61, 61, 61, 61, 61, 8, 61,125,125, 61, 61, 61, 61, 61, + 61, 61, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 61, 61, 61, 61, 4, 4, 61, 61, 8, 61, 61, 61,126,127, 61, 61, + 61, 61, 61, 61, 61, 61,125, 61, 61, 61, 61, 61, 61, 26, 8, 8, + 8, 8, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 8, 8, + 8, 61, 61, 61, 61, 61, 61, 61, 27, 27, 27, 27, 27, 27, 61, 61, + 61, 61, 61, 61, 61, 27, 27, 27, 61, 61, 61, 26, 61, 61, 61, 61, + 26, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 8, 8, 8, 8, + 61, 61, 61, 61, 61, 61, 61, 26, 61, 61, 61, 61, 4, 4, 4, 4, + 4, 4, 4, 27, 27, 27, 27, 27, 27, 27, 61, 61, 61, 61, 61, 61, + 8, 8,112,128, 8, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 4, + 8,112,129,129,129,129,129,129,129,129,129,129,128, 8, 8, 8, + 8, 8, 8, 8, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 4, 8, + 8, 8,125, 26, 8, 8,125, 61, 32, 11, 32, 34, 34, 34, 34, 11, + 32, 32, 34, 16, 16, 16, 40, 11, 32, 32,121, 61, 61,119, 34,130, + 43, 32, 16, 16, 50, 2, 87, 2, 36, 36, 36, 36, 36, 36, 36, 95, + 2, 2, 2, 2, 2, 2, 2, 56, 2,104,104, 2,108,109,104, 2, + 2, 2, 2, 6, 2, 94,104, 2,104, 4, 4, 4, 4, 2, 2, 77, + 2, 2, 2, 2, 2, 51, 2, 2, 94,131, 2, 2, 2, 2, 2, 2, + 61, 2, 2, 2, 2, 2, 2, 2, 1, 2,132,133, 4, 4, 4, 4, + 4, 61, 4, 4, 4, 4,134, 91,135, 92, 92, 92, 92, 43, 43, 75, + 136, 40, 40, 61, 92,137, 58, 61, 71, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 63,138,139, 62, 36, 36, 36, 36, 36, 58, 40, 62, + 61, 27, 27, 61, 61, 61, 61, 61, 27, 27, 27, 27, 27, 61, 61, 61, + 61, 61, 61, 61, 27, 27, 27, 27,140, 27, 27, 27, 27, 27, 27, 27, + 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,141, 2, + 32, 32, 32, 32, 32, 32, 32, 63, 48,142, 43, 43, 43, 43, 43, 77, + 32, 32, 32, 32, 32, 32, 40, 43, 36, 36, 36, 92, 92, 92, 92, 92, + 43, 2, 2, 2, 2, 2, 2, 2, 41, 41, 41,139, 40, 40, 40, 40, + 41, 32, 32, 32, 32, 32, 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, + 44, 16, 16, 16, 34, 34, 34, 32, 32, 32, 32, 32, 42,143, 34, 35, + 32, 32, 16, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 11, 11, 32, + 11, 11, 32, 32, 32, 32, 32, 32, 16, 32, 11, 11, 34, 16, 16, 16, + 16, 16, 34, 35, 40, 35, 36, 36, 36, 64, 36, 64, 36, 63, 36, 36, + 36, 79, 76, 74, 61, 61, 43, 43, 27, 27, 27, 61,144, 61, 61, 61, + 36, 36, 2, 2, 2, 2, 2, 2, 75, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 75, 75, 75, 75, 75, 75, 75, 75, 43, 43, 43, 43, 43, 2, + 43, 36, 36, 36, 2, 65, 65, 63, 36, 36, 36, 43, 43, 43, 43, 2, + 36, 36, 36, 63, 43, 43, 43, 43, 43, 75, 75, 75, 75, 75, 75,145, + 36, 63, 75, 43, 43, 75, 43, 75,145, 2, 2, 2, 2, 2, 2, 77, + 7, 7, 7, 7, 7, 7, 7, 2, 36, 36, 63, 62, 36, 36, 36, 36, + 36, 36, 36, 36, 63, 43, 43, 74, 76, 74, 76, 43, 43, 43, 43, 43, + 36, 63, 36, 36, 36, 36, 74, 75, 7, 7, 7, 7, 7, 7, 2, 2, + 62, 36, 36, 70, 61, 79, 74, 36, 64, 43, 64, 63, 64, 36, 36, 43, + 36, 36, 36, 36, 36, 36, 95, 2, 36, 36, 36, 36, 36, 79, 43, 75, + 2, 95,146, 43, 43, 43, 43, 43, 16, 16, 16, 16, 16,100, 40, 40, + 16, 16, 16, 16, 97, 41, 41, 41, 36, 79, 76, 75, 74,145, 76, 43, + 147,147,147,147,147,147,147,147,148,148,148,148,148,148,148,148, + 16, 16, 16, 16, 16, 16, 35, 64, 36, 36, 36, 36,149, 36, 36, 36, + 36, 41, 41, 41, 41, 41, 41, 41, 41,150, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36,129,151,151,151,151,151,151,151,151, + 36, 36, 36, 36, 36, 36,144, 61, 2, 2, 2,152,113, 2, 2, 2, + 6,153,154,129,129,129,129,129,129,129,113,152,113, 2,110,155, + 2, 2, 2, 2,134,129,129,113, 2,156, 8, 8, 60, 2, 2, 2, + 36, 36, 36, 36, 36, 36, 36,157, 2, 2, 3, 2, 4, 5, 6, 2, + 16, 16, 16, 16, 16, 17, 18,112,113, 4, 2, 36, 36, 36, 36, 36, + 62, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 40, + 20,158, 53, 20, 26, 8,125, 61, 61, 61, 61, 61,159, 59, 61, 61, + 2, 2, 2, 87, 27, 27, 27, 27, 27, 27, 27, 81, 61, 61, 61, 61, + 92, 92,124, 27, 81, 61, 61, 61, 61, 61, 61, 61, 61, 27, 61, 61, + 61, 61, 61, 61, 61, 61, 47, 43,160,160,160,160,160,160,160,160, + 161, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 84, 36, + 133, 36, 36, 36, 36, 92, 92, 92, 36, 36, 36, 36, 36, 36, 36, 58, + 162, 92, 92, 92, 92, 92, 92, 92, 36, 36, 36, 58, 27, 27, 27, 27, + 36, 36, 36, 70,140, 27, 27, 27, 36, 36, 36,163, 27, 27, 27, 27, + 36, 36, 36, 36, 36,163, 27, 27, 36, 36, 36, 27, 27, 27, 27, 30, + 36, 36, 36, 36, 36, 36, 27, 36, 63, 43, 43, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 43, 43, 43, 43, 36, 36, 36, 36, 36, 36,163, 30, + 36, 36, 36, 36, 36, 36,163, 27, 36, 36, 36, 36, 71, 36, 36, 36, + 36, 36, 63, 43, 43,161, 27, 27, 36, 36, 36, 36, 58, 2, 2, 2, + 36, 36, 36, 36, 27, 27, 27, 27, 16, 16, 16, 16, 16, 27, 27, 27, + 36, 36, 43, 43, 43, 43, 43, 43, 36, 36, 36, 36, 36, 63,164, 51, + 27, 27, 27, 84, 36, 36, 36, 36,161, 27, 30, 2, 2, 2, 2, 2, + 36, 36,163, 27, 27, 27, 27, 27, 76, 78, 36, 36, 36, 36, 36, 36, + 43, 43, 43, 57, 2, 2, 2, 2, 2, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,165, + 75, 76, 43, 74, 76, 57, 72, 2, 2, 2, 2, 2, 2, 2, 72, 59, + 36, 36, 36, 63, 43, 43, 76, 43, 43, 43, 43, 7, 7, 7, 7, 7, + 2, 2, 79, 78, 36, 36, 36, 36, 36, 63, 2, 36, 36, 36, 36, 36, + 36, 79, 75, 43, 43, 43, 43, 74, 78, 36, 58, 2, 56, 43, 57, 76, + 7, 7, 7, 7, 7, 58, 58, 2, 87, 27, 27, 27, 27, 27, 27, 27, + 36, 36, 36, 36, 36, 36, 75, 76, 43, 75, 74, 43, 2, 2, 2, 43, + 36, 36, 36, 36, 36, 36, 36, 63, 74, 75, 75, 75, 75, 75, 75, 75, + 36, 36, 36, 79, 75, 75, 78, 36, 36, 75, 75, 43, 43, 43, 43, 43, + 36, 36, 79, 75, 43, 43, 43, 43, 75, 43, 74, 64, 36, 58, 2, 2, + 7, 7, 7, 7, 7, 2, 2, 64, 75, 76, 43, 43, 74, 74, 75, 76, + 74, 43, 36, 65, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 79, + 75, 43, 43, 43, 75, 75, 43, 76, 57, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 36, 36, 43, 43, 75, 76, 43, 43, 43, 74, 76, 76, + 57, 2, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 63, 76, 75, + 43, 43, 43, 76, 36, 36, 36, 36, 75, 43, 43, 76, 43, 43, 43, 43, + 7, 7, 7, 7, 7, 27, 2, 86, 43, 43, 43, 43, 76, 57, 2, 2, + 27, 27, 27, 27, 27, 27, 27, 84, 75, 75, 75, 75, 75, 76, 74, 64, + 78, 76, 2, 2, 2, 2, 2, 2, 79, 75, 43, 43, 43, 43, 75, 75, + 64, 65, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, + 63, 43, 43, 43, 43, 64, 36, 36, 36, 63, 43, 43, 74, 63, 43, 57, + 2, 2, 2, 56, 43, 43, 43, 43, 63, 43, 43, 74, 76, 43, 36, 36, + 36, 36, 36, 36, 36, 43, 43, 43, 43, 43, 43, 74, 43, 2, 65, 2, + 43, 43, 43, 43, 43, 43, 43, 76, 58, 2, 2, 2, 2, 2, 2, 2, + 2, 36, 36, 36, 36, 36, 36, 36, 43, 43, 43, 43, 74, 43, 43, 43, + 74, 43, 76, 43, 43, 43, 43, 43, 43, 43, 43, 63, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 75, 75, 75, 43, 74, 76, 76, 36, 36, 36, 36, + 36, 63, 74,145, 2, 2, 2, 2, 27, 27, 81, 61, 61, 61, 53, 20, + 144, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 21, + 43, 43, 57, 2, 2, 2, 2, 2, 43, 43, 43, 57, 2, 2, 61, 61, + 40, 40, 86, 61, 61, 61, 61, 61, 7, 7, 7, 7, 7,166, 27, 27, + 27, 84, 36, 36, 36, 36, 36, 36, 27, 27, 27, 30, 2, 2, 2, 2, + 79, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, 76, + 43, 67, 40, 40, 40, 40, 40, 40, 40, 77, 43, 43, 43, 43, 43, 43, + 36, 36, 36, 36, 36, 36, 47, 57, 61, 61,167, 76, 43, 61,167, 75, + 75,168, 59, 59, 59, 73, 43, 43, 43, 69, 47, 43, 43, 43, 61, 61, + 61, 61, 61, 61, 61, 43, 43, 61, 61, 43, 69, 61, 61, 61, 61, 61, + 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 16, 11, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 11, 11, 11, 11, 11, 16, 16, 16, 16, 16, + 31, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, + 16, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, + 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 31, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 33, 16, 16, 16, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, + 11, 11, 11, 11, 31, 16, 16, 16, 16, 33, 16, 16, 16, 32, 16, 7, + 43, 43, 43, 69, 61, 47, 43, 43, 43, 43, 43, 43, 43, 43, 69, 61, + 61, 61, 47, 61, 61, 61, 61, 61, 61, 61, 69, 21, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 56, 43, 43, 43, 43, 43, 67, 40, 40, 40, 40, + 7, 7, 7, 7, 7, 7, 7, 70, 36, 36, 36, 36, 36, 36, 43, 43, + 7, 7, 7, 7, 7, 7, 7,169, 16, 16, 43, 43, 43, 67, 40, 40, + 27, 27, 27, 27, 27, 27,140, 27,170, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27,140, 27, 27, 27, 27, 27, 27, 81, 61, + 61, 61, 61, 61, 61, 25, 41, 41, 0, 0, 29, 21, 21, 21, 23, 21, + 22, 18, 21, 25, 21, 17, 13, 13, 25, 25, 25, 21, 21, 9, 9, 9, + 9, 22, 21, 18, 24, 16, 24, 5, 5, 5, 5, 22, 25, 18, 25, 0, + 23, 23, 26, 21, 24, 26, 7, 20, 25, 1, 26, 24, 26, 25, 15, 15, + 24, 15, 7, 19, 15, 21, 9, 25, 9, 5, 5, 25, 5, 9, 5, 7, + 7, 7, 9, 8, 8, 5, 7, 5, 6, 6, 24, 24, 6, 24, 12, 12, + 6, 5, 9, 21, 25, 9, 26, 12, 11, 11, 9, 6, 5, 21, 17, 17, + 17, 26, 26, 23, 23, 12, 17, 12, 21, 12, 12, 21, 7, 21, 1, 1, + 21, 23, 26, 26, 6, 7, 7, 12, 12, 7, 21, 7, 12, 1, 12, 6, + 6, 12, 12, 26, 7, 26, 26, 7, 21, 1, 1, 12, 12, 10, 10, 10, + 10, 12, 21, 6, 10, 7, 7, 10, 23, 7, 15, 26, 13, 21, 13, 7, + 15, 7, 12, 23, 21, 26, 21, 15, 17, 7, 29, 7, 7, 22, 18, 18, + 14, 14, 14, 7, 17, 21, 7, 6, 11, 12, 5, 6, 8, 8, 8, 24, + 5, 24, 9, 24, 29, 29, 29, 1, 20, 19, 22, 20, 27, 28, 1, 29, + 21, 20, 19, 21, 21, 16, 16, 21, 25, 22, 18, 21, 21, 29, 15, 6, + 18, 6, 12, 11, 9, 26, 26, 9, 26, 5, 5, 26, 14, 9, 5, 14, + 14, 15, 25, 26, 26, 22, 18, 26, 18, 25, 18, 22, 5, 12, 22, 21, + 26, 6, 7, 14, 17, 22, 26, 14, 17, 6, 14, 6, 12, 24, 24, 6, + 26, 15, 6, 21, 11, 21, 24, 9, 23, 26, 10, 21, 6, 10, 4, 4, + 3, 3, 7, 25, 24, 7, 22, 22, 21, 22, 17, 16, 16, 22, 16, 16, + 25, 17, 7, 1, 25, 24, 26, 1, 2, 2, 12, 15, 21, 14, 7, 15, + 12, 17, 13, 12, 13, 15, 26, 10, 10, 1, 13, 23, 23, 15, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 0, 10, 11, 12, 13, 0, 14, 0, + 0, 0, 0, 0, 15, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 21, 22, 23, + 0, 0, 0, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 34, 0, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 38, 0, 0, 0, 0, 0, 0, 39, 40, + 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 2, 0, 0, 0, 0, 3, 0, 0, 0, 4, 5, 6, 7, 0, 8, + 9, 10, 0, 11, 12, 13, 0, 14, 15, 16, 15, 17, 15, 18, 15, 18, + 15, 18, 0, 18, 0, 19, 15, 18, 20, 18, 0, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 32, 0, 0, 0, 0, 0, 0, 33, 0, 0, 34, 0, 0, 35, 0, + 36, 0, 0, 0, 37, 38, 39, 40, 41, 42, 43, 44, 45, 0, 0, 46, + 0, 0, 0, 47, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, 49, + 0, 50, 0, 51, 52, 0, 53, 0, 0, 0, 0, 0, 0, 54, 55, 56, + 0, 0, 0, 0, 57, 0, 0, 58, 59, 60, 61, 62, 0, 0, 63, 64, + 0, 0, 0, 65, 0, 0, 0, 0, 66, 0, 0, 0, 67, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 68, 0, 0, 0, 69, + 0, 70, 0, 0, 71, 0, 0, 72, 0, 0, 0, 0, 0, 0, 0, 0, + 73, 0, 0, 0, 0, 0, 74, 0, 0, 75, 0, 0, 0, 76, 77, 0, + 78, 61, 0, 79, 80, 0, 0, 81, 82, 83, 0, 0, 0, 84, 0, 85, + 0, 0, 50, 86, 50, 0, 87, 0, 88, 0, 0, 0, 77, 0, 0, 0, + 89, 90, 0, 91, 92, 93, 94, 0, 0, 0, 0, 0, 50, 0, 0, 0, + 0, 95, 96, 0, 0, 0, 0, 97, 98, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 99, 0, 0,100, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,101,102, 0, 0,103, 0, 0, 0, 0, 0, 0,104, 0, 0, 0, + 98, 0, 0, 0, 0, 0, 0,105, 0, 0, 0, 0, 0, 0, 0,106, + 0,107, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 0, + 8, 0, 0, 0, 0, 9, 10, 11, 12, 0, 0, 0, 0, 13, 0, 0, + 14, 15, 0, 16, 0, 17, 18, 0, 0, 19, 0, 20, 21, 0, 0, 0, + 0, 0, 22, 23, 0, 24, 25, 0, 0, 26, 0, 0, 0, 27, 28, 29, + 0, 0, 0, 30, 31, 32, 0, 0, 31, 0, 0, 33, 31, 0, 0, 0, + 31, 34, 0, 0, 0, 0, 0, 35, 36, 0, 0, 0, 0, 0, 0, 37, + 38, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 41, 0, 42, + 0, 0, 0, 43, 44, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 46, + 47, 0, 0, 0, 0, 48, 0, 0, 0, 49, 0, 49, 0, 50, 0, 0, + 0, 0, 51, 0, 0, 0, 0, 52, 0, 53, 0, 0, 0, 0, 54, 55, + 0, 0, 0, 56, 57, 0, 0, 0, 0, 0, 0, 58, 49, 0, 59, 60, + 0, 0, 61, 0, 0, 0, 62, 63, 0, 0, 0, 64, 0, 65, 66, 67, + 68, 69, 1, 70, 0, 71, 72, 73, 0, 0, 74, 75, 0, 0, 0, 76, + 0, 0, 1, 1, 0, 0, 77, 0, 0, 78, 0, 0, 0, 0, 74, 79, + 0, 80, 0, 0, 0, 0, 0, 75, 81, 0, 82, 0, 49, 0, 1, 75, + 0, 0, 83, 0, 0, 84, 0, 0, 0, 0, 0, 85, 54, 0, 0, 0, + 0, 0, 0, 86, 87, 0, 0, 81, 0, 0, 31, 0, 0, 88, 0, 0, + 0, 0, 89, 0, 0, 0, 0, 47, 0, 0, 57, 0, 0, 0, 0, 90, + 91, 0, 0, 92, 0, 0, 93, 0, 0, 0, 94, 0, 0, 0, 95, 0, + 96, 57, 0, 0, 81, 0, 0, 76, 0, 0, 0, 97, 98, 0, 0, 99, + 100, 0, 0, 0, 0, 0, 0,101, 0, 0,102, 0, 0, 0, 0,103, + 31, 0,104,105,106, 33, 0, 0,107, 0, 0, 0,108, 0, 0, 0, + 0, 0, 0,109, 0, 0,110, 0, 0, 0, 0,111, 85, 0, 0, 0, + 0, 0, 54, 0, 0, 0, 0, 49,112, 0, 0, 0, 0,113, 0, 0, + 114, 0, 0, 0, 0,112, 0, 0, 0, 0, 0,115, 0, 0, 0,116, + 0, 0, 0,117, 0,118, 0, 0, 0, 0,119,120,121, 0,122, 0, + 123, 0, 0, 0,124,125,126, 0, 0, 0,127, 0, 0,128, 0, 0, + 129, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3, 4, + 5, 6, 7, 4, 4, 8, 9, 10, 1, 11, 12, 13, 14, 15, 16, 17, + 18, 1, 1, 1, 19, 1, 0, 0, 20, 21, 22, 1, 23, 4, 21, 24, + 25, 26, 27, 28, 29, 30, 0, 0, 1, 1, 31, 0, 0, 0, 32, 33, + 34, 35, 1, 36, 37, 0, 0, 0, 0, 38, 1, 39, 14, 39, 40, 41, + 42, 0, 0, 0, 43, 36, 44, 45, 21, 45, 46, 0, 0, 0, 19, 1, + 21, 0, 0, 47, 0, 38, 48, 1, 1, 49, 49, 50, 0, 0, 51, 0, + 52, 1, 1, 1, 53, 21, 43, 54, 55, 21, 35, 1, 0, 0, 0, 56, + 0, 0, 0, 57, 58, 59, 0, 0, 0, 0, 0, 60, 0, 61, 0, 0, + 0, 0, 62, 63, 0, 0, 64, 0, 0, 0, 65, 0, 0, 0, 66, 0, + 0, 0, 67, 0, 0, 0, 68, 0, 0, 0, 69, 0, 0, 70, 71, 0, + 72, 73, 74, 75, 76, 77, 0, 0, 0, 78, 0, 0, 0, 79, 80, 0, + 0, 0, 0, 47, 0, 0, 0, 49, 0, 63, 0, 0, 64, 0, 0, 81, + 0, 0, 82, 0, 0, 0, 83, 0, 0, 19, 84, 0, 63, 0, 0, 0, + 0, 49, 1, 85, 1, 54, 15, 86, 84, 0, 0, 0, 0, 56, 0, 0, + 0, 0, 19, 10, 1, 0, 0, 0, 0, 0, 87, 0, 0, 88, 0, 0, + 87, 0, 0, 0, 0, 79, 0, 0, 89, 9, 12, 4, 90, 8, 91, 47, + 0, 59, 50, 0, 21, 1, 21, 92, 93, 1, 1, 1, 1, 94, 95, 96, + 97, 1, 98, 59, 81, 99,100, 4, 59, 0, 0, 0, 0, 0, 0, 19, + 50, 0, 0, 0, 0, 0, 0, 62, 0, 0,101,102, 0, 0,103, 0, + 0, 1, 1, 50, 0, 0, 0, 38, 0, 64, 0, 0, 0, 0, 0, 63, + 0, 0, 52, 69, 62, 0, 0, 0, 79, 0, 0, 0,104,105, 59, 38, + 81, 0, 0, 0, 0, 0, 0,106, 1, 14, 4, 12, 0, 38, 89, 0, + 0, 0, 0,107, 0, 0,108, 62, 0,109, 0, 0, 0, 1, 0, 0, + 0, 0, 19, 59, 0,110, 14, 54, 0, 0,111, 0, 89, 0, 0, 0, + 62, 63, 0, 0, 63, 0, 88, 0, 0,111, 0, 0, 0, 0,112, 0, + 0, 0, 79, 56, 0, 38, 1, 59, 1, 59, 0, 0, 64, 88, 0, 0, + 113, 0, 0, 0, 56, 0, 0, 0, 0,113, 0, 0, 0, 0, 62, 0, + 0, 0, 0, 80, 0, 62, 0, 0, 0, 0, 57, 0, 88,114, 0, 0, + 8, 91, 0, 0, 1, 89, 0, 0,115, 0, 0, 0, 0, 0, 0,116, + 0,117,118,119,120, 0, 52, 4,121, 49, 23, 0, 0, 0, 38, 50, + 38, 59, 0, 0, 1, 89, 1, 1, 1, 1, 39, 1, 48,104, 89, 0, + 0, 0, 0, 1, 4,121, 0, 0, 0, 1,122, 0, 0, 0, 0, 0, + 230,230,230,230,230,232,220,220,220,220,232,216,220,220,220,220, + 220,202,202,220,220,220,220,202,202,220,220,220, 1, 1, 1, 1, + 1,220,220,220,220,230,230,230,230,240,230,220,220,220,230,230, + 230,220,220, 0,230,230,230,220,220,220,220,230,232,220,220,230, + 233,234,234,233,234,234,233,230, 0, 0, 0,230, 0,220,230,230, + 230,230,220,230,230,230,222,220,230,230,220,220,230,222,228,230, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 0, 23, + 0, 24, 25, 0,230,220, 0, 18, 30, 31, 32, 0, 0, 0, 0, 27, + 28, 29, 30, 31, 32, 33, 34,230,230,220,220,230,220,230,230,220, + 35, 0, 0, 0, 0, 0,230,230,230, 0, 0,230,230, 0,220,230, + 230,220, 0, 0, 0, 36, 0, 0,230,220,230,230,220,220,230,220, + 220,230,220,230,220,230,230, 0, 0,220, 0, 0,230,230, 0,230, + 0,230,230,230,230,230, 0, 0, 0,220,220,220, 0, 0, 0,220, + 230,230, 0,220,230,220,220,220, 27, 28, 29,230, 7, 0, 0, 0, + 0, 9, 0, 0, 0,230,220,230,230, 0, 0, 0, 0, 0,230, 0, + 0, 84, 91, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 9, 0, + 103,103, 9, 0,107,107,107,107,118,118, 9, 0,122,122,122,122, + 220,220, 0, 0, 0,220, 0,220, 0,216, 0, 0, 0,129,130, 0, + 132, 0, 0, 0, 0, 0,130,130,130,130, 0, 0,130, 0,230,230, + 9, 0,230,230, 0, 0,220, 0, 0, 0, 0, 7, 0, 9, 9, 0, + 0,230, 0, 0, 0,228, 0, 0, 0,222,230,220,220, 0, 0, 0, + 230, 0, 0,220,230,220, 0,220, 0, 0, 9, 9, 0, 0, 7, 0, + 230,230,230, 0,230, 0, 1, 1, 1, 0, 0, 0,230,234,214,220, + 202,230,230,230,230,230,232,228,228,220, 0,230,233,220,230,220, + 230,230, 1, 1, 1, 1, 1,230, 0, 1, 1,230,220,230, 1, 1, + 0, 0,218,228,232,222,224,224, 0, 8, 8, 0,230, 0,230,230, + 220, 0, 0,230, 0, 0, 26, 0, 0,220, 0,230,230, 1,220, 0, + 0,230,220, 0, 0, 0,220,220, 0, 9, 7, 0, 0, 7, 9, 0, + 0, 0, 9, 7, 9, 9, 0, 0, 6, 6, 0, 0, 0, 0, 1, 0, + 0,216,216, 1, 1, 1, 0, 0, 0,226,216,216,216,216,216, 0, + 220,220,220, 0,230,230, 7, 0, 16, 17, 17, 33, 17, 49, 17, 17, + 84, 97,135,145, 26, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17,177, 0, 1, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, + 3, 3, 5, 3, 3, 3, 3, 3, 6, 7, 8, 3, 3, 3, 3, 3, + 9, 10, 11, 12, 13, 3, 3, 3, 3, 3, 3, 3, 3, 14, 3, 15, + 3, 3, 3, 3, 3, 3, 16, 17, 18, 19, 20, 21, 3, 3, 3, 22, + 23, 3, 3, 3, 3, 3, 3, 3, 24, 3, 3, 3, 3, 3, 3, 3, + 3, 25, 3, 3, 26, 27, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, + 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, + 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, + 9, 0, 0, 0, 0, 0, 0, 9, 0, 9, 0, 0, 0, 0, 0, 0, + 0, 10, 11, 12, 13, 0, 0, 14, 15, 16, 6, 0, 17, 18, 19, 19, + 19, 20, 21, 22, 23, 24, 19, 25, 0, 26, 27, 19, 19, 28, 29, 30, + 0, 31, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 19, 28, 0, + 32, 33, 9, 34, 35, 19, 0, 0, 36, 37, 38, 39, 40, 19, 0, 41, + 42, 43, 44, 31, 0, 1, 45, 42, 0, 0, 0, 0, 0, 32, 14, 14, + 0, 0, 0, 0, 14, 0, 0, 46, 47, 47, 47, 47, 48, 49, 47, 47, + 47, 47, 50, 51, 52, 53, 43, 21, 0, 0, 0, 0, 0, 0, 0, 54, + 6, 55, 0, 14, 19, 1, 0, 0, 0, 19, 56, 31, 0, 0, 0, 0, + 0, 0, 0, 57, 14, 0, 0, 0, 0, 1, 0, 2, 0, 0, 0, 3, + 0, 0, 0, 58, 59, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 2, 3, 0, 4, 5, 0, 0, 6, 0, 0, 0, 7, 0, 0, + 0, 1, 1, 0, 0, 8, 9, 0, 8, 9, 0, 0, 0, 0, 8, 9, + 10, 11, 12, 0, 0, 0, 13, 0, 0, 0, 0, 14, 15, 16, 17, 0, + 0, 0, 1, 0, 0, 18, 19, 0, 0, 0, 20, 0, 0, 0, 1, 1, + 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, 8, 21, 9, 0, 0, + 22, 0, 0, 0, 0, 1, 0, 23, 24, 25, 0, 0, 26, 0, 0, 0, + 8, 21, 27, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 28, 29, 30, + 0, 31, 32, 20, 1, 1, 0, 0, 0, 8, 21, 9, 1, 4, 5, 0, + 0, 0, 33, 9, 0, 1, 1, 1, 0, 8, 21, 21, 21, 21, 34, 1, + 35, 21, 21, 21, 9, 36, 0, 0, 37, 38, 1, 0, 39, 0, 0, 0, + 1, 0, 1, 0, 0, 0, 0, 8, 21, 9, 1, 0, 0, 0, 40, 0, + 8, 21, 21, 21, 21, 21, 21, 21, 21, 9, 0, 1, 1, 1, 1, 8, + 21, 21, 21, 9, 0, 0, 0, 41, 0, 42, 43, 0, 0, 0, 1, 44, + 0, 0, 0, 45, 8, 9, 1, 0, 1, 0, 1, 1, 8, 21, 21, 9, + 0, 4, 5, 8, 9, 1, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, + 7, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 9, 10, 11, 11, + 11, 11, 11, 12, 12, 12, 12, 13, 14, 15, 16, 17, 18, 12, 19, 12, + 20, 12, 12, 12, 12, 21, 22, 22, 22, 23, 12, 12, 12, 12, 24, 25, + 12, 12, 26, 27, 28, 29, 30, 31, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 32, 12, 33, 7, 7, 34, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 35, 0, 0, 1, 2, 2, 2, 3, + 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, + 33, 34, 35, 35, 35, 35, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 2, 2, 51, 51, 52, 53, 54, 55, 56, 56, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 56, 56, 56, 56, + 56, 56, 58, 59, 60, 61, 56, 62, 62, 63, 64, 65, 66, 67, 68, 69, + 70, 56, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 62, 71, 62, 62, 62, 62, 72, 72, 72, 72, 72, 72, + 72, 72, 72, 73, 74, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, + 88, 89, 89, 89, 90, 89, 91, 92, 93, 94, 95, 95, 96, 97, 87, 98, + 99,100,101,102,103, 87,104,104,104, 87,105,106,107,108,109,110, + 111,112,113,114,115, 87, 89,116,117,118,119,120,121,122,123,124, + 125, 87,126,127, 87,128,129,130,131, 87,132,133,134,135,136,137, + 87, 87,138,139,140,141, 87,142, 87,143,144,144,144,144,144,144, + 144,144,144,144,144, 87, 87, 87, 87, 87,145,145,145,145,145,145, + 145,145,145, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87,146,146,146,146,146, 87, 87, 87,147,147,147,147,148,149, + 150,150, 87, 87, 87, 87,151,151,152,153,154,154,154,154,154,154, + 154,154,154,154,154,154,154,154,154,154,154,154,154,154,154,154, + 155,155,155,155,154, 87, 87, 87, 87, 87,156,157,158,159,159,159, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87,160,161, 87, 87, 87, 87, 87, 87, 56, 56,162,163, 51, 56, + 56, 87, 56, 56, 56, 56, 56, 56, 56, 56,164,164,164,164,164,164, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,165, 87,166, 87, 87,167, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87,168,168,169, 87, 87, 87, + 87, 87, 56, 56, 56, 87, 89, 89, 87, 87, 56, 56, 56, 56,170, 87, + 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, + 56, 56, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 62, 62, + 62, 62, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 62, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, 62, 62, 62, 62, 62, 62, + 62, 87, 87, 87, 87, 87, 87, 87, 87, 87, 56, 87,171,171, 0, 1, + 2, 2, 0, 1, 2, 2, 2, 3, 4, 5, 0, 0, 0, 0, 1, 2, + 1, 2, 0, 0, 3, 3, 4, 5, 4, 5, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 6, 0, 0, 7, 0, 8, 8, 8, 8, 8, 8, + 8, 9, 10, 11, 11, 11, 11, 11, 12, 11, 13, 13, 13, 13, 13, 13, + 13, 13, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 15, 16, 16, + 16, 16, 16, 17, 18, 18, 18, 18, 18, 18, 19, 20, 21, 21, 22, 23, + 21, 24, 21, 21, 21, 21, 21, 25, 21, 21, 26, 26, 26, 26, 26, 21, + 21, 21, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, + 26, 26, 21, 21, 21, 21, 21, 21, 31, 21, 32, 32, 32, 32, 32, 33, + 34, 32, 35, 35, 35, 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, 36, + 36, 36, 37, 37, 37, 37, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, + 38, 38, 39, 39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, + 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 42, + 42, 42, 43, 43, 43, 43, 43, 43, 43, 43, 44, 44, 44, 45, 44, 44, + 44, 44, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 48, 47, 47, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 50, 50, 50, 50, 50, 51, 52, 52, 52, 52, 52, 52, + 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, + 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 57, 57, 57, 57, + 58, 57, 59, 59, 60, 61, 62, 62, 63, 63, 64, 64, 64, 64, 64, 64, + 64, 64, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 55, 55, 55, + 55, 55, 67, 67, 67, 67, 67, 68, 68, 68, 69, 69, 69, 69, 69, 69, + 64, 64, 70, 70, 71, 71, 71, 71, 71, 71, 71, 71, 71, 8, 8, 8, + 8, 8, 72, 72, 72, 72, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, + 74, 74, 75, 75, 75, 75, 75, 76, 76, 76, 13, 50, 50, 50, 73, 77, + 78, 79, 4, 4, 80, 4, 4, 81, 82, 83, 4, 4, 4, 84, 8, 8, + 8, 8, 11, 11, 11, 11, 11, 11, 11, 11, 85, 0, 0, 0, 0, 0, + 0, 86, 0, 4, 0, 0, 0, 8, 8, 8, 0, 0, 87, 88, 89, 0, + 4, 4, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, + 4, 4, 92, 92, 92, 92, 92, 92, 92, 92, 50, 50, 50, 93, 93, 93, + 93, 93, 53, 53, 53, 53, 53, 53, 13, 13, 94, 94, 94, 94, 94, 94, + 94, 94, 94, 94, 94, 94, 94, 94, 94, 0, 95, 0, 96, 97, 98, 99, + 99, 99, 99,100,101,102,102,102,102,103,104,104,104,105, 52, 52, + 52, 52, 52, 0,104,104, 0, 0, 0,102, 52, 52, 0, 0, 0, 0, + 52,106, 0, 0, 0, 0, 0,102,102,107,102,102,102,102,102,108, + 0, 0, 94, 94, 94, 94, 0, 0, 0, 0,109,109,109,109,109,109, + 109,109,109,109,109,109,109,110,110,110,111,111,111,111,111,111, + 111,111,111,111,111,111, 13, 13, 13, 13, 13, 13,112,112,112,112, + 112,112, 0, 0,113, 4, 4, 4, 4, 4,114, 4, 4, 4, 4, 4, + 4, 4,115,115,115, 0,116,116,116,116,117,117,117,117,117,117, + 32, 32,118,118,119,120,120,120, 52, 52,121,121,121,121,122,121, + 49, 49,123,123,123,123,123,123, 49, 49,124,124,124,124,124,124, + 125,125, 53, 53, 53, 4, 4,126,127, 54, 54, 54, 54, 54,125,125, + 125,125,128,128,128,128,128,128,128,128, 4,129, 18, 18, 18, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,130, 0, 21, + 21, 21, 8, 0,131, 0, 0, 0, 0, 21, 21, 21, 21, 21, 21, 21, + 21,132, 0, 0, 1, 2, 1, 2,133,101,102,134, 52, 52, 52, 52, + 0, 0,135,135,135,135,135,135,135,135, 0, 0, 0, 0, 11, 11, + 11, 11, 11, 0, 11, 11, 11, 0, 0,136,137,137,138,138,138,138, + 139, 0,140,140,140,141,141,142,142,142,143,143,144,144,144,144, + 144,144,145,145,145,145,145,146,146,146,147,147,147,148,148,148, + 148,148,149,149,149,150,150,150,150,150,151,151,151,151,151,151, + 151,151,152,152,152,152,153,153,154,154,155,155,155,155,155,155, + 156,156,157,157,158,158,158,158,158,158,159,159,160,160,160,160, + 160,160,161,161,161,161,161,161,162,162,163,163,163,163,164,164, + 164,164,165,165,165,165,166,166,167,167,168,168,168,168,168,168, + 168,168,169,169,169,169,169,169,169,169,170,170,170,170,170,170, + 170,170,171,171,171,171,171,171,171,171,172,172,172,172,172,172, + 172,172,173,173,173,174,174,174,174,174,175,175,175,175,175,175, + 176,176,177,177,177,177,177,177,177,177,178,178,178,178,178,179, + 179,179,180,180,180,180,180,181,181,181,182,182,182,182,182,182, + 183, 43,184,184,184,184,184,184,184,184,185,185,185,186,186,186, + 186,186,187,187,187,188,187,187,187,187,189,189,189,189,189,189, + 189,189,190,190,190,190,190,190,190,190,191,191,191,191,191,191, + 191,191,192,192,192,192,192,192, 66, 66,193,193,193,193,193,193, + 193,193,194,194,194,194,194,194,194,194,195,195,195,195,195,195, + 195,195,196,196,196,196,196,196,196,196,197,197,197,197,197,197, + 197,197,198,198,198,198,198,198,198,198,199,199,199,199,199,200, + 200,200,200,200,200,200,201,201,201,201,202,202,202,202,202,202, + 202,203,203,203,203,203,203,203,203,203,204,204,204,204,204,204, + 205,205,205,205,205,205,205,205,205,205,206,206,206,206,206,206, + 206,206,110,110,110,110, 39, 39, 39, 39,207,207,207,207,207,207, + 207,207,208,208,208,208,208,208,208,208,209,209,209,209,209,209, + 209,209,112,112,112,112,112,112,112,112,112,112,112,112,210,210, + 210,210,211,211,211,211,211,211,211,211,212,212,212,212,212,212, + 212,212,213,213,213,213,213,213,213,213,214,214,214,214,214,214, + 214,214,214,214,214,214,214,214,215, 94,216,216,216,216,216,216, + 216,216,217,217,217,217,217,217,217,217,218, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, + 219,220,220,220,220,220,220,220,220,220,221,221,221,221,221,221, + 221,221,221,221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 222,223,224, 0,225, 0, 0, 0, 0, 0,226,226,226,226,226,226, + 226,226, 91, 91, 91, 91, 91, 91, 91, 91,227,227,227,227,227,227, + 227,227,228,228,228,228,228,228,228,228,229,229,229,229,229,229, + 229,229,230,230,230,230,230,230,230,230,231, 0, 0, 0, 0, 0, + 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 0, 0, 0, 0, 1, 2, + 2, 2, 2, 2, 3, 0, 0, 0, 4, 0, 2, 2, 2, 2, 2, 3, + 2, 2, 2, 2, 5, 0, 2, 5, 6, 0, 7, 7, 7, 7, 8, 9, + 8, 10, 8, 11, 8, 8, 8, 8, 8, 8, 12, 13, 13, 13, 14, 14, + 14, 14, 14, 15, 14, 14, 16, 17, 17, 17, 17, 17, 17, 17, 18, 19, + 19, 19, 19, 19, 19, 19, 20, 21, 20, 22, 20, 20, 23, 23, 20, 20, + 20, 20, 22, 20, 24, 7, 7, 25, 20, 20, 26, 20, 20, 20, 20, 20, + 20, 21, 27, 27, 27, 27, 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, + 30, 30, 31, 31, 31, 31, 32, 20, 20, 20, 33, 33, 33, 33, 34, 35, + 33, 33, 33, 36, 33, 33, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, + 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, + 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, + 46, 47, 48, 48, 48, 48, 49, 49, 49, 49, 49, 50, 51, 49, 52, 52, + 52, 52, 53, 53, 53, 53, 53, 53, 54, 53, 55, 55, 55, 55, 56, 56, + 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, + 60, 60, 60, 60, 61, 62, 63, 63, 63, 63, 64, 64, 64, 64, 64, 65, + 0, 0, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 70, + 71, 71, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 74, 74, + 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78, + 78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 7, + 7, 7, 83, 7, 84, 85, 0, 84, 86, 0, 2, 87, 88, 2, 2, 2, + 2, 89, 90, 87, 91, 2, 2, 2, 92, 2, 2, 2, 2, 93, 0, 0, + 0, 86, 1, 0, 0, 94, 0, 95, 96, 0, 4, 0, 0, 0, 0, 0, + 0, 4, 97, 97, 97, 97, 98, 98, 98, 98, 13, 13, 13, 13, 99, 99, + 99, 99,100,100,100,100, 0,101, 0, 0,102,100,103,104, 0, 0, + 100, 0,105,106,106,106,106,106,106,106,106,106,107,105,108,109, + 109,109,109,109,109,109,109,109,110,108,111,111,111,111,112, 55, + 55, 55, 55, 55, 55,113,109,109,109,110,109,109, 0, 0,114,114, + 114,114,115,115,115,115,116,116,116,116,117,117,117,117, 96, 2, + 2, 2, 2, 2, 94, 2,118,118,118,118,119,119,119,119,120,120, + 120,120,121,121,121,121,121,121,121,122,123,123,123,123,124,124, + 124,124,124,124,124,125,126,126,126,126,127,127,127,127,128,128, + 128,128, 2, 2, 3, 2, 2,129,130, 0,131,131,131,131,132, 17, + 17, 18, 20, 20, 20,133, 7, 7, 7,134, 20, 20, 20, 23, 0,135, + 109,109,109,109,109,136,137,137,137,137, 0, 0, 0,138,139,139, + 139,139,140,140,140,140, 84, 0, 0, 0,141,141,141,141,142,142, + 142,142,143,143,143,143,144,144,144,144,145,145,145,145,146,146, + 146,146,147,147,147,147,148,148,148,148,149,149,149,149,150,150, + 150,150,151,151,151,151,152,152,152,152,153,153,153,153,154,154, + 154,154,155,155,155,155,156,156,156,156,157,157,157,157,158,158, + 158,158,159,159,159,159,160,160,160,160,161,161,161,161,162,162, + 162,162,163,163,163,163,164,164,164,164,165,165,165,165,166,166, + 166,166,167,167,167,167,168,168,168,168,169,169,169,169,170,170, + 170,170,171,171,171,171,172,172,172,172,173,173,173,173,174,174, + 174,174,175,175,175,175,176,176,176,176,177,177,177,177,178,178, + 178,178,179,179,179,179,180,180,180,180,181,181,181,181,182,182, + 182,182,183,183,183,183,184, 45, 45, 45,185,185,185,185,186,186, + 186,186,187,187,187,187,188,188,188,188,188,188,189,188,190,190, + 190,190,191,191,191,191,192,192,192,192,193,193,193,193,194,194, + 194,194,195,195,195,195,196,196,196,196,197,197,197,197,198,198, + 198,198,199,199,199,199,200,200,200,200,201,201,201,201,202,202, + 202,202,203,203,203,203,204,204,204,204,205,205,205,205,206,206, + 206,206,207,207,207,207,208,208,208,208,209,209,209,209,210,210, + 210,210,211,211,211,211,212,212,212,212,213,213,213,213,214,214, + 214,214,215,215,215,215,216,217,217,217,218,218,218,218,217,217, + 217,217,219,106,106,106,106,109,109,109,220,220,220,220,221,221, + 221,221, 0,222, 86, 0, 0, 0,222, 7, 82,138, 7, 0, 0, 0, + 223, 86,224,224,224,224,225,225,225,225,226,226,226,226,227,227, + 227,227,228,228,228,228,229, 0, 0, 0, 0, 0, 0, 0, 0, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 0, 0, 0, 19, 0, 19, 0, + 0, 0, 0, 0, 26, 26, 1, 1, 1, 1, 9, 9, 9, 9, 0, 9, + 9, 9, 9, 9, 0, 9, 9, 0, 9, 0, 9, 9, 55, 55, 55, 55, + 55, 55, 6, 6, 6, 6, 6, 1, 1, 6, 6, 4, 4, 4, 4, 4, + 4, 4, 4, 14, 14, 14, 14, 14, 14, 14, 3, 3, 3, 3, 3, 0, + 3, 3, 0, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 1, 1, 1, + 3, 3, 1, 3, 3, 3, 37, 37, 37, 37, 38, 38, 38, 38, 64, 64, + 64, 64, 90, 90, 90, 90, 95, 95, 95, 95, 3, 3, 0, 3, 7, 7, + 7, 7, 7, 1, 1, 1, 1, 7, 7, 7, 0, 0, 7, 7, 5, 5, + 5, 5, 11, 11, 11, 11, 10, 10, 10, 10, 21, 21, 21, 21, 22, 22, + 22, 22, 23, 23, 23, 23, 16, 16, 16, 16, 20, 20, 20, 20, 36, 36, + 36, 36, 24, 24, 24, 24, 24, 24, 24, 0, 18, 18, 18, 18, 25, 25, + 25, 25, 25, 0, 0, 0, 0, 25, 25, 25, 33, 33, 33, 33, 8, 8, + 8, 8, 8, 8, 8, 0, 12, 12, 12, 12, 30, 30, 30, 30, 29, 29, + 29, 29, 28, 28, 28, 28, 34, 34, 34, 34, 35, 35, 35, 35, 35, 35, + 35, 0, 0, 0, 35, 35, 45, 45, 45, 45, 44, 44, 44, 44, 44, 0, + 0, 0, 43, 43, 43, 43, 46, 46, 46, 46, 31, 31, 31, 31, 32, 32, + 0, 0, 32, 0, 32, 32, 32, 32, 32, 32, 48, 48, 48, 48, 52, 52, + 52, 52, 58, 58, 58, 58, 54, 54, 54, 54, 91, 91, 91, 91, 62, 62, + 62, 62, 76, 76, 76, 76, 93, 93, 93, 93, 70, 70, 70, 70, 73, 73, + 73, 73, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, + 0, 0, 1, 1, 0, 0, 19, 19, 9, 9, 9, 9, 9, 6, 19, 9, + 9, 9, 9, 9, 19, 19, 9, 9, 9, 19, 6, 19, 19, 19, 19, 19, + 19, 9, 0, 0, 0, 19, 0, 0, 9, 0, 0, 0, 19, 19, 27, 27, + 27, 27, 56, 56, 56, 56, 61, 61, 61, 61, 13, 13, 13, 13, 0, 13, + 0, 13, 0, 13, 13, 13, 13, 13, 1, 1, 1, 1, 12, 12, 0, 15, + 15, 15, 15, 15, 15, 15, 15, 1, 1, 0, 0, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 0, 26, 26, 26, 26, 26, 12, 12, 12, 12, 12, + 12, 0, 39, 39, 39, 39, 86, 86, 86, 86, 77, 77, 77, 77, 79, 79, + 79, 79, 60, 60, 60, 60, 65, 65, 65, 65, 75, 75, 75, 75, 69, 69, + 69, 69, 69, 69, 0, 69, 74, 74, 74, 74, 84, 84, 84, 84, 84, 84, + 84, 0, 68, 68, 68, 68, 92, 92, 92, 92, 87, 87, 87, 87, 19, 9, + 19, 19, 19, 19, 0, 0, 2, 2, 2, 2, 19, 19, 19, 4, 3, 3, + 0, 0, 1, 1, 6, 6, 0, 0, 17, 17, 17, 17, 0, 0, 49, 49, + 49, 49, 0, 1, 1, 1, 71, 71, 71, 71, 67, 67, 67, 67, 42, 42, + 42, 42, 41, 41, 41, 41,118,118,118,118, 53, 53, 53, 53, 59, 59, + 59, 59, 40, 40, 40, 40, 51, 51, 51, 51, 50, 50, 50, 50,135,135, + 135,135,106,106,106,106,104,104,104,104,110,110,110,110, 47, 47, + 47, 47, 81, 81, 81, 81,120,120,120,120,116,116,116,116,128,128, + 128,128, 66, 66, 66, 66, 72, 72, 72, 72, 98, 98, 98, 98, 97, 97, + 97, 97, 57, 57, 57, 57, 88, 88, 88, 88,117,117,117,117,112,112, + 112,112, 78, 78, 78, 78, 83, 83, 83, 83, 82, 82, 82, 82,122,122, + 122,122, 89, 89, 89, 89,130,130,130,130,144,144,144,144,156,156, + 156,156,147,147,147,147,148,148,148,148,153,153,153,153,149,149, + 149,149, 94, 94, 94, 94, 85, 85, 85, 85,101,101,101,101, 96, 96, + 96, 96,111,111,111,111,100,100,100,100,100, 36, 36, 36,108,108, + 108,108,129,129,129,129,109,109,109,109,107,107,107,107,107,107, + 107, 1,137,137,137,137,124,124,124,124,123,123,123,123,114,114, + 114,114,102,102,102,102,126,126,126,126,142,142,142,142,125,125, + 125,125,154,154,154,154,150,150,150,150,141,141,141,141,140,140, + 140,140,121,121,121,121,133,133,133,133,134,134,134,134,138,138, + 138,138,143,143,143,143,145,145,145,145, 63, 63, 63, 63, 80, 80, + 80, 80,127,127,127,127,115,115,115,115,103,103,103,103,119,119, + 119,119,146,146,146,146, 99, 99, 99, 99,136,139, 0, 0,155,155, + 155,155,136,136,136,136, 17, 15, 15, 15,139,139,139,139,105,105, + 105,105, 0, 0, 0, 1, 0, 0, 1, 1,131,131,131,131,151,151, + 151,151,152,152,152,152,113,113,113,113,132,132,132,132, 15, 0, + 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 9, 10, + 9, 11, 12, 13, 9, 9, 9, 14, 9, 9, 15, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 16, 17, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 18, 19, 20, 9, 21, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 22, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 23, 24, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 0, 0, 13, 14, 15, 16, 17, 18, + 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 23, 0, 0, 24, 25, 26, 27, 28, 29, 30, 0, 0, + 31, 32, 0, 33, 0, 34, 0, 35, 0, 0, 0, 0, 36, 37, 38, 39, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 41, 42, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 43, 44, 0, 45, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, + 0, 0, 0, 48, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 50, 51, 0, 0, 0, 52, 0, 0, 53, 0, 0, 0, + 0, 0, 0, 0, 54, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, + 0, 0, 0, 0, 56, 0, 0, 0, 0, 0, 0, 0, 0, 57, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 58, 59, 60, 61, 62, 63, 64, 65, 0, 0, 0, 0, + 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 67, 68, 0, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102, + 103, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0,104, 0, 0, 0, 0, 0, 0,105,106, 0,107, 0, 0, 0, + 108, 0,109, 0,110, 0,111,112,113, 0,114, 0, 0, 0,115, 0, + 0, 0,116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,117, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,118,119,120,121, 0,122,123,124,125,126, 0,127, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143, + 144,145,146,147,148,149,150,151,152,153,154,155,156,157, 0, 0, + 0,158,159,160,161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,162,163, 0, 0, 0, 0, 0, + 0, 0,164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,166, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,167, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,169,170, 0, 0, 0, 0,171,172, 0, 0, 0, + 173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188, + 189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204, + 205,206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, +}; +static const uint16_t +_hb_ucd_u16[4848] = +{ + 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 10, 11, 12, + 13, 13, 13, 14, 15, 13, 13, 16, 17, 18, 19, 20, 21, 22, 13, 23, + 13, 13, 13, 24, 25, 11, 11, 11, 11, 26, 11, 27, 28, 29, 30, 31, + 32, 32, 32, 32, 32, 32, 32, 33, 34, 35, 36, 11, 37, 38, 13, 39, + 9, 9, 9, 11, 11, 11, 13, 13, 40, 13, 13, 13, 41, 13, 13, 13, + 13, 13, 13, 35, 9, 42, 11, 11, 43, 44, 32, 45, 46, 47, 47, 48, + 49, 50, 47, 47, 51, 32, 52, 53, 47, 47, 47, 47, 47, 54, 55, 56, + 57, 58, 47, 32, 59, 47, 47, 47, 47, 47, 60, 53, 61, 47, 62, 63, + 47, 64, 65, 66, 47, 67, 47, 47, 47, 47, 47, 47, 47, 68, 69, 32, + 70, 47, 47, 71, 72, 73, 74, 75, 76, 47, 47, 77, 78, 79, 80, 81, + 82, 47, 47, 83, 84, 85, 86, 87, 82, 47, 47, 77, 88, 47, 80, 89, + 90, 47, 47, 91, 92, 93, 80, 94, 95, 47, 47, 96, 97, 98, 99, 100, + 101, 47, 47, 102, 103, 104, 80, 105, 106, 47, 47, 91, 107, 108, 80, 109, + 110, 47, 47, 111, 112, 113, 80, 114, 90, 47, 47, 47, 115, 116, 99, 117, + 47, 47, 47, 118, 119, 120, 66, 66, 47, 47, 47, 121, 122, 123, 47, 47, + 124, 125, 126, 127, 47, 47, 47, 128, 129, 32, 32, 130, 131, 132, 66, 66, + 47, 47, 133, 134, 120, 135, 136, 137, 138, 139, 9, 9, 9, 11, 11, 140, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 141, 142, 143, + 47, 144, 9, 9, 9, 9, 9, 145, 146, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 147, 47, 148, 149, 47, 47, 47, 47, 150, 151, + 47, 152, 47, 153, 47, 152, 47, 152, 47, 47, 47, 154, 155, 156, 157, 143, + 158, 157, 47, 47, 159, 47, 47, 47, 160, 47, 161, 47, 47, 47, 47, 47, + 47, 47, 162, 163, 164, 47, 47, 47, 47, 47, 47, 47, 47, 165, 144, 144, + 47, 166, 47, 47, 47, 167, 168, 169, 157, 157, 170, 171, 32, 32, 32, 32, + 172, 47, 47, 173, 174, 120, 175, 176, 177, 47, 178, 61, 47, 47, 179, 180, + 47, 47, 181, 182, 183, 61, 47, 184, 11, 9, 9, 9, 66, 185, 186, 187, + 11, 11, 188, 27, 27, 27, 189, 190, 11, 191, 27, 27, 32, 32, 32, 32, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 192, 13, 13, 13, 13, 13, 13, + 193, 193, 193, 193, 193, 194, 193, 11, 195, 195, 195, 196, 197, 198, 198, 197, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 27, 208, 208, 208, 209, 210, 32, + 211, 212, 213, 214, 215, 143, 216, 216, 217, 218, 219, 144, 220, 221, 144, 222, + 223, 223, 223, 223, 223, 223, 223, 223, 224, 144, 225, 144, 144, 144, 144, 226, + 144, 227, 223, 228, 144, 229, 230, 144, 144, 144, 144, 144, 144, 144, 143, 143, + 143, 231, 144, 144, 144, 144, 232, 143, 144, 144, 144, 144, 144, 144, 144, 144, + 144, 144, 144, 233, 234, 144, 144, 235, 144, 144, 144, 144, 144, 144, 236, 144, + 144, 144, 144, 144, 144, 144, 237, 238, 143, 239, 144, 144, 240, 223, 241, 223, + 242, 243, 223, 223, 223, 244, 223, 245, 144, 144, 144, 223, 246, 144, 144, 144, + 9, 9, 9, 11, 11, 11, 247, 248, 13, 13, 13, 13, 13, 13, 249, 250, + 11, 11, 11, 47, 47, 47, 251, 252, 47, 47, 47, 47, 47, 47, 32, 32, + 253, 254, 255, 256, 257, 258, 66, 66, 259, 260, 261, 262, 263, 47, 47, 47, + 47, 264, 146, 47, 47, 47, 47, 265, 47, 266, 47, 47, 144, 144, 144, 47, + 144, 144, 267, 144, 268, 269, 144, 144, 267, 144, 144, 269, 144, 144, 144, 144, + 47, 47, 47, 47, 144, 144, 144, 144, 47, 270, 47, 47, 47, 47, 47, 47, + 47, 144, 144, 144, 144, 47, 47, 184, 271, 47, 61, 47, 13, 13, 272, 273, + 13, 274, 47, 47, 47, 47, 275, 276, 31, 277, 278, 279, 13, 13, 13, 280, + 281, 282, 283, 284, 285, 11, 11, 286, 287, 47, 288, 289, 47, 47, 47, 290, + 291, 47, 47, 292, 293, 157, 32, 294, 61, 47, 295, 47, 296, 297, 47, 47, + 70, 47, 47, 298, 299, 300, 301, 61, 47, 47, 302, 303, 304, 305, 47, 306, + 47, 47, 47, 307, 58, 308, 309, 310, 47, 47, 47, 11, 11, 311, 312, 11, + 11, 11, 11, 11, 47, 47, 313, 157, 314, 314, 314, 314, 314, 314, 314, 314, + 315, 315, 315, 315, 315, 315, 315, 315, 11, 316, 317, 47, 47, 47, 47, 47, + 47, 47, 47, 318, 31, 319, 47, 47, 47, 47, 47, 320, 321, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 322, 32, 323, 32, 324, 325, 326, 327, 47, + 47, 47, 47, 47, 47, 47, 47, 328, 329, 2, 3, 4, 5, 330, 331, 332, + 47, 333, 47, 47, 47, 47, 334, 335, 336, 143, 143, 337, 216, 216, 216, 338, + 339, 144, 144, 144, 144, 144, 144, 340, 341, 341, 341, 341, 341, 341, 341, 341, + 47, 47, 47, 47, 47, 47, 342, 143, 47, 47, 343, 47, 344, 47, 47, 60, + 47, 345, 47, 47, 47, 346, 216, 216, 9, 9, 145, 11, 11, 47, 47, 47, + 47, 47, 157, 9, 9, 145, 11, 11, 47, 47, 47, 47, 47, 47, 345, 66, + 47, 47, 47, 47, 47, 347, 47, 348, 47, 47, 349, 143, 143, 143, 47, 350, + 47, 351, 47, 345, 66, 66, 66, 66, 47, 47, 47, 352, 143, 143, 143, 143, + 353, 47, 47, 354, 143, 66, 47, 355, 47, 356, 143, 143, 357, 47, 358, 66, + 47, 47, 47, 359, 47, 360, 47, 360, 47, 359, 142, 143, 143, 143, 143, 143, + 9, 9, 9, 9, 11, 11, 11, 361, 47, 47, 362, 157, 157, 157, 157, 157, + 143, 143, 143, 143, 143, 143, 143, 143, 47, 47, 363, 47, 47, 47, 47, 47, + 47, 356, 364, 47, 60, 365, 66, 66, 47, 47, 47, 47, 366, 143, 47, 47, + 367, 47, 47, 354, 368, 369, 370, 371, 177, 47, 47, 372, 373, 47, 47, 157, + 95, 47, 374, 375, 376, 47, 47, 377, 177, 47, 47, 378, 379, 380, 381, 143, + 47, 47, 382, 383, 32, 32, 32, 32, 47, 47, 359, 47, 47, 384, 169, 157, + 90, 47, 47, 111, 385, 386, 387, 32, 47, 47, 47, 388, 389, 390, 47, 47, + 47, 47, 47, 391, 392, 157, 157, 157, 47, 47, 393, 394, 395, 396, 32, 32, + 47, 47, 47, 397, 398, 157, 66, 66, 47, 47, 399, 400, 157, 157, 157, 157, + 47, 141, 401, 402, 144, 144, 144, 144, 47, 47, 382, 403, 66, 66, 66, 66, + 9, 9, 9, 9, 11, 11, 126, 404, 47, 47, 47, 405, 406, 157, 157, 157, + 47, 47, 47, 47, 47, 407, 408, 409, 410, 47, 47, 411, 412, 413, 47, 47, + 414, 415, 66, 66, 47, 47, 47, 47, 47, 47, 393, 416, 417, 126, 143, 418, + 47, 152, 419, 420, 32, 32, 32, 32, 47, 47, 47, 353, 421, 157, 47, 47, + 422, 423, 157, 157, 157, 157, 157, 157, 47, 47, 47, 47, 47, 47, 47, 424, + 47, 47, 47, 47, 143, 425, 426, 427, 216, 216, 216, 216, 216, 216, 216, 66, + 47, 47, 47, 205, 205, 205, 205, 205, 47, 47, 47, 47, 47, 47, 300, 66, + 47, 47, 47, 47, 47, 47, 47, 428, 47, 47, 47, 429, 430, 431, 432, 47, + 9, 9, 9, 9, 9, 9, 11, 11, 143, 433, 66, 66, 66, 66, 66, 66, + 47, 47, 47, 47, 384, 434, 409, 409, 435, 436, 27, 27, 27, 27, 437, 409, + 47, 438, 205, 205, 205, 205, 205, 205, 144, 144, 144, 144, 144, 144, 439, 440, + 441, 144, 442, 144, 144, 144, 144, 144, 144, 144, 144, 144, 443, 144, 144, 144, + 9, 444, 11, 445, 446, 11, 193, 9, 447, 448, 9, 449, 11, 9, 444, 11, + 445, 446, 11, 193, 9, 447, 448, 9, 449, 11, 9, 444, 11, 445, 446, 11, + 193, 9, 447, 448, 9, 449, 11, 9, 444, 11, 193, 9, 450, 451, 452, 453, + 11, 454, 9, 455, 456, 457, 458, 11, 459, 9, 460, 11, 461, 157, 157, 157, + 32, 32, 32, 462, 32, 32, 463, 464, 465, 466, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 47, 47, 47, 467, 468, 144, 144, 144, + 47, 47, 47, 47, 47, 47, 469, 470, 47, 47, 47, 47, 349, 32, 32, 32, + 9, 9, 447, 11, 471, 300, 66, 66, 143, 143, 472, 473, 143, 143, 143, 143, + 143, 143, 474, 143, 143, 143, 143, 143, 47, 47, 47, 47, 47, 47, 47, 223, + 475, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 144, 476, + 144, 144, 144, 144, 144, 144, 144, 157, 205, 205, 205, 205, 205, 205, 205, 205, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 939, 940, 941, 942, 946, 948, 0, 962, 969, 970, 971, 976,1001,1002,1003,1008, + 0,1033,1040,1041,1042,1043,1047, 0, 0,1080,1081,1082,1086,1110, 0, 0, + 1124,1125,1126,1127,1131,1133, 0,1147,1154,1155,1156,1161,1187,1188,1189,1193, + 0,1219,1226,1227,1228,1229,1233, 0, 0,1267,1268,1269,1273,1298, 0,1303, + 943,1128, 944,1129, 954,1139, 958,1143, 959,1144, 960,1145, 961,1146, 964,1149, + 0, 0, 973,1158, 974,1159, 975,1160, 983,1168, 978,1163, 988,1173, 990,1175, + 991,1176, 993,1178, 994,1179, 0, 0,1004,1190,1005,1191,1006,1192,1014,1199, + 1007, 0, 0, 0,1016,1201,1020,1206, 0,1022,1208,1025,1211,1023,1209, 0, + 0, 0, 0,1032,1218,1037,1223,1035,1221, 0, 0, 0,1044,1230,1045,1231, + 1049,1235, 0, 0,1058,1244,1064,1250,1060,1246,1066,1252,1067,1253,1072,1258, + 1069,1255,1077,1264,1074,1261, 0, 0,1083,1270,1084,1271,1085,1272,1088,1275, + 1089,1276,1096,1283,1103,1290,1111,1299,1115,1118,1307,1120,1309,1121,1310, 0, + 1053,1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1093, + 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 949,1134,1010, + 1195,1050,1236,1090,1277,1341,1368,1340,1367,1342,1369,1339,1366, 0,1320,1347, + 1418,1419,1323,1350, 0, 0, 992,1177,1018,1204,1055,1241,1416,1417,1415,1424, + 1202, 0, 0, 0, 987,1172, 0, 0,1031,1217,1321,1348,1322,1349,1338,1365, + 950,1135, 951,1136, 979,1164, 980,1165,1011,1196,1012,1197,1051,1237,1052,1238, + 1061,1247,1062,1248,1091,1278,1092,1279,1071,1257,1076,1263, 0, 0, 997,1182, + 0, 0, 0, 0, 0, 0, 945,1130, 982,1167,1337,1364,1335,1362,1046,1232, + 1422,1423,1113,1301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 9, 0, 10,1425, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, + 0, 0, 0, 0, 0,1314,1427, 5,1434,1438,1443, 0,1450, 0,1455,1461, + 1514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1446,1458,1468,1476,1480,1486, + 1517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1489,1503,1494,1500,1508, 0, + 0, 0, 0,1520,1521, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1526,1528, 0,1525, 0, 0, 0,1522, 0, 0, 0, 0,1536,1532,1539, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1534, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1556, 0, 0, 0, 0, 0, 0, + 1548,1550, 0,1547, 0, 0, 0,1567, 0, 0, 0, 0,1558,1554,1561, 0, + 0, 0, 0, 0, 0, 0,1568,1569, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1529,1551, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1523,1545,1524,1546, 0, 0,1527,1549, 0, 0,1570,1571,1530,1552,1531,1553, + 0, 0,1533,1555,1535,1557,1537,1559, 0, 0,1572,1573,1544,1566,1538,1560, + 1540,1562,1541,1563,1542,1564, 0, 0,1543,1565, 0, 0, 0, 0, 0, 0, + 0, 0,1606,1607,1609,1608,1610, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1613, 0,1611, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1620, 0, 0, 0, 0, 0, 0, + 0,1623, 0, 0,1624, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1614,1615,1616,1617,1618,1619,1621,1622, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1628,1629, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1625,1626, 0,1627, + 0, 0, 0,1634, 0, 0,1635, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1630,1631,1632, 0, 0,1633, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1639, 0, 0,1638,1640, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1636,1637, 0, 0, + 0, 0, 0, 0,1641, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1642,1644,1643, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1645, 0, 0, 0, 0, 0, 0, 0, + 1646, 0, 0, 0, 0, 0, 0,1648,1649, 0,1647,1650, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1651,1653,1652, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1654, 0,1655,1657,1656, 0, + 0, 0, 0,1659, 0, 0, 0, 0, 0, 0, 0, 0, 0,1660, 0, 0, + 0, 0,1661, 0, 0, 0, 0,1662, 0, 0, 0, 0,1663, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1658, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1664, 0,1665,1673, 0,1674, 0, 0, 0, 0, 0, 0, 0, + 0,1666, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0,1668, 0, 0, 0, 0, 0, 0, 0, 0, 0,1669, 0, 0, + 0, 0,1670, 0, 0, 0, 0,1671, 0, 0, 0, 0,1672, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0,1667, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1675, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,1676, 0,1677, 0,1678, 0,1679, 0,1680, 0, + 0, 0,1681, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1682, 0,1683, 0, 0, + 1684,1685, 0,1686, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 953,1138, 955,1140, 956,1141, 957,1142,1324,1351, 963,1148, 965,1150, 968,1153, + 966,1151, 967,1152,1378,1380,1379,1381, 984,1169, 985,1170,1420,1421, 986,1171, + 989,1174, 995,1180, 998,1183, 996,1181, 999,1184,1000,1185,1015,1200,1329,1356, + 1017,1203,1019,1205,1021,1207,1024,1210,1687,1688,1027,1213,1026,1212,1028,1214, + 1029,1215,1030,1216,1034,1220,1036,1222,1039,1225,1038,1224,1334,1361,1336,1363, + 1382,1384,1383,1385,1056,1242,1057,1243,1059,1245,1063,1249,1689,1690,1065,1251, + 1068,1254,1070,1256,1386,1387,1388,1389,1691,1692,1073,1259,1075,1262,1079,1266, + 1078,1265,1095,1282,1098,1285,1097,1284,1390,1391,1392,1393,1099,1286,1100,1287, + 1101,1288,1102,1289,1105,1292,1104,1291,1106,1294,1107,1295,1108,1296,1114,1302, + 1119,1308,1122,1311,1123,1312,1186,1260,1293,1305, 0,1394, 0, 0, 0, 0, + 952,1137, 947,1132,1317,1344,1316,1343,1319,1346,1318,1345,1693,1695,1371,1375, + 1370,1374,1373,1377,1372,1376,1694,1696, 981,1166, 977,1162, 972,1157,1326,1353, + 1325,1352,1328,1355,1327,1354,1697,1698,1009,1194,1013,1198,1054,1240,1048,1234, + 1331,1358,1330,1357,1333,1360,1332,1359,1699,1700,1396,1401,1395,1400,1398,1403, + 1397,1402,1399,1404,1094,1281,1087,1274,1406,1411,1405,1410,1408,1413,1407,1412, + 1409,1414,1109,1297,1117,1306,1116,1304,1112,1300, 0, 0, 0, 0, 0, 0, + 1471,1472,1701,1705,1702,1706,1703,1707,1430,1431,1715,1719,1716,1720,1717,1721, + 1477,1478,1729,1731,1730,1732, 0, 0,1435,1436,1733,1735,1734,1736, 0, 0, + 1481,1482,1737,1741,1738,1742,1739,1743,1439,1440,1751,1755,1752,1756,1753,1757, + 1490,1491,1765,1768,1766,1769,1767,1770,1447,1448,1771,1774,1772,1775,1773,1776, + 1495,1496,1777,1779,1778,1780, 0, 0,1451,1452,1781,1783,1782,1784, 0, 0, + 1504,1505,1785,1788,1786,1789,1787,1790, 0,1459, 0,1791, 0,1792, 0,1793, + 1509,1510,1794,1798,1795,1799,1796,1800,1462,1463,1808,1812,1809,1813,1810,1814, + 1467, 21,1475, 22,1479, 23,1485, 24,1493, 27,1499, 28,1507, 29, 0, 0, + 1704,1708,1709,1710,1711,1712,1713,1714,1718,1722,1723,1724,1725,1726,1727,1728, + 1740,1744,1745,1746,1747,1748,1749,1750,1754,1758,1759,1760,1761,1762,1763,1764, + 1797,1801,1802,1803,1804,1805,1806,1807,1811,1815,1816,1817,1818,1819,1820,1821, + 1470,1469,1822,1474,1465, 0,1473,1825,1429,1428,1426, 12,1432, 0, 26, 0, + 0,1315,1823,1484,1466, 0,1483,1829,1433, 13,1437, 14,1441,1826,1827,1828, + 1488,1487,1513, 19, 0, 0,1492,1515,1445,1444,1442, 15, 0,1831,1832,1833, + 1502,1501,1516, 25,1497,1498,1506,1518,1457,1456,1454, 17,1453,1313, 11, 3, + 0, 0,1824,1512,1519, 0,1511,1830,1449, 16,1460, 18,1464, 4, 0, 0, + 30, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 2, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1834,1835, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1836, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1837,1839,1838, + 0, 0, 0, 0,1840, 0, 0, 0, 0,1841, 0, 0,1842, 0, 0, 0, + 0, 0, 0, 0,1843, 0,1844, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,1845, 0, 0,1846, 0, 0,1847, 0,1848, 0, 0, 0, 0, 0, 0, + 937, 0,1850, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1849, 936, 938, + 1851,1852, 0, 0,1853,1854, 0, 0,1855,1856, 0, 0, 0, 0, 0, 0, + 1857,1858, 0, 0,1861,1862, 0, 0,1863,1864, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1867,1868,1869,1870, + 1859,1860,1865,1866, 0, 0, 0, 0, 0, 0,1871,1872,1873,1874, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 33, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1875, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1877, 0,1878, 0, + 1879, 0,1880, 0,1881, 0,1882, 0,1883, 0,1884, 0,1885, 0,1886, 0, + 1887, 0,1888, 0, 0,1889, 0,1890, 0,1891, 0, 0, 0, 0, 0, 0, + 1892,1893, 0,1894,1895, 0,1896,1897, 0,1898,1899, 0,1900,1901, 0, 0, + 0, 0, 0, 0,1876, 0, 0, 0, 0, 0, 0, 0, 0, 0,1902, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1904, 0,1905, 0, + 1906, 0,1907, 0,1908, 0,1909, 0,1910, 0,1911, 0,1912, 0,1913, 0, + 1914, 0,1915, 0, 0,1916, 0,1917, 0,1918, 0, 0, 0, 0, 0, 0, + 1919,1920, 0,1921,1922, 0,1923,1924, 0,1925,1926, 0,1927,1928, 0, 0, + 0, 0, 0, 0,1903, 0, 0,1929,1930,1931,1932, 0, 0, 0,1933, 0, + 710, 385, 724, 715, 455, 103, 186, 825, 825, 242, 751, 205, 241, 336, 524, 601, + 663, 676, 688, 738, 411, 434, 474, 500, 649, 746, 799, 108, 180, 416, 482, 662, + 810, 275, 462, 658, 692, 344, 618, 679, 293, 388, 440, 492, 740, 116, 146, 168, + 368, 414, 481, 527, 606, 660, 665, 722, 781, 803, 809, 538, 553, 588, 642, 758, + 811, 701, 233, 299, 573, 612, 487, 540, 714, 779, 232, 267, 412, 445, 457, 585, + 594, 766, 167, 613, 149, 148, 560, 589, 648, 768, 708, 345, 411, 704, 105, 259, + 313, 496, 518, 174, 542, 120, 307, 101, 430, 372, 584, 183, 228, 529, 650, 697, + 424, 732, 428, 349, 632, 355, 517, 110, 135, 147, 403, 580, 624, 700, 750, 170, + 193, 245, 297, 374, 463, 543, 763, 801, 812, 815, 162, 384, 420, 730, 287, 330, + 337, 366, 459, 476, 509, 558, 591, 610, 726, 652, 734, 759, 154, 163, 198, 473, + 683, 697, 292, 311, 353, 423, 572, 494, 113, 217, 259, 280, 314, 499, 506, 603, + 608, 752, 778, 782, 788, 117, 557, 748, 774, 320, 109, 126, 260, 265, 373, 411, + 479, 523, 655, 737, 823, 380, 765, 161, 395, 398, 438, 451, 502, 516, 537, 583, + 791, 136, 340, 769, 122, 273, 446, 727, 305, 322, 400, 496, 771, 155, 190, 269, + 377, 391, 406, 432, 501, 519, 599, 684, 687, 749, 776, 175, 452, 191, 480, 510, + 659, 772, 805, 813, 397, 444, 619, 566, 568, 575, 491, 471, 707, 111, 636, 156, + 153, 288, 346, 578, 256, 435, 383, 729, 680, 767, 694, 295, 128, 210, 0, 0, + 227, 0, 379, 0, 0, 150, 493, 525, 544, 551, 552, 556, 783, 576, 604, 0, + 661, 0, 703, 0, 0, 735, 743, 0, 0, 0, 793, 794, 795, 808, 741, 773, + 118, 127, 130, 166, 169, 177, 207, 213, 215, 226, 229, 268, 270, 317, 327, 329, + 335, 369, 375, 381, 404, 441, 448, 458, 477, 484, 503, 539, 545, 547, 546, 548, + 549, 550, 554, 555, 561, 564, 569, 591, 593, 595, 598, 607, 620, 625, 625, 651, + 690, 695, 705, 706, 716, 717, 733, 735, 777, 786, 790, 315, 869, 623, 0, 0, + 102, 145, 134, 115, 129, 138, 165, 171, 207, 202, 206, 212, 227, 231, 240, 243, + 250, 254, 294, 296, 303, 308, 319, 325, 321, 329, 326, 335, 341, 357, 360, 362, + 370, 379, 388, 389, 393, 421, 424, 438, 456, 454, 458, 465, 477, 535, 485, 490, + 493, 507, 512, 514, 521, 522, 525, 526, 528, 533, 532, 541, 565, 569, 574, 586, + 591, 597, 607, 637, 647, 674, 691, 693, 695, 698, 703, 699, 705, 704, 702, 706, + 709, 717, 728, 736, 747, 754, 770, 777, 783, 784, 786, 787, 790, 802, 825, 848, + 847, 857, 55, 65, 66, 883, 892, 916, 822, 824, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1586, 0,1605, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1602,1603,1934,1935,1574,1575, + 1576,1577,1579,1580,1581,1583,1584, 0,1585,1587,1588,1589,1591, 0,1592, 0, + 1593,1594, 0,1595,1596, 0,1598,1599,1600,1601,1604,1582,1578,1590,1597, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1936, 0,1937, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1938, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1939,1940, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1941,1942, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1944,1943, 0,1945, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1946,1947, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,1948, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1949,1950, + 1951,1952,1953,1954,1955, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,1956,1957,1958,1960,1959, + 1961, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 106, 104, 107, 826, 114, 118, 119, 121, 123, 124, 127, 125, 34, 830, 130, 131, + 132, 137, 827, 35, 133, 139, 829, 142, 143, 112, 144, 145, 924, 151, 152, 37, + 157, 158, 159, 160, 38, 165, 166, 169, 171, 172, 173, 174, 176, 177, 178, 179, + 181, 182, 182, 182, 833, 468, 184, 185, 834, 187, 188, 189, 196, 192, 194, 195, + 197, 199, 200, 201, 203, 204, 204, 206, 208, 209, 211, 218, 213, 219, 214, 216, + 153, 234, 221, 222, 223, 220, 225, 224, 230, 835, 235, 236, 237, 238, 239, 244, + 836, 837, 247, 248, 249, 246, 251, 39, 40, 253, 255, 255, 838, 257, 258, 259, + 261, 839, 262, 263, 301, 264, 41, 266, 270, 272, 271, 841, 274, 842, 277, 276, + 278, 281, 282, 42, 283, 284, 285, 286, 43, 843, 44, 289, 290, 291, 293, 934, + 298, 845, 845, 621, 300, 300, 45, 852, 894, 302, 304, 46, 306, 309, 310, 312, + 316, 48, 47, 317, 846, 318, 323, 324, 325, 324, 328, 329, 333, 331, 332, 334, + 335, 336, 338, 339, 342, 343, 347, 351, 849, 350, 348, 352, 354, 359, 850, 361, + 358, 356, 49, 363, 365, 367, 364, 50, 369, 371, 851, 376, 386, 378, 53, 381, + 52, 51, 140, 141, 387, 382, 614, 78, 388, 389, 390, 394, 392, 856, 54, 399, + 396, 402, 404, 858, 405, 401, 407, 55, 408, 409, 410, 413, 859, 415, 56, 417, + 860, 418, 57, 419, 422, 424, 425, 861, 840, 862, 426, 863, 429, 431, 427, 433, + 437, 441, 438, 439, 442, 443, 864, 436, 449, 450, 58, 454, 453, 865, 447, 460, + 866, 867, 461, 466, 465, 464, 59, 467, 470, 469, 472, 828, 475, 868, 478, 870, + 483, 485, 486, 871, 488, 489, 872, 873, 495, 497, 60, 498, 61, 61, 504, 505, + 507, 508, 511, 62, 513, 874, 515, 875, 518, 844, 520, 876, 877, 878, 63, 64, + 528, 880, 879, 881, 882, 530, 531, 531, 533, 66, 534, 67, 68, 884, 536, 538, + 541, 69, 885, 549, 886, 887, 556, 559, 70, 561, 562, 563, 888, 889, 889, 567, + 71, 890, 570, 571, 72, 891, 577, 73, 581, 579, 582, 893, 587, 74, 590, 592, + 596, 75, 895, 896, 76, 897, 600, 898, 602, 605, 607, 899, 900, 609, 901, 611, + 853, 77, 615, 616, 79, 617, 252, 902, 903, 854, 855, 621, 622, 731, 80, 627, + 626, 628, 164, 629, 630, 631, 633, 904, 632, 634, 639, 640, 635, 641, 646, 651, + 638, 643, 644, 645, 905, 907, 906, 81, 653, 654, 656, 911, 657, 908, 82, 83, + 909, 910, 84, 664, 665, 666, 667, 669, 668, 671, 670, 674, 672, 673, 675, 85, + 677, 678, 86, 681, 682, 912, 685, 686, 87, 689, 36, 913, 914, 88, 89, 696, + 702, 709, 711, 915, 712, 713, 718, 719, 917, 831, 721, 720, 723, 832, 725, 728, + 918, 919, 739, 742, 744, 920, 745, 753, 756, 757, 755, 760, 761, 921, 762, 90, + 764, 922, 91, 775, 279, 780, 923, 925, 92, 93, 785, 926, 94, 927, 787, 787, + 789, 928, 792, 95, 796, 797, 798, 800, 96, 929, 802, 804, 806, 97, 98, 807, + 930, 99, 931, 932, 933, 814, 100, 816, 817, 818, 819, 820, 821, 935, 0, 0, +}; +static const int16_t +_hb_ucd_i16[92] = +{ + 0, 0, 1, -1, 2, 0, -2, 0, 0, 2, 0, -2, 0, 16, 0, -16, + 0, 1, -1, 0, 3, 3, 3, -3, -3, -3, 0, 2016, 0, 2527, 1923, 1914, + 1918, 0, 2250, 0, 0, 138, 0, 7, -7, 0, -1, 1, 1824, 0, 2104, 0, + 2108, 2106, 0, 2106, 1316, 0, -1, -138, 8, 8, 8, 0, 7, 7, -8, -8, + -8, -7,-1316, 1, -1, 3, -3, 1, 0,-1914,-1918, 0, 0,-1923,-1824, 0, + 0,-2016,-2104, 0, 0,-2106,-2108,-2106,-2250, 0,-2527, 0, +}; + +static inline uint_fast8_t +_hb_ucd_gc (unsigned u) +{ + return u<1114112u?_hb_ucd_u8[4920+(((_hb_ucd_u8[1104+(((_hb_ucd_u16[((_hb_ucd_u8[272+(((_hb_ucd_u8[u>>1>>3>>3>>5])<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:2; +} +static inline uint_fast8_t +_hb_ucd_ccc (unsigned u) +{ + return u<125259u?_hb_ucd_u8[6796+(((_hb_ucd_u8[6276+(((_hb_ucd_u8[5844+(((_hb_ucd_u8[5508+(((_hb_ucd_u8[5262+(u>>2>>2>>2>>3)])<<3)+((u>>2>>2>>2)&7u))])<<2)+((u>>2>>2)&3u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:0; +} +static inline unsigned +_hb_ucd_b4 (const uint8_t* a, unsigned i) +{ + return (a[i>>1]>>((i&1u)<<2))&15u; +} +static inline int_fast16_t +_hb_ucd_bmg (unsigned u) +{ + return u<65380u?_hb_ucd_i16[((_hb_ucd_u8[7672+(((_hb_ucd_u8[7448+(((_hb_ucd_u8[7352+(((_hb_ucd_b4(7288+_hb_ucd_u8,u>>1>>2>>3>>3))<<3)+((u>>1>>2>>3)&7u))])<<3)+((u>>1>>2)&7u))])<<2)+((u>>1)&3u))])<<1)+((u)&1u)]:0; +} +static inline uint_fast8_t +_hb_ucd_sc (unsigned u) +{ + return u<918016u?_hb_ucd_u8[11242+(((_hb_ucd_u8[10314+(((_hb_ucd_u8[8938+(((_hb_ucd_u8[8362+(((_hb_ucd_u8[7912+(u>>2>>2>>3>>4)])<<4)+((u>>2>>2>>3)&15u))])<<3)+((u>>2>>2)&7u))])<<2)+((u>>2)&3u))])<<2)+((u)&3u))]:2; +} +static inline uint_fast16_t +_hb_ucd_dm (unsigned u) +{ + return u<195102u?_hb_ucd_u16[1536+(((_hb_ucd_u8[12544+(((_hb_ucd_u8[12162+(u>>4>>5)])<<5)+((u>>4)&31u))])<<4)+((u)&15u))]:0; +} + +#endif + + +#endif /* HB_UCD_TABLE_HH */ + +/* == End of generated table == */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucd.cc b/src/java.desktop/share/native/libharfbuzz/hb-ucd.cc new file mode 100644 index 00000000000..f56f05f1707 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-ucd.cc @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2012 Grigori Goronzy + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "hb.hh" +#include "hb-unicode.hh" +#include "hb-machinery.hh" + +#include "hb-ucd-table.hh" + +static hb_unicode_combining_class_t +hb_ucd_combining_class (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + return (hb_unicode_combining_class_t) _hb_ucd_ccc (unicode); +} + +static hb_unicode_general_category_t +hb_ucd_general_category (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + return (hb_unicode_general_category_t) _hb_ucd_gc (unicode); +} + +static hb_codepoint_t +hb_ucd_mirroring (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + return unicode + _hb_ucd_bmg (unicode); +} + +static hb_script_t +hb_ucd_script (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t unicode, + void *user_data HB_UNUSED) +{ + return _hb_ucd_sc_map[_hb_ucd_sc (unicode)]; +} + + +#define SBASE 0xAC00u +#define LBASE 0x1100u +#define VBASE 0x1161u +#define TBASE 0x11A7u +#define SCOUNT 11172u +#define LCOUNT 19u +#define VCOUNT 21u +#define TCOUNT 28u +#define NCOUNT (VCOUNT * TCOUNT) + +static inline bool +_hb_ucd_decompose_hangul (hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b) +{ + unsigned si = ab - SBASE; + + if (si >= SCOUNT) + return false; + + if (si % TCOUNT) + { + /* LV,T */ + *a = SBASE + (si / TCOUNT) * TCOUNT; + *b = TBASE + (si % TCOUNT); + return true; + } else { + /* L,V */ + *a = LBASE + (si / NCOUNT); + *b = VBASE + (si % NCOUNT) / TCOUNT; + return true; + } +} + +static inline bool +_hb_ucd_compose_hangul (hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab) +{ + if (a >= SBASE && a < (SBASE + SCOUNT) && b > TBASE && b < (TBASE + TCOUNT) && + !((a - SBASE) % TCOUNT)) + { + /* LV,T */ + *ab = a + (b - TBASE); + return true; + } + else if (a >= LBASE && a < (LBASE + LCOUNT) && b >= VBASE && b < (VBASE + VCOUNT)) + { + /* L,V */ + int li = a - LBASE; + int vi = b - VBASE; + *ab = SBASE + li * NCOUNT + vi * TCOUNT; + return true; + } + else + return false; +} + +static int +_cmp_pair (const void *_key, const void *_item) +{ + uint64_t& a = * (uint64_t*) _key; + uint64_t b = (* (uint64_t*) _item) & HB_CODEPOINT_ENCODE3(0x1FFFFFu, 0x1FFFFFu, 0); + + return a < b ? -1 : a > b ? +1 : 0; +} +static int +_cmp_pair_11_7_14 (const void *_key, const void *_item) +{ + uint32_t& a = * (uint32_t*) _key; + uint32_t b = (* (uint32_t*) _item) & HB_CODEPOINT_ENCODE3_11_7_14(0x1FFFFFu, 0x1FFFFFu, 0); + + return a < b ? -1 : a > b ? +1 : 0; +} + +static hb_bool_t +hb_ucd_compose (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab, + void *user_data HB_UNUSED) +{ + if (_hb_ucd_compose_hangul (a, b, ab)) return true; + + hb_codepoint_t u = 0; + + if ((a & 0xFFFFF800u) == 0x0000u && (b & 0xFFFFFF80) == 0x0300u) + { + uint32_t k = HB_CODEPOINT_ENCODE3_11_7_14 (a, b, 0); + const uint32_t *v = hb_bsearch (k, + _hb_ucd_dm2_u32_map, + ARRAY_LENGTH (_hb_ucd_dm2_u32_map), + sizeof (*_hb_ucd_dm2_u32_map), + _cmp_pair_11_7_14); + if (likely (!v)) return false; + u = HB_CODEPOINT_DECODE3_11_7_14_3 (*v); + } + else + { + uint64_t k = HB_CODEPOINT_ENCODE3 (a, b, 0); + const uint64_t *v = hb_bsearch (k, + _hb_ucd_dm2_u64_map, + ARRAY_LENGTH (_hb_ucd_dm2_u64_map), + sizeof (*_hb_ucd_dm2_u64_map), + _cmp_pair); + if (likely (!v)) return false; + u = HB_CODEPOINT_DECODE3_3 (*v); + } + + if (unlikely (!u)) return false; + *ab = u; + return true; +} + +static hb_bool_t +hb_ucd_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED, + hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b, + void *user_data HB_UNUSED) +{ + if (_hb_ucd_decompose_hangul (ab, a, b)) return true; + + unsigned i = _hb_ucd_dm (ab); + + if (likely (!i)) return false; + i--; + + if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map)) + { + if (i < ARRAY_LENGTH (_hb_ucd_dm1_p0_map)) + *a = _hb_ucd_dm1_p0_map[i]; + else + { + i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map); + *a = 0x20000 | _hb_ucd_dm1_p2_map[i]; + } + *b = 0; + return true; + } + i -= ARRAY_LENGTH (_hb_ucd_dm1_p0_map) + ARRAY_LENGTH (_hb_ucd_dm1_p2_map); + + if (i < ARRAY_LENGTH (_hb_ucd_dm2_u32_map)) + { + uint32_t v = _hb_ucd_dm2_u32_map[i]; + *a = HB_CODEPOINT_DECODE3_11_7_14_1 (v); + *b = HB_CODEPOINT_DECODE3_11_7_14_2 (v); + return true; + } + i -= ARRAY_LENGTH (_hb_ucd_dm2_u32_map); + + uint64_t v = _hb_ucd_dm2_u64_map[i]; + *a = HB_CODEPOINT_DECODE3_1 (v); + *b = HB_CODEPOINT_DECODE3_2 (v); + return true; +} + + +#if HB_USE_ATEXIT +static void free_static_ucd_funcs (); +#endif + +static struct hb_ucd_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t +{ + static hb_unicode_funcs_t *create () + { + hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr); + + hb_unicode_funcs_set_combining_class_func (funcs, hb_ucd_combining_class, nullptr, nullptr); + hb_unicode_funcs_set_general_category_func (funcs, hb_ucd_general_category, nullptr, nullptr); + hb_unicode_funcs_set_mirroring_func (funcs, hb_ucd_mirroring, nullptr, nullptr); + hb_unicode_funcs_set_script_func (funcs, hb_ucd_script, nullptr, nullptr); + hb_unicode_funcs_set_compose_func (funcs, hb_ucd_compose, nullptr, nullptr); + hb_unicode_funcs_set_decompose_func (funcs, hb_ucd_decompose, nullptr, nullptr); + + hb_unicode_funcs_make_immutable (funcs); + +#if HB_USE_ATEXIT + atexit (free_static_ucd_funcs); +#endif + + return funcs; + } +} static_ucd_funcs; + +#if HB_USE_ATEXIT +static +void free_static_ucd_funcs () +{ + static_ucd_funcs.free_instance (); +} +#endif + +hb_unicode_funcs_t * +hb_ucd_get_unicode_funcs () +{ +#ifdef HB_NO_UCD + return hb_unicode_funcs_get_empty (); +#endif + return static_ucd_funcs.get_unconst (); +} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucdn.cc b/src/java.desktop/share/native/libharfbuzz/hb-ucdn.cc deleted file mode 100644 index d80f6e97b8d..00000000000 --- a/src/java.desktop/share/native/libharfbuzz/hb-ucdn.cc +++ /dev/null @@ -1,268 +0,0 @@ -/* - * Copyright (C) 2012 Grigori Goronzy - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include "hb.hh" - -#include "hb-machinery.hh" - -#include "ucdn.h" - -static const hb_script_t ucdn_script_translate[] = -{ - HB_SCRIPT_COMMON, - HB_SCRIPT_LATIN, - HB_SCRIPT_GREEK, - HB_SCRIPT_CYRILLIC, - HB_SCRIPT_ARMENIAN, - HB_SCRIPT_HEBREW, - HB_SCRIPT_ARABIC, - HB_SCRIPT_SYRIAC, - HB_SCRIPT_THAANA, - HB_SCRIPT_DEVANAGARI, - HB_SCRIPT_BENGALI, - HB_SCRIPT_GURMUKHI, - HB_SCRIPT_GUJARATI, - HB_SCRIPT_ORIYA, - HB_SCRIPT_TAMIL, - HB_SCRIPT_TELUGU, - HB_SCRIPT_KANNADA, - HB_SCRIPT_MALAYALAM, - HB_SCRIPT_SINHALA, - HB_SCRIPT_THAI, - HB_SCRIPT_LAO, - HB_SCRIPT_TIBETAN, - HB_SCRIPT_MYANMAR, - HB_SCRIPT_GEORGIAN, - HB_SCRIPT_HANGUL, - HB_SCRIPT_ETHIOPIC, - HB_SCRIPT_CHEROKEE, - HB_SCRIPT_CANADIAN_SYLLABICS, - HB_SCRIPT_OGHAM, - HB_SCRIPT_RUNIC, - HB_SCRIPT_KHMER, - HB_SCRIPT_MONGOLIAN, - HB_SCRIPT_HIRAGANA, - HB_SCRIPT_KATAKANA, - HB_SCRIPT_BOPOMOFO, - HB_SCRIPT_HAN, - HB_SCRIPT_YI, - HB_SCRIPT_OLD_ITALIC, - HB_SCRIPT_GOTHIC, - HB_SCRIPT_DESERET, - HB_SCRIPT_INHERITED, - HB_SCRIPT_TAGALOG, - HB_SCRIPT_HANUNOO, - HB_SCRIPT_BUHID, - HB_SCRIPT_TAGBANWA, - HB_SCRIPT_LIMBU, - HB_SCRIPT_TAI_LE, - HB_SCRIPT_LINEAR_B, - HB_SCRIPT_UGARITIC, - HB_SCRIPT_SHAVIAN, - HB_SCRIPT_OSMANYA, - HB_SCRIPT_CYPRIOT, - HB_SCRIPT_BRAILLE, - HB_SCRIPT_BUGINESE, - HB_SCRIPT_COPTIC, - HB_SCRIPT_NEW_TAI_LUE, - HB_SCRIPT_GLAGOLITIC, - HB_SCRIPT_TIFINAGH, - HB_SCRIPT_SYLOTI_NAGRI, - HB_SCRIPT_OLD_PERSIAN, - HB_SCRIPT_KHAROSHTHI, - HB_SCRIPT_BALINESE, - HB_SCRIPT_CUNEIFORM, - HB_SCRIPT_PHOENICIAN, - HB_SCRIPT_PHAGS_PA, - HB_SCRIPT_NKO, - HB_SCRIPT_SUNDANESE, - HB_SCRIPT_LEPCHA, - HB_SCRIPT_OL_CHIKI, - HB_SCRIPT_VAI, - HB_SCRIPT_SAURASHTRA, - HB_SCRIPT_KAYAH_LI, - HB_SCRIPT_REJANG, - HB_SCRIPT_LYCIAN, - HB_SCRIPT_CARIAN, - HB_SCRIPT_LYDIAN, - HB_SCRIPT_CHAM, - HB_SCRIPT_TAI_THAM, - HB_SCRIPT_TAI_VIET, - HB_SCRIPT_AVESTAN, - HB_SCRIPT_EGYPTIAN_HIEROGLYPHS, - HB_SCRIPT_SAMARITAN, - HB_SCRIPT_LISU, - HB_SCRIPT_BAMUM, - HB_SCRIPT_JAVANESE, - HB_SCRIPT_MEETEI_MAYEK, - HB_SCRIPT_IMPERIAL_ARAMAIC, - HB_SCRIPT_OLD_SOUTH_ARABIAN, - HB_SCRIPT_INSCRIPTIONAL_PARTHIAN, - HB_SCRIPT_INSCRIPTIONAL_PAHLAVI, - HB_SCRIPT_OLD_TURKIC, - HB_SCRIPT_KAITHI, - HB_SCRIPT_BATAK, - HB_SCRIPT_BRAHMI, - HB_SCRIPT_MANDAIC, - HB_SCRIPT_CHAKMA, - HB_SCRIPT_MEROITIC_CURSIVE, - HB_SCRIPT_MEROITIC_HIEROGLYPHS, - HB_SCRIPT_MIAO, - HB_SCRIPT_SHARADA, - HB_SCRIPT_SORA_SOMPENG, - HB_SCRIPT_TAKRI, - HB_SCRIPT_UNKNOWN, - HB_SCRIPT_BASSA_VAH, - HB_SCRIPT_CAUCASIAN_ALBANIAN, - HB_SCRIPT_DUPLOYAN, - HB_SCRIPT_ELBASAN, - HB_SCRIPT_GRANTHA, - HB_SCRIPT_KHOJKI, - HB_SCRIPT_KHUDAWADI, - HB_SCRIPT_LINEAR_A, - HB_SCRIPT_MAHAJANI, - HB_SCRIPT_MANICHAEAN, - HB_SCRIPT_MENDE_KIKAKUI, - HB_SCRIPT_MODI, - HB_SCRIPT_MRO, - HB_SCRIPT_NABATAEAN, - HB_SCRIPT_OLD_NORTH_ARABIAN, - HB_SCRIPT_OLD_PERMIC, - HB_SCRIPT_PAHAWH_HMONG, - HB_SCRIPT_PALMYRENE, - HB_SCRIPT_PAU_CIN_HAU, - HB_SCRIPT_PSALTER_PAHLAVI, - HB_SCRIPT_SIDDHAM, - HB_SCRIPT_TIRHUTA, - HB_SCRIPT_WARANG_CITI, - HB_SCRIPT_AHOM, - HB_SCRIPT_ANATOLIAN_HIEROGLYPHS, - HB_SCRIPT_HATRAN, - HB_SCRIPT_MULTANI, - HB_SCRIPT_OLD_HUNGARIAN, - HB_SCRIPT_SIGNWRITING, - HB_SCRIPT_ADLAM, - HB_SCRIPT_BHAIKSUKI, - HB_SCRIPT_MARCHEN, - HB_SCRIPT_NEWA, - HB_SCRIPT_OSAGE, - HB_SCRIPT_TANGUT, - HB_SCRIPT_MASARAM_GONDI, - HB_SCRIPT_NUSHU, - HB_SCRIPT_SOYOMBO, - HB_SCRIPT_ZANABAZAR_SQUARE, - HB_SCRIPT_DOGRA, - HB_SCRIPT_GUNJALA_GONDI, - HB_SCRIPT_HANIFI_ROHINGYA, - HB_SCRIPT_MAKASAR, - HB_SCRIPT_MEDEFAIDRIN, - HB_SCRIPT_OLD_SOGDIAN, - HB_SCRIPT_SOGDIAN, -}; - -static hb_unicode_combining_class_t -hb_ucdn_combining_class(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - return (hb_unicode_combining_class_t) ucdn_get_combining_class(unicode); -} - -static hb_unicode_general_category_t -hb_ucdn_general_category(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - return (hb_unicode_general_category_t)ucdn_get_general_category(unicode); -} - -static hb_codepoint_t -hb_ucdn_mirroring(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - return ucdn_mirror(unicode); -} - -static hb_script_t -hb_ucdn_script(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t unicode, - void *user_data HB_UNUSED) -{ - return ucdn_script_translate[ucdn_get_script(unicode)]; -} - -static hb_bool_t -hb_ucdn_compose(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t a, hb_codepoint_t b, hb_codepoint_t *ab, - void *user_data HB_UNUSED) -{ - return ucdn_compose(ab, a, b); -} - -static hb_bool_t -hb_ucdn_decompose(hb_unicode_funcs_t *ufuncs HB_UNUSED, - hb_codepoint_t ab, hb_codepoint_t *a, hb_codepoint_t *b, - void *user_data HB_UNUSED) -{ - return ucdn_decompose(ab, a, b); -} - - -#if HB_USE_ATEXIT -static void free_static_ucdn_funcs (); -#endif - -static struct hb_ucdn_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t -{ - static hb_unicode_funcs_t *create () - { - hb_unicode_funcs_t *funcs = hb_unicode_funcs_create (nullptr); - - hb_unicode_funcs_set_combining_class_func (funcs, hb_ucdn_combining_class, nullptr, nullptr); - hb_unicode_funcs_set_general_category_func (funcs, hb_ucdn_general_category, nullptr, nullptr); - hb_unicode_funcs_set_mirroring_func (funcs, hb_ucdn_mirroring, nullptr, nullptr); - hb_unicode_funcs_set_script_func (funcs, hb_ucdn_script, nullptr, nullptr); - hb_unicode_funcs_set_compose_func (funcs, hb_ucdn_compose, nullptr, nullptr); - hb_unicode_funcs_set_decompose_func (funcs, hb_ucdn_decompose, nullptr, nullptr); - - hb_unicode_funcs_make_immutable (funcs); - -#if HB_USE_ATEXIT - atexit (free_static_ucdn_funcs); -#endif - - return funcs; - } -} static_ucdn_funcs; - -#if HB_USE_ATEXIT -static -void free_static_ucdn_funcs () -{ - static_ucdn_funcs.free_instance (); -} -#endif - -extern "C" HB_INTERNAL -hb_unicode_funcs_t * -hb_ucdn_get_unicode_funcs (); - -hb_unicode_funcs_t * -hb_ucdn_get_unicode_funcs () -{ - return static_ucdn_funcs.get_unconst (); -} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.c b/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.c deleted file mode 100644 index 30747fea251..00000000000 --- a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * Copyright (C) 2012 Grigori Goronzy - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include "ucdn.h" - -typedef struct { - unsigned char category; - unsigned char combining; - unsigned char bidi_class; - unsigned char east_asian_width; - unsigned char script; - unsigned char linebreak_class; -} UCDRecord; - -typedef struct { - unsigned short from, to; -} MirrorPair; - -typedef struct { - unsigned short from, to; - unsigned char type; -} BracketPair; - -typedef struct { - unsigned int start; - short count, index; -} Reindex; - -#include "ucdn_db.h" - -/* constants required for Hangul (de)composition */ -#define SBASE 0xAC00 -#define LBASE 0x1100 -#define VBASE 0x1161 -#define TBASE 0x11A7 -#define SCOUNT 11172 -#define LCOUNT 19 -#define VCOUNT 21 -#define TCOUNT 28 -#define NCOUNT (VCOUNT * TCOUNT) - -static const UCDRecord *get_ucd_record(uint32_t code) -{ - int index, offset; - - if (code >= 0x110000) - index = 0; - else { - index = index0[code >> (SHIFT1+SHIFT2)] << SHIFT1; - offset = (code >> SHIFT2) & ((1<= 0x110000) - index = 0; - else { - index = decomp_index0[code >> (DECOMP_SHIFT1+DECOMP_SHIFT2)] - << DECOMP_SHIFT1; - offset = (code >> DECOMP_SHIFT2) & ((1<start < rb->start) - return -1; - else if (ra->start > (rb->start + rb->count)) - return 1; - else - return 0; -} - -static int get_comp_index(uint32_t code, const Reindex *idx, size_t len) -{ - Reindex *res; - Reindex r = {0, 0, 0}; - r.start = code; - res = (Reindex *) bsearch(&r, idx, len, sizeof(Reindex), compare_reindex); - - if (res != NULL) - return res->index + (code - res->start); - else - return -1; -} - -static int compare_mp(const void *a, const void *b) -{ - MirrorPair *mpa = (MirrorPair *)a; - MirrorPair *mpb = (MirrorPair *)b; - return mpa->from - mpb->from; -} - -static int compare_bp(const void *a, const void *b) -{ - BracketPair *bpa = (BracketPair *)a; - BracketPair *bpb = (BracketPair *)b; - return bpa->from - bpb->from; -} - -static BracketPair *search_bp(uint32_t code) -{ - BracketPair bp = {0,0,2}; - BracketPair *res; - - bp.from = code; - res = (BracketPair *) bsearch(&bp, bracket_pairs, BIDI_BRACKET_LEN, - sizeof(BracketPair), compare_bp); - return res; -} - -static int hangul_pair_decompose(uint32_t code, uint32_t *a, uint32_t *b) -{ - int si = code - SBASE; - - if (si < 0 || si >= SCOUNT) - return 0; - - if (si % TCOUNT) { - /* LV,T */ - *a = SBASE + (si / TCOUNT) * TCOUNT; - *b = TBASE + (si % TCOUNT); - return 3; - } else { - /* L,V */ - *a = LBASE + (si / NCOUNT); - *b = VBASE + (si % NCOUNT) / TCOUNT; - return 2; - } -} - -static int hangul_pair_compose(uint32_t *code, uint32_t a, uint32_t b) -{ - if (a >= SBASE && a < (SBASE + SCOUNT) && b >= TBASE && b < (TBASE + TCOUNT)) { - /* LV,T */ - *code = a + (b - TBASE); - return 3; - } else if (a >= LBASE && a < (LBASE + LCOUNT) && b >= VBASE && b < (VBASE + VCOUNT)) { - /* L,V */ - int li = a - LBASE; - int vi = b - VBASE; - *code = SBASE + li * NCOUNT + vi * TCOUNT; - return 2; - } else { - return 0; - } -} - -static uint32_t decode_utf16(const unsigned short **code_ptr) -{ - const unsigned short *code = *code_ptr; - - if (code[0] < 0xd800 || code[0] > 0xdc00) { - *code_ptr += 1; - return (uint32_t)code[0]; - } else { - *code_ptr += 2; - return 0x10000 + ((uint32_t)code[1] - 0xdc00) + - (((uint32_t)code[0] - 0xd800) << 10); - } -} - -const char *ucdn_get_unicode_version(void) -{ - return UNIDATA_VERSION; -} - -int ucdn_get_combining_class(uint32_t code) -{ - return get_ucd_record(code)->combining; -} - -int ucdn_get_east_asian_width(uint32_t code) -{ - return get_ucd_record(code)->east_asian_width; -} - -int ucdn_get_general_category(uint32_t code) -{ - return get_ucd_record(code)->category; -} - -int ucdn_get_bidi_class(uint32_t code) -{ - return get_ucd_record(code)->bidi_class; -} - -int ucdn_get_mirrored(uint32_t code) -{ - return ucdn_mirror(code) != code; -} - -int ucdn_get_script(uint32_t code) -{ - return get_ucd_record(code)->script; -} - -int ucdn_get_linebreak_class(uint32_t code) -{ - return get_ucd_record(code)->linebreak_class; -} - -int ucdn_get_resolved_linebreak_class(uint32_t code) -{ - const UCDRecord *record = get_ucd_record(code); - - switch (record->linebreak_class) - { - case UCDN_LINEBREAK_CLASS_AI: - case UCDN_LINEBREAK_CLASS_SG: - case UCDN_LINEBREAK_CLASS_XX: - return UCDN_LINEBREAK_CLASS_AL; - - case UCDN_LINEBREAK_CLASS_SA: - if (record->category == UCDN_GENERAL_CATEGORY_MC || - record->category == UCDN_GENERAL_CATEGORY_MN) - return UCDN_LINEBREAK_CLASS_CM; - return UCDN_LINEBREAK_CLASS_AL; - - case UCDN_LINEBREAK_CLASS_CJ: - return UCDN_LINEBREAK_CLASS_NS; - - case UCDN_LINEBREAK_CLASS_CB: - return UCDN_LINEBREAK_CLASS_B2; - - case UCDN_LINEBREAK_CLASS_NL: - return UCDN_LINEBREAK_CLASS_BK; - - default: - return record->linebreak_class; - } -} - -uint32_t ucdn_mirror(uint32_t code) -{ - MirrorPair mp = {0}; - MirrorPair *res; - - mp.from = code; - res = (MirrorPair *) bsearch(&mp, mirror_pairs, BIDI_MIRROR_LEN, - sizeof(MirrorPair), compare_mp); - - if (res == NULL) - return code; - else - return res->to; -} - -uint32_t ucdn_paired_bracket(uint32_t code) -{ - BracketPair *res = search_bp(code); - if (res == NULL) - return code; - else - return res->to; -} - -int ucdn_paired_bracket_type(uint32_t code) -{ - BracketPair *res = search_bp(code); - if (res == NULL) - return UCDN_BIDI_PAIRED_BRACKET_TYPE_NONE; - else - return res->type; -} - -int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b) -{ - const unsigned short *rec; - int len; - - if (hangul_pair_decompose(code, a, b)) - return 1; - - rec = get_decomp_record(code); - len = rec[0] >> 8; - - if ((rec[0] & 0xff) != 0 || len == 0) - return 0; - - rec++; - *a = decode_utf16(&rec); - if (len > 1) - *b = decode_utf16(&rec); - else - *b = 0; - - return 1; -} - -int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b) -{ - int l, r, index, indexi, offset; - - if (hangul_pair_compose(code, a, b)) - return 1; - - l = get_comp_index(a, nfc_first, sizeof(nfc_first) / sizeof(Reindex)); - r = get_comp_index(b, nfc_last, sizeof(nfc_last) / sizeof(Reindex)); - - if (l < 0 || r < 0) - return 0; - - indexi = l * TOTAL_LAST + r; - index = comp_index0[indexi >> (COMP_SHIFT1+COMP_SHIFT2)] << COMP_SHIFT1; - offset = (indexi >> COMP_SHIFT2) & ((1<> 8; - - if (len == 0) - return 0; - - rec++; - for (i = 0; i < len; i++) - decomposed[i] = decode_utf16(&rec); - - return len; -} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.h b/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.h deleted file mode 100644 index 05d46d2b1be..00000000000 --- a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn.h +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (C) 2012 Grigori Goronzy - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef UCDN_H -#define UCDN_H - - - -#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__MINGW32__) -# define HB_BEGIN_VISIBILITY _Pragma ("GCC visibility push(hidden)") -# define HB_END_VISIBILITY _Pragma ("GCC visibility pop") -#else -# define HB_BEGIN_VISIBILITY -# define HB_END_VISIBILITY -#endif -#ifdef __cplusplus -# define HB_BEGIN_HEADER extern "C" { HB_BEGIN_VISIBILITY -# define HB_END_HEADER HB_END_VISIBILITY } -#else -# define HB_BEGIN_HEADER HB_BEGIN_VISIBILITY -# define HB_END_HEADER HB_END_VISIBILITY -#endif - -HB_BEGIN_HEADER - -#if defined (_SVR4) || defined (SVR4) || defined (__OpenBSD__) || \ - defined (_sgi) || defined (__sun) || defined (sun) || \ - defined (__digital__) || defined (__HP_cc) -# include -#elif defined (_AIX) -# include -#elif defined (_MSC_VER) && _MSC_VER < 1600 -/* VS 2010 (_MSC_VER 1600) has stdint.h */ -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#else -# include -#endif - - -#define UCDN_EAST_ASIAN_F 0 -#define UCDN_EAST_ASIAN_H 1 -#define UCDN_EAST_ASIAN_W 2 -#define UCDN_EAST_ASIAN_NA 3 -#define UCDN_EAST_ASIAN_A 4 -#define UCDN_EAST_ASIAN_N 5 - -#define UCDN_SCRIPT_COMMON 0 -#define UCDN_SCRIPT_LATIN 1 -#define UCDN_SCRIPT_GREEK 2 -#define UCDN_SCRIPT_CYRILLIC 3 -#define UCDN_SCRIPT_ARMENIAN 4 -#define UCDN_SCRIPT_HEBREW 5 -#define UCDN_SCRIPT_ARABIC 6 -#define UCDN_SCRIPT_SYRIAC 7 -#define UCDN_SCRIPT_THAANA 8 -#define UCDN_SCRIPT_DEVANAGARI 9 -#define UCDN_SCRIPT_BENGALI 10 -#define UCDN_SCRIPT_GURMUKHI 11 -#define UCDN_SCRIPT_GUJARATI 12 -#define UCDN_SCRIPT_ORIYA 13 -#define UCDN_SCRIPT_TAMIL 14 -#define UCDN_SCRIPT_TELUGU 15 -#define UCDN_SCRIPT_KANNADA 16 -#define UCDN_SCRIPT_MALAYALAM 17 -#define UCDN_SCRIPT_SINHALA 18 -#define UCDN_SCRIPT_THAI 19 -#define UCDN_SCRIPT_LAO 20 -#define UCDN_SCRIPT_TIBETAN 21 -#define UCDN_SCRIPT_MYANMAR 22 -#define UCDN_SCRIPT_GEORGIAN 23 -#define UCDN_SCRIPT_HANGUL 24 -#define UCDN_SCRIPT_ETHIOPIC 25 -#define UCDN_SCRIPT_CHEROKEE 26 -#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27 -#define UCDN_SCRIPT_OGHAM 28 -#define UCDN_SCRIPT_RUNIC 29 -#define UCDN_SCRIPT_KHMER 30 -#define UCDN_SCRIPT_MONGOLIAN 31 -#define UCDN_SCRIPT_HIRAGANA 32 -#define UCDN_SCRIPT_KATAKANA 33 -#define UCDN_SCRIPT_BOPOMOFO 34 -#define UCDN_SCRIPT_HAN 35 -#define UCDN_SCRIPT_YI 36 -#define UCDN_SCRIPT_OLD_ITALIC 37 -#define UCDN_SCRIPT_GOTHIC 38 -#define UCDN_SCRIPT_DESERET 39 -#define UCDN_SCRIPT_INHERITED 40 -#define UCDN_SCRIPT_TAGALOG 41 -#define UCDN_SCRIPT_HANUNOO 42 -#define UCDN_SCRIPT_BUHID 43 -#define UCDN_SCRIPT_TAGBANWA 44 -#define UCDN_SCRIPT_LIMBU 45 -#define UCDN_SCRIPT_TAI_LE 46 -#define UCDN_SCRIPT_LINEAR_B 47 -#define UCDN_SCRIPT_UGARITIC 48 -#define UCDN_SCRIPT_SHAVIAN 49 -#define UCDN_SCRIPT_OSMANYA 50 -#define UCDN_SCRIPT_CYPRIOT 51 -#define UCDN_SCRIPT_BRAILLE 52 -#define UCDN_SCRIPT_BUGINESE 53 -#define UCDN_SCRIPT_COPTIC 54 -#define UCDN_SCRIPT_NEW_TAI_LUE 55 -#define UCDN_SCRIPT_GLAGOLITIC 56 -#define UCDN_SCRIPT_TIFINAGH 57 -#define UCDN_SCRIPT_SYLOTI_NAGRI 58 -#define UCDN_SCRIPT_OLD_PERSIAN 59 -#define UCDN_SCRIPT_KHAROSHTHI 60 -#define UCDN_SCRIPT_BALINESE 61 -#define UCDN_SCRIPT_CUNEIFORM 62 -#define UCDN_SCRIPT_PHOENICIAN 63 -#define UCDN_SCRIPT_PHAGS_PA 64 -#define UCDN_SCRIPT_NKO 65 -#define UCDN_SCRIPT_SUNDANESE 66 -#define UCDN_SCRIPT_LEPCHA 67 -#define UCDN_SCRIPT_OL_CHIKI 68 -#define UCDN_SCRIPT_VAI 69 -#define UCDN_SCRIPT_SAURASHTRA 70 -#define UCDN_SCRIPT_KAYAH_LI 71 -#define UCDN_SCRIPT_REJANG 72 -#define UCDN_SCRIPT_LYCIAN 73 -#define UCDN_SCRIPT_CARIAN 74 -#define UCDN_SCRIPT_LYDIAN 75 -#define UCDN_SCRIPT_CHAM 76 -#define UCDN_SCRIPT_TAI_THAM 77 -#define UCDN_SCRIPT_TAI_VIET 78 -#define UCDN_SCRIPT_AVESTAN 79 -#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80 -#define UCDN_SCRIPT_SAMARITAN 81 -#define UCDN_SCRIPT_LISU 82 -#define UCDN_SCRIPT_BAMUM 83 -#define UCDN_SCRIPT_JAVANESE 84 -#define UCDN_SCRIPT_MEETEI_MAYEK 85 -#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86 -#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87 -#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88 -#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89 -#define UCDN_SCRIPT_OLD_TURKIC 90 -#define UCDN_SCRIPT_KAITHI 91 -#define UCDN_SCRIPT_BATAK 92 -#define UCDN_SCRIPT_BRAHMI 93 -#define UCDN_SCRIPT_MANDAIC 94 -#define UCDN_SCRIPT_CHAKMA 95 -#define UCDN_SCRIPT_MEROITIC_CURSIVE 96 -#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97 -#define UCDN_SCRIPT_MIAO 98 -#define UCDN_SCRIPT_SHARADA 99 -#define UCDN_SCRIPT_SORA_SOMPENG 100 -#define UCDN_SCRIPT_TAKRI 101 -#define UCDN_SCRIPT_UNKNOWN 102 -#define UCDN_SCRIPT_BASSA_VAH 103 -#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104 -#define UCDN_SCRIPT_DUPLOYAN 105 -#define UCDN_SCRIPT_ELBASAN 106 -#define UCDN_SCRIPT_GRANTHA 107 -#define UCDN_SCRIPT_KHOJKI 108 -#define UCDN_SCRIPT_KHUDAWADI 109 -#define UCDN_SCRIPT_LINEAR_A 110 -#define UCDN_SCRIPT_MAHAJANI 111 -#define UCDN_SCRIPT_MANICHAEAN 112 -#define UCDN_SCRIPT_MENDE_KIKAKUI 113 -#define UCDN_SCRIPT_MODI 114 -#define UCDN_SCRIPT_MRO 115 -#define UCDN_SCRIPT_NABATAEAN 116 -#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117 -#define UCDN_SCRIPT_OLD_PERMIC 118 -#define UCDN_SCRIPT_PAHAWH_HMONG 119 -#define UCDN_SCRIPT_PALMYRENE 120 -#define UCDN_SCRIPT_PAU_CIN_HAU 121 -#define UCDN_SCRIPT_PSALTER_PAHLAVI 122 -#define UCDN_SCRIPT_SIDDHAM 123 -#define UCDN_SCRIPT_TIRHUTA 124 -#define UCDN_SCRIPT_WARANG_CITI 125 -#define UCDN_SCRIPT_AHOM 126 -#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127 -#define UCDN_SCRIPT_HATRAN 128 -#define UCDN_SCRIPT_MULTANI 129 -#define UCDN_SCRIPT_OLD_HUNGARIAN 130 -#define UCDN_SCRIPT_SIGNWRITING 131 -#define UCDN_SCRIPT_ADLAM 132 -#define UCDN_SCRIPT_BHAIKSUKI 133 -#define UCDN_SCRIPT_MARCHEN 134 -#define UCDN_SCRIPT_NEWA 135 -#define UCDN_SCRIPT_OSAGE 136 -#define UCDN_SCRIPT_TANGUT 137 -#define UCDN_SCRIPT_MASARAM_GONDI 138 -#define UCDN_SCRIPT_NUSHU 139 -#define UCDN_SCRIPT_SOYOMBO 140 -#define UCDN_SCRIPT_ZANABAZAR_SQUARE 141 - -#define UCDN_LINEBREAK_CLASS_OP 0 -#define UCDN_LINEBREAK_CLASS_CL 1 -#define UCDN_LINEBREAK_CLASS_CP 2 -#define UCDN_LINEBREAK_CLASS_QU 3 -#define UCDN_LINEBREAK_CLASS_GL 4 -#define UCDN_LINEBREAK_CLASS_NS 5 -#define UCDN_LINEBREAK_CLASS_EX 6 -#define UCDN_LINEBREAK_CLASS_SY 7 -#define UCDN_LINEBREAK_CLASS_IS 8 -#define UCDN_LINEBREAK_CLASS_PR 9 -#define UCDN_LINEBREAK_CLASS_PO 10 -#define UCDN_LINEBREAK_CLASS_NU 11 -#define UCDN_LINEBREAK_CLASS_AL 12 -#define UCDN_LINEBREAK_CLASS_HL 13 -#define UCDN_LINEBREAK_CLASS_ID 14 -#define UCDN_LINEBREAK_CLASS_IN 15 -#define UCDN_LINEBREAK_CLASS_HY 16 -#define UCDN_LINEBREAK_CLASS_BA 17 -#define UCDN_LINEBREAK_CLASS_BB 18 -#define UCDN_LINEBREAK_CLASS_B2 19 -#define UCDN_LINEBREAK_CLASS_ZW 20 -#define UCDN_LINEBREAK_CLASS_CM 21 -#define UCDN_LINEBREAK_CLASS_WJ 22 -#define UCDN_LINEBREAK_CLASS_H2 23 -#define UCDN_LINEBREAK_CLASS_H3 24 -#define UCDN_LINEBREAK_CLASS_JL 25 -#define UCDN_LINEBREAK_CLASS_JV 26 -#define UCDN_LINEBREAK_CLASS_JT 27 -#define UCDN_LINEBREAK_CLASS_RI 28 -#define UCDN_LINEBREAK_CLASS_AI 29 -#define UCDN_LINEBREAK_CLASS_BK 30 -#define UCDN_LINEBREAK_CLASS_CB 31 -#define UCDN_LINEBREAK_CLASS_CJ 32 -#define UCDN_LINEBREAK_CLASS_CR 33 -#define UCDN_LINEBREAK_CLASS_LF 34 -#define UCDN_LINEBREAK_CLASS_NL 35 -#define UCDN_LINEBREAK_CLASS_SA 36 -#define UCDN_LINEBREAK_CLASS_SG 37 -#define UCDN_LINEBREAK_CLASS_SP 38 -#define UCDN_LINEBREAK_CLASS_XX 39 -#define UCDN_LINEBREAK_CLASS_ZWJ 40 -#define UCDN_LINEBREAK_CLASS_EB 41 -#define UCDN_LINEBREAK_CLASS_EM 42 - -#define UCDN_GENERAL_CATEGORY_CC 0 -#define UCDN_GENERAL_CATEGORY_CF 1 -#define UCDN_GENERAL_CATEGORY_CN 2 -#define UCDN_GENERAL_CATEGORY_CO 3 -#define UCDN_GENERAL_CATEGORY_CS 4 -#define UCDN_GENERAL_CATEGORY_LL 5 -#define UCDN_GENERAL_CATEGORY_LM 6 -#define UCDN_GENERAL_CATEGORY_LO 7 -#define UCDN_GENERAL_CATEGORY_LT 8 -#define UCDN_GENERAL_CATEGORY_LU 9 -#define UCDN_GENERAL_CATEGORY_MC 10 -#define UCDN_GENERAL_CATEGORY_ME 11 -#define UCDN_GENERAL_CATEGORY_MN 12 -#define UCDN_GENERAL_CATEGORY_ND 13 -#define UCDN_GENERAL_CATEGORY_NL 14 -#define UCDN_GENERAL_CATEGORY_NO 15 -#define UCDN_GENERAL_CATEGORY_PC 16 -#define UCDN_GENERAL_CATEGORY_PD 17 -#define UCDN_GENERAL_CATEGORY_PE 18 -#define UCDN_GENERAL_CATEGORY_PF 19 -#define UCDN_GENERAL_CATEGORY_PI 20 -#define UCDN_GENERAL_CATEGORY_PO 21 -#define UCDN_GENERAL_CATEGORY_PS 22 -#define UCDN_GENERAL_CATEGORY_SC 23 -#define UCDN_GENERAL_CATEGORY_SK 24 -#define UCDN_GENERAL_CATEGORY_SM 25 -#define UCDN_GENERAL_CATEGORY_SO 26 -#define UCDN_GENERAL_CATEGORY_ZL 27 -#define UCDN_GENERAL_CATEGORY_ZP 28 -#define UCDN_GENERAL_CATEGORY_ZS 29 - -#define UCDN_BIDI_CLASS_L 0 -#define UCDN_BIDI_CLASS_LRE 1 -#define UCDN_BIDI_CLASS_LRO 2 -#define UCDN_BIDI_CLASS_R 3 -#define UCDN_BIDI_CLASS_AL 4 -#define UCDN_BIDI_CLASS_RLE 5 -#define UCDN_BIDI_CLASS_RLO 6 -#define UCDN_BIDI_CLASS_PDF 7 -#define UCDN_BIDI_CLASS_EN 8 -#define UCDN_BIDI_CLASS_ES 9 -#define UCDN_BIDI_CLASS_ET 10 -#define UCDN_BIDI_CLASS_AN 11 -#define UCDN_BIDI_CLASS_CS 12 -#define UCDN_BIDI_CLASS_NSM 13 -#define UCDN_BIDI_CLASS_BN 14 -#define UCDN_BIDI_CLASS_B 15 -#define UCDN_BIDI_CLASS_S 16 -#define UCDN_BIDI_CLASS_WS 17 -#define UCDN_BIDI_CLASS_ON 18 -#define UCDN_BIDI_CLASS_LRI 19 -#define UCDN_BIDI_CLASS_RLI 20 -#define UCDN_BIDI_CLASS_FSI 21 -#define UCDN_BIDI_CLASS_PDI 22 - -#define UCDN_BIDI_PAIRED_BRACKET_TYPE_OPEN 0 -#define UCDN_BIDI_PAIRED_BRACKET_TYPE_CLOSE 1 -#define UCDN_BIDI_PAIRED_BRACKET_TYPE_NONE 2 - -/** - * Return version of the Unicode database. - * - * @return Unicode database version - */ -const char *ucdn_get_unicode_version(void); - -/** - * Get combining class of a codepoint. - * - * @param code Unicode codepoint - * @return combining class value, as defined in UAX#44 - */ -int ucdn_get_combining_class(uint32_t code); - -/** - * Get east-asian width of a codepoint. - * - * @param code Unicode codepoint - * @return value according to UCDN_EAST_ASIAN_* and as defined in UAX#11. - */ -int ucdn_get_east_asian_width(uint32_t code); - -/** - * Get general category of a codepoint. - * - * @param code Unicode codepoint - * @return value according to UCDN_GENERAL_CATEGORY_* and as defined in - * UAX#44. - */ -int ucdn_get_general_category(uint32_t code); - -/** - * Get bidirectional class of a codepoint. - * - * @param code Unicode codepoint - * @return value according to UCDN_BIDI_CLASS_* and as defined in UAX#44. - */ -int ucdn_get_bidi_class(uint32_t code); - -/** - * Get script of a codepoint. - * - * @param code Unicode codepoint - * @return value according to UCDN_SCRIPT_* and as defined in UAX#24. - */ -int ucdn_get_script(uint32_t code); - -/** - * Get unresolved linebreak class of a codepoint. This does not take - * rule LB1 of UAX#14 into account. See ucdn_get_resolved_linebreak_class() - * for resolved linebreak classes. - * - * @param code Unicode codepoint - * @return value according to UCDN_LINEBREAK_* and as defined in UAX#14. - */ -int ucdn_get_linebreak_class(uint32_t code); - -/** - * Get resolved linebreak class of a codepoint. This resolves characters - * in the AI, SG, XX, SA and CJ classes according to rule LB1 of UAX#14. - * In addition the CB class is resolved as the equivalent B2 class and - * the NL class is resolved as the equivalent BK class. - * - * @param code Unicode codepoint - * @return value according to UCDN_LINEBREAK_* and as defined in UAX#14. - */ -int ucdn_get_resolved_linebreak_class(uint32_t code); - -/** - * Check if codepoint can be mirrored. - * - * @param code Unicode codepoint - * @return 1 if mirrored character exists, otherwise 0 - */ -int ucdn_get_mirrored(uint32_t code); - -/** - * Mirror a codepoint. - * - * @param code Unicode codepoint - * @return mirrored codepoint or the original codepoint if no - * mirrored character exists - */ -uint32_t ucdn_mirror(uint32_t code); - -/** - * Get paired bracket for a codepoint. - * - * @param code Unicode codepoint - * @return paired bracket codepoint or the original codepoint if no - * paired bracket character exists - */ -uint32_t ucdn_paired_bracket(uint32_t code); - -/** - * Get paired bracket type for a codepoint. - * - * @param code Unicode codepoint - * @return value according to UCDN_BIDI_PAIRED_BRACKET_TYPE_* and as defined - * in UAX#9. - * - */ -int ucdn_paired_bracket_type(uint32_t code); - -/** - * Pairwise canonical decomposition of a codepoint. This includes - * Hangul Jamo decomposition (see chapter 3.12 of the Unicode core - * specification). - * - * Hangul is decomposed into L and V jamos for LV forms, and an - * LV precomposed syllable and a T jamo for LVT forms. - * - * @param code Unicode codepoint - * @param a filled with first codepoint of decomposition - * @param b filled with second codepoint of decomposition, or 0 - * @return success - */ -int ucdn_decompose(uint32_t code, uint32_t *a, uint32_t *b); - -/** - * Compatibility decomposition of a codepoint. - * - * @param code Unicode codepoint - * @param decomposed filled with decomposition, must be able to hold 18 - * characters - * @return length of decomposition or 0 in case none exists - */ -int ucdn_compat_decompose(uint32_t code, uint32_t *decomposed); - -/** - * Pairwise canonical composition of two codepoints. This includes - * Hangul Jamo composition (see chapter 3.12 of the Unicode core - * specification). - * - * Hangul composition expects either L and V jamos, or an LV - * precomposed syllable and a T jamo. This is exactly the inverse - * of pairwise Hangul decomposition. - * - * @param code filled with composition - * @param a first codepoint - * @param b second codepoint - * @return success - */ -int ucdn_compose(uint32_t *code, uint32_t a, uint32_t b); - -HB_END_HEADER - -#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn_db.h b/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn_db.h deleted file mode 100644 index d72c7ba0dff..00000000000 --- a/src/java.desktop/share/native/libharfbuzz/hb-ucdn/ucdn_db.h +++ /dev/null @@ -1,5730 +0,0 @@ -/* this file was generated by makeunicodedata.py 3.2 */ - -#define UNIDATA_VERSION "11.0.0" -/* a list of unique database records */ -static const UCDRecord ucd_records[] = { - {2, 0, 18, 5, 102, 39}, - {0, 0, 14, 5, 0, 21}, - {0, 0, 16, 5, 0, 17}, - {0, 0, 15, 5, 0, 34}, - {0, 0, 16, 5, 0, 30}, - {0, 0, 17, 5, 0, 30}, - {0, 0, 15, 5, 0, 33}, - {0, 0, 15, 5, 0, 21}, - {0, 0, 16, 5, 0, 21}, - {29, 0, 17, 3, 0, 38}, - {21, 0, 18, 3, 0, 6}, - {21, 0, 18, 3, 0, 3}, - {21, 0, 10, 3, 0, 12}, - {23, 0, 10, 3, 0, 9}, - {21, 0, 10, 3, 0, 10}, - {21, 0, 18, 3, 0, 12}, - {22, 0, 18, 3, 0, 0}, - {18, 0, 18, 3, 0, 2}, - {25, 0, 9, 3, 0, 9}, - {21, 0, 12, 3, 0, 8}, - {17, 0, 9, 3, 0, 16}, - {21, 0, 12, 3, 0, 7}, - {13, 0, 8, 3, 0, 11}, - {21, 0, 18, 3, 0, 8}, - {25, 0, 18, 3, 0, 12}, - {9, 0, 0, 3, 1, 12}, - {21, 0, 18, 3, 0, 9}, - {24, 0, 18, 3, 0, 12}, - {16, 0, 18, 3, 0, 12}, - {5, 0, 0, 3, 1, 12}, - {25, 0, 18, 3, 0, 17}, - {18, 0, 18, 3, 0, 1}, - {0, 0, 15, 5, 0, 35}, - {29, 0, 12, 5, 0, 4}, - {21, 0, 18, 4, 0, 0}, - {23, 0, 10, 3, 0, 10}, - {23, 0, 10, 4, 0, 9}, - {26, 0, 18, 3, 0, 12}, - {21, 0, 18, 4, 0, 29}, - {24, 0, 18, 4, 0, 29}, - {26, 0, 18, 5, 0, 12}, - {7, 0, 0, 4, 1, 29}, - {20, 0, 18, 5, 0, 3}, - {1, 0, 14, 4, 0, 17}, - {26, 0, 18, 4, 0, 12}, - {26, 0, 10, 4, 0, 10}, - {25, 0, 10, 4, 0, 9}, - {15, 0, 8, 4, 0, 29}, - {24, 0, 18, 4, 0, 18}, - {5, 0, 0, 5, 0, 12}, - {19, 0, 18, 5, 0, 3}, - {15, 0, 18, 4, 0, 29}, - {9, 0, 0, 5, 1, 12}, - {9, 0, 0, 4, 1, 12}, - {25, 0, 18, 4, 0, 29}, - {5, 0, 0, 4, 1, 12}, - {5, 0, 0, 5, 1, 12}, - {7, 0, 0, 5, 1, 12}, - {8, 0, 0, 5, 1, 12}, - {6, 0, 0, 5, 1, 12}, - {6, 0, 18, 5, 0, 12}, - {6, 0, 0, 5, 0, 12}, - {24, 0, 18, 5, 0, 12}, - {24, 0, 18, 4, 0, 12}, - {6, 0, 18, 4, 0, 29}, - {6, 0, 18, 5, 0, 18}, - {6, 0, 0, 4, 0, 29}, - {24, 0, 18, 5, 34, 12}, - {12, 230, 13, 4, 40, 21}, - {12, 232, 13, 4, 40, 21}, - {12, 220, 13, 4, 40, 21}, - {12, 216, 13, 4, 40, 21}, - {12, 202, 13, 4, 40, 21}, - {12, 1, 13, 4, 40, 21}, - {12, 240, 13, 4, 40, 21}, - {12, 0, 13, 4, 40, 4}, - {12, 233, 13, 4, 40, 4}, - {12, 234, 13, 4, 40, 4}, - {9, 0, 0, 5, 2, 12}, - {5, 0, 0, 5, 2, 12}, - {24, 0, 18, 5, 2, 12}, - {2, 0, 18, 5, 102, 39}, - {6, 0, 0, 5, 2, 12}, - {21, 0, 18, 5, 0, 8}, - {21, 0, 18, 5, 0, 12}, - {9, 0, 0, 4, 2, 12}, - {5, 0, 0, 4, 2, 12}, - {9, 0, 0, 5, 54, 12}, - {5, 0, 0, 5, 54, 12}, - {25, 0, 18, 5, 2, 12}, - {9, 0, 0, 5, 3, 12}, - {9, 0, 0, 4, 3, 12}, - {5, 0, 0, 4, 3, 12}, - {5, 0, 0, 5, 3, 12}, - {26, 0, 0, 5, 3, 12}, - {12, 230, 13, 5, 3, 21}, - {12, 230, 13, 5, 40, 21}, - {11, 0, 13, 5, 3, 21}, - {9, 0, 0, 5, 4, 12}, - {6, 0, 0, 5, 4, 12}, - {21, 0, 0, 5, 4, 12}, - {5, 0, 0, 5, 4, 12}, - {21, 0, 0, 5, 0, 8}, - {17, 0, 18, 5, 4, 17}, - {26, 0, 18, 5, 4, 12}, - {23, 0, 10, 5, 4, 9}, - {12, 220, 13, 5, 5, 21}, - {12, 230, 13, 5, 5, 21}, - {12, 222, 13, 5, 5, 21}, - {12, 228, 13, 5, 5, 21}, - {12, 10, 13, 5, 5, 21}, - {12, 11, 13, 5, 5, 21}, - {12, 12, 13, 5, 5, 21}, - {12, 13, 13, 5, 5, 21}, - {12, 14, 13, 5, 5, 21}, - {12, 15, 13, 5, 5, 21}, - {12, 16, 13, 5, 5, 21}, - {12, 17, 13, 5, 5, 21}, - {12, 18, 13, 5, 5, 21}, - {12, 19, 13, 5, 5, 21}, - {12, 20, 13, 5, 5, 21}, - {12, 21, 13, 5, 5, 21}, - {12, 22, 13, 5, 5, 21}, - {17, 0, 3, 5, 5, 17}, - {12, 23, 13, 5, 5, 21}, - {21, 0, 3, 5, 5, 12}, - {12, 24, 13, 5, 5, 21}, - {12, 25, 13, 5, 5, 21}, - {21, 0, 3, 5, 5, 6}, - {7, 0, 3, 5, 5, 13}, - {1, 0, 11, 5, 6, 12}, - {1, 0, 11, 5, 0, 12}, - {25, 0, 18, 5, 6, 12}, - {25, 0, 4, 5, 6, 12}, - {21, 0, 10, 5, 6, 10}, - {23, 0, 4, 5, 6, 10}, - {21, 0, 12, 5, 0, 8}, - {21, 0, 4, 5, 6, 8}, - {26, 0, 18, 5, 6, 12}, - {12, 230, 13, 5, 6, 21}, - {12, 30, 13, 5, 6, 21}, - {12, 31, 13, 5, 6, 21}, - {12, 32, 13, 5, 6, 21}, - {21, 0, 4, 5, 0, 6}, - {1, 0, 4, 5, 6, 21}, - {21, 0, 4, 5, 6, 6}, - {7, 0, 4, 5, 6, 12}, - {6, 0, 4, 5, 0, 12}, - {12, 27, 13, 5, 40, 21}, - {12, 28, 13, 5, 40, 21}, - {12, 29, 13, 5, 40, 21}, - {12, 30, 13, 5, 40, 21}, - {12, 31, 13, 5, 40, 21}, - {12, 32, 13, 5, 40, 21}, - {12, 33, 13, 5, 40, 21}, - {12, 34, 13, 5, 40, 21}, - {12, 220, 13, 5, 40, 21}, - {12, 220, 13, 5, 6, 21}, - {13, 0, 11, 5, 6, 11}, - {21, 0, 11, 5, 6, 11}, - {21, 0, 4, 5, 6, 12}, - {12, 35, 13, 5, 40, 21}, - {6, 0, 4, 5, 6, 12}, - {13, 0, 8, 5, 6, 11}, - {26, 0, 4, 5, 6, 12}, - {21, 0, 4, 5, 7, 12}, - {1, 0, 4, 5, 7, 12}, - {7, 0, 4, 5, 7, 12}, - {12, 36, 13, 5, 7, 21}, - {12, 230, 13, 5, 7, 21}, - {12, 220, 13, 5, 7, 21}, - {7, 0, 4, 5, 8, 12}, - {12, 0, 13, 5, 8, 21}, - {13, 0, 3, 5, 65, 11}, - {7, 0, 3, 5, 65, 12}, - {12, 230, 13, 5, 65, 21}, - {12, 220, 13, 5, 65, 21}, - {6, 0, 3, 5, 65, 12}, - {26, 0, 18, 5, 65, 12}, - {21, 0, 18, 5, 65, 12}, - {21, 0, 18, 5, 65, 8}, - {21, 0, 18, 5, 65, 6}, - {23, 0, 3, 5, 65, 9}, - {7, 0, 3, 5, 81, 12}, - {12, 230, 13, 5, 81, 21}, - {6, 0, 3, 5, 81, 12}, - {21, 0, 3, 5, 81, 12}, - {7, 0, 3, 5, 94, 12}, - {12, 220, 13, 5, 94, 21}, - {21, 0, 3, 5, 94, 12}, - {12, 27, 13, 5, 6, 21}, - {12, 28, 13, 5, 6, 21}, - {12, 29, 13, 5, 6, 21}, - {12, 0, 13, 5, 9, 21}, - {10, 0, 0, 5, 9, 21}, - {7, 0, 0, 5, 9, 12}, - {12, 7, 13, 5, 9, 21}, - {12, 9, 13, 5, 9, 21}, - {12, 230, 13, 5, 9, 21}, - {21, 0, 0, 5, 0, 17}, - {13, 0, 0, 5, 9, 11}, - {21, 0, 0, 5, 9, 12}, - {6, 0, 0, 5, 9, 12}, - {7, 0, 0, 5, 10, 12}, - {12, 0, 13, 5, 10, 21}, - {10, 0, 0, 5, 10, 21}, - {12, 7, 13, 5, 10, 21}, - {12, 9, 13, 5, 10, 21}, - {13, 0, 0, 5, 10, 11}, - {23, 0, 10, 5, 10, 10}, - {15, 0, 0, 5, 10, 12}, - {15, 0, 0, 5, 10, 10}, - {26, 0, 0, 5, 10, 12}, - {23, 0, 10, 5, 10, 9}, - {21, 0, 0, 5, 10, 12}, - {12, 230, 13, 5, 10, 21}, - {12, 0, 13, 5, 11, 21}, - {10, 0, 0, 5, 11, 21}, - {7, 0, 0, 5, 11, 12}, - {12, 7, 13, 5, 11, 21}, - {12, 9, 13, 5, 11, 21}, - {13, 0, 0, 5, 11, 11}, - {21, 0, 0, 5, 11, 12}, - {12, 0, 13, 5, 12, 21}, - {10, 0, 0, 5, 12, 21}, - {7, 0, 0, 5, 12, 12}, - {12, 7, 13, 5, 12, 21}, - {12, 9, 13, 5, 12, 21}, - {13, 0, 0, 5, 12, 11}, - {21, 0, 0, 5, 12, 12}, - {23, 0, 10, 5, 12, 9}, - {12, 0, 13, 5, 13, 21}, - {10, 0, 0, 5, 13, 21}, - {7, 0, 0, 5, 13, 12}, - {12, 7, 13, 5, 13, 21}, - {12, 9, 13, 5, 13, 21}, - {13, 0, 0, 5, 13, 11}, - {26, 0, 0, 5, 13, 12}, - {15, 0, 0, 5, 13, 12}, - {12, 0, 13, 5, 14, 21}, - {7, 0, 0, 5, 14, 12}, - {10, 0, 0, 5, 14, 21}, - {12, 9, 13, 5, 14, 21}, - {13, 0, 0, 5, 14, 11}, - {15, 0, 0, 5, 14, 12}, - {26, 0, 18, 5, 14, 12}, - {23, 0, 10, 5, 14, 9}, - {12, 0, 13, 5, 15, 21}, - {10, 0, 0, 5, 15, 21}, - {7, 0, 0, 5, 15, 12}, - {12, 9, 13, 5, 15, 21}, - {12, 84, 13, 5, 15, 21}, - {12, 91, 13, 5, 15, 21}, - {13, 0, 0, 5, 15, 11}, - {15, 0, 18, 5, 15, 12}, - {26, 0, 0, 5, 15, 12}, - {7, 0, 0, 5, 16, 12}, - {12, 0, 13, 5, 16, 21}, - {10, 0, 0, 5, 16, 21}, - {21, 0, 0, 5, 16, 18}, - {12, 7, 13, 5, 16, 21}, - {12, 0, 0, 5, 16, 21}, - {12, 9, 13, 5, 16, 21}, - {13, 0, 0, 5, 16, 11}, - {12, 0, 13, 5, 17, 21}, - {10, 0, 0, 5, 17, 21}, - {7, 0, 0, 5, 17, 12}, - {12, 9, 13, 5, 17, 21}, - {26, 0, 0, 5, 17, 12}, - {15, 0, 0, 5, 17, 12}, - {13, 0, 0, 5, 17, 11}, - {26, 0, 0, 5, 17, 10}, - {10, 0, 0, 5, 18, 21}, - {7, 0, 0, 5, 18, 12}, - {12, 9, 13, 5, 18, 21}, - {12, 0, 13, 5, 18, 21}, - {13, 0, 0, 5, 18, 11}, - {21, 0, 0, 5, 18, 12}, - {7, 0, 0, 5, 19, 36}, - {12, 0, 13, 5, 19, 36}, - {12, 103, 13, 5, 19, 36}, - {12, 9, 13, 5, 19, 36}, - {23, 0, 10, 5, 0, 9}, - {6, 0, 0, 5, 19, 36}, - {12, 107, 13, 5, 19, 36}, - {21, 0, 0, 5, 19, 12}, - {13, 0, 0, 5, 19, 11}, - {21, 0, 0, 5, 19, 17}, - {7, 0, 0, 5, 20, 36}, - {12, 0, 13, 5, 20, 36}, - {12, 118, 13, 5, 20, 36}, - {6, 0, 0, 5, 20, 36}, - {12, 122, 13, 5, 20, 36}, - {13, 0, 0, 5, 20, 11}, - {7, 0, 0, 5, 21, 12}, - {26, 0, 0, 5, 21, 18}, - {21, 0, 0, 5, 21, 18}, - {21, 0, 0, 5, 21, 12}, - {21, 0, 0, 5, 21, 4}, - {21, 0, 0, 5, 21, 17}, - {21, 0, 0, 5, 21, 6}, - {26, 0, 0, 5, 21, 12}, - {12, 220, 13, 5, 21, 21}, - {13, 0, 0, 5, 21, 11}, - {15, 0, 0, 5, 21, 12}, - {26, 0, 0, 5, 21, 17}, - {12, 216, 13, 5, 21, 21}, - {22, 0, 18, 5, 21, 0}, - {18, 0, 18, 5, 21, 1}, - {10, 0, 0, 5, 21, 21}, - {12, 129, 13, 5, 21, 21}, - {12, 130, 13, 5, 21, 21}, - {12, 0, 13, 5, 21, 21}, - {12, 132, 13, 5, 21, 21}, - {10, 0, 0, 5, 21, 17}, - {12, 230, 13, 5, 21, 21}, - {12, 9, 13, 5, 21, 21}, - {26, 0, 0, 5, 0, 12}, - {7, 0, 0, 5, 22, 36}, - {10, 0, 0, 5, 22, 36}, - {12, 0, 13, 5, 22, 36}, - {12, 7, 13, 5, 22, 36}, - {12, 9, 13, 5, 22, 36}, - {13, 0, 0, 5, 22, 11}, - {21, 0, 0, 5, 22, 17}, - {21, 0, 0, 5, 22, 12}, - {12, 220, 13, 5, 22, 36}, - {26, 0, 0, 5, 22, 36}, - {9, 0, 0, 5, 23, 12}, - {5, 0, 0, 5, 23, 12}, - {21, 0, 0, 5, 0, 12}, - {6, 0, 0, 5, 23, 12}, - {7, 0, 0, 2, 24, 25}, - {7, 0, 0, 5, 24, 26}, - {7, 0, 0, 5, 24, 27}, - {7, 0, 0, 5, 25, 12}, - {12, 230, 13, 5, 25, 21}, - {21, 0, 0, 5, 25, 12}, - {21, 0, 0, 5, 25, 17}, - {15, 0, 0, 5, 25, 12}, - {26, 0, 18, 5, 25, 12}, - {9, 0, 0, 5, 26, 12}, - {5, 0, 0, 5, 26, 12}, - {17, 0, 18, 5, 27, 17}, - {7, 0, 0, 5, 27, 12}, - {21, 0, 0, 5, 27, 12}, - {29, 0, 17, 5, 28, 17}, - {7, 0, 0, 5, 28, 12}, - {22, 0, 18, 5, 28, 0}, - {18, 0, 18, 5, 28, 1}, - {7, 0, 0, 5, 29, 12}, - {14, 0, 0, 5, 29, 12}, - {7, 0, 0, 5, 41, 12}, - {12, 0, 13, 5, 41, 21}, - {12, 9, 13, 5, 41, 21}, - {7, 0, 0, 5, 42, 12}, - {12, 0, 13, 5, 42, 21}, - {12, 9, 13, 5, 42, 21}, - {7, 0, 0, 5, 43, 12}, - {12, 0, 13, 5, 43, 21}, - {7, 0, 0, 5, 44, 12}, - {12, 0, 13, 5, 44, 21}, - {7, 0, 0, 5, 30, 36}, - {12, 0, 13, 5, 30, 36}, - {10, 0, 0, 5, 30, 36}, - {12, 9, 13, 5, 30, 36}, - {21, 0, 0, 5, 30, 17}, - {21, 0, 0, 5, 30, 5}, - {6, 0, 0, 5, 30, 36}, - {21, 0, 0, 5, 30, 12}, - {23, 0, 10, 5, 30, 9}, - {12, 230, 13, 5, 30, 36}, - {13, 0, 0, 5, 30, 11}, - {15, 0, 18, 5, 30, 12}, - {21, 0, 18, 5, 31, 12}, - {21, 0, 18, 5, 0, 6}, - {21, 0, 18, 5, 31, 17}, - {21, 0, 18, 5, 0, 17}, - {17, 0, 18, 5, 31, 18}, - {21, 0, 18, 5, 31, 6}, - {12, 0, 13, 5, 31, 21}, - {1, 0, 14, 5, 31, 4}, - {13, 0, 0, 5, 31, 11}, - {7, 0, 0, 5, 31, 12}, - {6, 0, 0, 5, 31, 12}, - {12, 228, 13, 5, 31, 21}, - {7, 0, 0, 5, 45, 12}, - {12, 0, 13, 5, 45, 21}, - {10, 0, 0, 5, 45, 21}, - {12, 222, 13, 5, 45, 21}, - {12, 230, 13, 5, 45, 21}, - {12, 220, 13, 5, 45, 21}, - {26, 0, 18, 5, 45, 12}, - {21, 0, 18, 5, 45, 6}, - {13, 0, 0, 5, 45, 11}, - {7, 0, 0, 5, 46, 36}, - {7, 0, 0, 5, 55, 36}, - {13, 0, 0, 5, 55, 11}, - {15, 0, 0, 5, 55, 36}, - {26, 0, 18, 5, 55, 36}, - {26, 0, 18, 5, 30, 12}, - {7, 0, 0, 5, 53, 12}, - {12, 230, 13, 5, 53, 21}, - {12, 220, 13, 5, 53, 21}, - {10, 0, 0, 5, 53, 21}, - {12, 0, 13, 5, 53, 21}, - {21, 0, 0, 5, 53, 12}, - {7, 0, 0, 5, 77, 36}, - {10, 0, 0, 5, 77, 36}, - {12, 0, 13, 5, 77, 36}, - {12, 9, 13, 5, 77, 36}, - {12, 230, 13, 5, 77, 36}, - {12, 220, 13, 5, 77, 21}, - {13, 0, 0, 5, 77, 11}, - {21, 0, 0, 5, 77, 36}, - {6, 0, 0, 5, 77, 36}, - {11, 0, 13, 5, 40, 21}, - {12, 0, 13, 5, 61, 21}, - {10, 0, 0, 5, 61, 21}, - {7, 0, 0, 5, 61, 12}, - {12, 7, 13, 5, 61, 21}, - {10, 9, 0, 5, 61, 21}, - {13, 0, 0, 5, 61, 11}, - {21, 0, 0, 5, 61, 17}, - {21, 0, 0, 5, 61, 12}, - {26, 0, 0, 5, 61, 12}, - {12, 230, 13, 5, 61, 21}, - {12, 220, 13, 5, 61, 21}, - {12, 0, 13, 5, 66, 21}, - {10, 0, 0, 5, 66, 21}, - {7, 0, 0, 5, 66, 12}, - {10, 9, 0, 5, 66, 21}, - {12, 9, 13, 5, 66, 21}, - {13, 0, 0, 5, 66, 11}, - {7, 0, 0, 5, 92, 12}, - {12, 7, 13, 5, 92, 21}, - {10, 0, 0, 5, 92, 21}, - {12, 0, 13, 5, 92, 21}, - {10, 9, 0, 5, 92, 21}, - {21, 0, 0, 5, 92, 12}, - {7, 0, 0, 5, 67, 12}, - {10, 0, 0, 5, 67, 21}, - {12, 0, 13, 5, 67, 21}, - {12, 7, 13, 5, 67, 21}, - {21, 0, 0, 5, 67, 17}, - {13, 0, 0, 5, 67, 11}, - {13, 0, 0, 5, 68, 11}, - {7, 0, 0, 5, 68, 12}, - {6, 0, 0, 5, 68, 12}, - {21, 0, 0, 5, 68, 17}, - {21, 0, 0, 5, 66, 12}, - {12, 1, 13, 5, 40, 21}, - {10, 0, 0, 5, 0, 21}, - {7, 0, 0, 5, 0, 12}, - {6, 0, 0, 5, 3, 12}, - {12, 234, 13, 5, 40, 21}, - {12, 214, 13, 5, 40, 21}, - {12, 202, 13, 5, 40, 21}, - {12, 232, 13, 5, 40, 21}, - {12, 228, 13, 5, 40, 21}, - {12, 233, 13, 5, 40, 21}, - {8, 0, 0, 5, 2, 12}, - {24, 0, 18, 5, 2, 18}, - {29, 0, 17, 5, 0, 17}, - {29, 0, 17, 5, 0, 4}, - {1, 0, 14, 5, 0, 20}, - {1, 0, 14, 5, 40, 21}, - {1, 0, 14, 5, 40, 40}, - {1, 0, 0, 5, 0, 21}, - {1, 0, 3, 5, 0, 21}, - {17, 0, 18, 4, 0, 17}, - {17, 0, 18, 5, 0, 4}, - {17, 0, 18, 5, 0, 17}, - {17, 0, 18, 4, 0, 19}, - {17, 0, 18, 4, 0, 29}, - {20, 0, 18, 4, 0, 3}, - {19, 0, 18, 4, 0, 3}, - {22, 0, 18, 5, 0, 0}, - {21, 0, 18, 4, 0, 12}, - {21, 0, 18, 4, 0, 15}, - {21, 0, 18, 4, 0, 17}, - {27, 0, 17, 5, 0, 30}, - {28, 0, 15, 5, 0, 30}, - {1, 0, 1, 5, 0, 21}, - {1, 0, 5, 5, 0, 21}, - {1, 0, 7, 5, 0, 21}, - {1, 0, 2, 5, 0, 21}, - {1, 0, 6, 5, 0, 21}, - {21, 0, 10, 4, 0, 10}, - {21, 0, 10, 5, 0, 10}, - {21, 0, 18, 4, 0, 10}, - {21, 0, 18, 5, 0, 10}, - {21, 0, 18, 5, 0, 5}, - {16, 0, 18, 5, 0, 12}, - {25, 0, 12, 5, 0, 8}, - {18, 0, 18, 5, 0, 1}, - {25, 0, 18, 5, 0, 12}, - {1, 0, 14, 5, 0, 22}, - {1, 0, 14, 5, 0, 12}, - {1, 0, 19, 5, 0, 21}, - {1, 0, 20, 5, 0, 21}, - {1, 0, 21, 5, 0, 21}, - {1, 0, 22, 5, 0, 21}, - {1, 0, 14, 5, 0, 21}, - {15, 0, 8, 5, 0, 12}, - {25, 0, 9, 5, 0, 12}, - {6, 0, 0, 4, 1, 29}, - {23, 0, 10, 5, 0, 10}, - {23, 0, 10, 1, 0, 9}, - {2, 0, 18, 5, 102, 9}, - {9, 0, 0, 5, 0, 12}, - {26, 0, 18, 4, 0, 10}, - {26, 0, 18, 4, 0, 29}, - {5, 0, 0, 4, 0, 29}, - {26, 0, 18, 4, 0, 9}, - {9, 0, 0, 4, 1, 29}, - {26, 0, 10, 5, 0, 12}, - {15, 0, 18, 5, 0, 12}, - {15, 0, 18, 4, 0, 12}, - {15, 0, 18, 5, 0, 29}, - {14, 0, 0, 4, 1, 29}, - {14, 0, 0, 5, 1, 12}, - {25, 0, 9, 5, 0, 9}, - {25, 0, 10, 5, 0, 9}, - {25, 0, 18, 5, 0, 15}, - {26, 0, 18, 2, 0, 14}, - {22, 0, 18, 2, 0, 0}, - {18, 0, 18, 2, 0, 1}, - {26, 0, 18, 2, 0, 12}, - {26, 0, 18, 5, 0, 14}, - {26, 0, 0, 4, 0, 29}, - {26, 0, 18, 5, 0, 29}, - {25, 0, 18, 2, 0, 12}, - {26, 0, 18, 4, 0, 14}, - {26, 0, 18, 5, 0, 41}, - {26, 0, 18, 4, 0, 41}, - {26, 0, 18, 2, 0, 41}, - {26, 0, 18, 2, 0, 29}, - {26, 0, 18, 5, 0, 3}, - {26, 0, 18, 5, 0, 6}, - {26, 0, 0, 5, 52, 12}, - {9, 0, 0, 5, 56, 12}, - {5, 0, 0, 5, 56, 12}, - {26, 0, 18, 5, 54, 12}, - {12, 230, 13, 5, 54, 21}, - {21, 0, 18, 5, 54, 6}, - {21, 0, 18, 5, 54, 17}, - {15, 0, 18, 5, 54, 12}, - {7, 0, 0, 5, 57, 12}, - {6, 0, 0, 5, 57, 12}, - {21, 0, 0, 5, 57, 17}, - {12, 9, 13, 5, 57, 21}, - {21, 0, 18, 5, 0, 3}, - {21, 0, 18, 5, 0, 0}, - {17, 0, 18, 5, 0, 12}, - {17, 0, 18, 5, 0, 19}, - {26, 0, 18, 2, 35, 14}, - {29, 0, 17, 0, 0, 17}, - {21, 0, 18, 2, 0, 1}, - {21, 0, 18, 2, 0, 14}, - {6, 0, 0, 2, 35, 5}, - {7, 0, 0, 2, 0, 14}, - {14, 0, 0, 2, 35, 14}, - {17, 0, 18, 2, 0, 5}, - {12, 218, 13, 2, 40, 21}, - {12, 228, 13, 2, 40, 21}, - {12, 232, 13, 2, 40, 21}, - {12, 222, 13, 2, 40, 21}, - {10, 224, 0, 2, 24, 21}, - {17, 0, 18, 2, 0, 14}, - {6, 0, 0, 2, 0, 14}, - {6, 0, 0, 2, 0, 21}, - {7, 0, 0, 2, 0, 5}, - {7, 0, 0, 2, 32, 32}, - {7, 0, 0, 2, 32, 14}, - {12, 8, 13, 2, 40, 21}, - {24, 0, 18, 2, 0, 5}, - {6, 0, 0, 2, 32, 5}, - {7, 0, 0, 2, 33, 32}, - {7, 0, 0, 2, 33, 14}, - {21, 0, 18, 2, 0, 5}, - {6, 0, 0, 2, 0, 32}, - {6, 0, 0, 2, 33, 5}, - {7, 0, 0, 2, 34, 14}, - {7, 0, 0, 2, 24, 14}, - {26, 0, 0, 2, 0, 14}, - {15, 0, 0, 2, 0, 14}, - {26, 0, 0, 2, 24, 14}, - {26, 0, 18, 2, 24, 14}, - {15, 0, 0, 4, 0, 29}, - {15, 0, 18, 2, 0, 14}, - {26, 0, 0, 2, 33, 14}, - {7, 0, 0, 2, 35, 14}, - {2, 0, 18, 2, 102, 14}, - {7, 0, 0, 2, 36, 14}, - {6, 0, 0, 2, 36, 5}, - {26, 0, 18, 2, 36, 14}, - {7, 0, 0, 5, 82, 12}, - {6, 0, 0, 5, 82, 12}, - {21, 0, 0, 5, 82, 17}, - {7, 0, 0, 5, 69, 12}, - {6, 0, 0, 5, 69, 12}, - {21, 0, 18, 5, 69, 17}, - {21, 0, 18, 5, 69, 6}, - {13, 0, 0, 5, 69, 11}, - {7, 0, 0, 5, 3, 12}, - {21, 0, 18, 5, 3, 12}, - {6, 0, 18, 5, 3, 12}, - {7, 0, 0, 5, 83, 12}, - {14, 0, 0, 5, 83, 12}, - {12, 230, 13, 5, 83, 21}, - {21, 0, 0, 5, 83, 12}, - {21, 0, 0, 5, 83, 17}, - {24, 0, 0, 5, 0, 12}, - {7, 0, 0, 5, 58, 12}, - {12, 0, 13, 5, 58, 21}, - {12, 9, 13, 5, 58, 21}, - {10, 0, 0, 5, 58, 21}, - {26, 0, 18, 5, 58, 12}, - {15, 0, 0, 5, 0, 12}, - {7, 0, 0, 5, 64, 12}, - {21, 0, 18, 5, 64, 18}, - {21, 0, 18, 5, 64, 6}, - {10, 0, 0, 5, 70, 21}, - {7, 0, 0, 5, 70, 12}, - {12, 9, 13, 5, 70, 21}, - {12, 0, 13, 5, 70, 21}, - {21, 0, 0, 5, 70, 17}, - {13, 0, 0, 5, 70, 11}, - {21, 0, 0, 5, 9, 18}, - {13, 0, 0, 5, 71, 11}, - {7, 0, 0, 5, 71, 12}, - {12, 0, 13, 5, 71, 21}, - {12, 220, 13, 5, 71, 21}, - {21, 0, 0, 5, 71, 17}, - {7, 0, 0, 5, 72, 12}, - {12, 0, 13, 5, 72, 21}, - {10, 0, 0, 5, 72, 21}, - {10, 9, 0, 5, 72, 21}, - {21, 0, 0, 5, 72, 12}, - {12, 0, 13, 5, 84, 21}, - {10, 0, 0, 5, 84, 21}, - {7, 0, 0, 5, 84, 12}, - {12, 7, 13, 5, 84, 21}, - {10, 9, 0, 5, 84, 21}, - {21, 0, 0, 5, 84, 12}, - {21, 0, 0, 5, 84, 17}, - {13, 0, 0, 5, 84, 11}, - {6, 0, 0, 5, 22, 36}, - {7, 0, 0, 5, 76, 12}, - {12, 0, 13, 5, 76, 21}, - {10, 0, 0, 5, 76, 21}, - {13, 0, 0, 5, 76, 11}, - {21, 0, 0, 5, 76, 12}, - {21, 0, 0, 5, 76, 17}, - {7, 0, 0, 5, 78, 36}, - {12, 230, 13, 5, 78, 36}, - {12, 220, 13, 5, 78, 36}, - {6, 0, 0, 5, 78, 36}, - {21, 0, 0, 5, 78, 36}, - {7, 0, 0, 5, 85, 12}, - {10, 0, 0, 5, 85, 21}, - {12, 0, 13, 5, 85, 21}, - {21, 0, 0, 5, 85, 17}, - {6, 0, 0, 5, 85, 12}, - {12, 9, 13, 5, 85, 21}, - {13, 0, 0, 5, 85, 11}, - {7, 0, 0, 2, 24, 23}, - {7, 0, 0, 2, 24, 24}, - {4, 0, 0, 5, 102, 37}, - {3, 0, 0, 4, 102, 39}, - {12, 26, 13, 5, 5, 21}, - {25, 0, 9, 5, 5, 12}, - {24, 0, 4, 5, 6, 12}, - {12, 0, 13, 4, 40, 21}, - {21, 0, 18, 2, 0, 8}, - {21, 0, 18, 2, 0, 6}, - {21, 0, 18, 2, 0, 15}, - {16, 0, 18, 2, 0, 14}, - {21, 0, 12, 2, 0, 1}, - {21, 0, 12, 2, 0, 5}, - {21, 0, 10, 2, 0, 14}, - {25, 0, 9, 2, 0, 14}, - {17, 0, 9, 2, 0, 14}, - {25, 0, 18, 2, 0, 14}, - {23, 0, 10, 2, 0, 9}, - {21, 0, 10, 2, 0, 10}, - {21, 0, 18, 0, 0, 6}, - {21, 0, 18, 0, 0, 14}, - {21, 0, 10, 0, 0, 14}, - {23, 0, 10, 0, 0, 9}, - {21, 0, 10, 0, 0, 10}, - {22, 0, 18, 0, 0, 0}, - {18, 0, 18, 0, 0, 1}, - {25, 0, 9, 0, 0, 14}, - {21, 0, 12, 0, 0, 1}, - {17, 0, 9, 0, 0, 14}, - {21, 0, 12, 0, 0, 14}, - {13, 0, 8, 0, 0, 14}, - {21, 0, 12, 0, 0, 5}, - {21, 0, 18, 0, 0, 5}, - {25, 0, 18, 0, 0, 14}, - {9, 0, 0, 0, 1, 14}, - {24, 0, 18, 0, 0, 14}, - {16, 0, 18, 0, 0, 14}, - {5, 0, 0, 0, 1, 14}, - {21, 0, 18, 1, 0, 1}, - {22, 0, 18, 1, 0, 0}, - {18, 0, 18, 1, 0, 1}, - {21, 0, 18, 1, 0, 5}, - {7, 0, 0, 1, 33, 14}, - {7, 0, 0, 1, 33, 32}, - {6, 0, 0, 1, 0, 32}, - {6, 0, 0, 1, 0, 5}, - {7, 0, 0, 1, 24, 14}, - {23, 0, 10, 0, 0, 10}, - {26, 0, 18, 0, 0, 14}, - {26, 0, 18, 1, 0, 12}, - {25, 0, 18, 1, 0, 12}, - {1, 0, 18, 5, 0, 21}, - {26, 0, 18, 5, 0, 31}, - {7, 0, 0, 5, 47, 12}, - {14, 0, 18, 5, 2, 12}, - {15, 0, 18, 5, 2, 12}, - {26, 0, 18, 5, 2, 12}, - {26, 0, 0, 5, 2, 12}, - {7, 0, 0, 5, 73, 12}, - {7, 0, 0, 5, 74, 12}, - {7, 0, 0, 5, 37, 12}, - {15, 0, 0, 5, 37, 12}, - {7, 0, 0, 5, 38, 12}, - {14, 0, 0, 5, 38, 12}, - {7, 0, 0, 5, 118, 12}, - {12, 230, 13, 5, 118, 21}, - {7, 0, 0, 5, 48, 12}, - {21, 0, 0, 5, 48, 17}, - {7, 0, 0, 5, 59, 12}, - {21, 0, 0, 5, 59, 17}, - {14, 0, 0, 5, 59, 12}, - {9, 0, 0, 5, 39, 12}, - {5, 0, 0, 5, 39, 12}, - {7, 0, 0, 5, 49, 12}, - {7, 0, 0, 5, 50, 12}, - {13, 0, 0, 5, 50, 11}, - {9, 0, 0, 5, 136, 12}, - {5, 0, 0, 5, 136, 12}, - {7, 0, 0, 5, 106, 12}, - {7, 0, 0, 5, 104, 12}, - {21, 0, 0, 5, 104, 12}, - {7, 0, 0, 5, 110, 12}, - {7, 0, 3, 5, 51, 12}, - {7, 0, 3, 5, 86, 12}, - {21, 0, 3, 5, 86, 17}, - {15, 0, 3, 5, 86, 12}, - {7, 0, 3, 5, 120, 12}, - {26, 0, 3, 5, 120, 12}, - {15, 0, 3, 5, 120, 12}, - {7, 0, 3, 5, 116, 12}, - {15, 0, 3, 5, 116, 12}, - {7, 0, 3, 5, 128, 12}, - {15, 0, 3, 5, 128, 12}, - {7, 0, 3, 5, 63, 12}, - {15, 0, 3, 5, 63, 12}, - {21, 0, 18, 5, 63, 17}, - {7, 0, 3, 5, 75, 12}, - {21, 0, 3, 5, 75, 12}, - {7, 0, 3, 5, 97, 12}, - {7, 0, 3, 5, 96, 12}, - {15, 0, 3, 5, 96, 12}, - {7, 0, 3, 5, 60, 12}, - {12, 0, 13, 5, 60, 21}, - {12, 220, 13, 5, 60, 21}, - {12, 230, 13, 5, 60, 21}, - {12, 1, 13, 5, 60, 21}, - {12, 9, 13, 5, 60, 21}, - {15, 0, 3, 5, 60, 12}, - {21, 0, 3, 5, 60, 17}, - {21, 0, 3, 5, 60, 12}, - {7, 0, 3, 5, 87, 12}, - {15, 0, 3, 5, 87, 12}, - {21, 0, 3, 5, 87, 12}, - {7, 0, 3, 5, 117, 12}, - {15, 0, 3, 5, 117, 12}, - {7, 0, 3, 5, 112, 12}, - {26, 0, 3, 5, 112, 12}, - {12, 230, 13, 5, 112, 21}, - {12, 220, 13, 5, 112, 21}, - {15, 0, 3, 5, 112, 12}, - {21, 0, 3, 5, 112, 17}, - {21, 0, 3, 5, 112, 15}, - {7, 0, 3, 5, 79, 12}, - {21, 0, 18, 5, 79, 17}, - {7, 0, 3, 5, 88, 12}, - {15, 0, 3, 5, 88, 12}, - {7, 0, 3, 5, 89, 12}, - {15, 0, 3, 5, 89, 12}, - {7, 0, 3, 5, 122, 12}, - {21, 0, 3, 5, 122, 12}, - {15, 0, 3, 5, 122, 12}, - {7, 0, 3, 5, 90, 12}, - {9, 0, 3, 5, 130, 12}, - {5, 0, 3, 5, 130, 12}, - {15, 0, 3, 5, 130, 12}, - {7, 0, 4, 5, 144, 12}, - {12, 230, 13, 5, 144, 21}, - {13, 0, 11, 5, 144, 11}, - {15, 0, 11, 5, 6, 12}, - {7, 0, 3, 5, 147, 12}, - {15, 0, 3, 5, 147, 12}, - {7, 0, 4, 5, 148, 12}, - {12, 220, 13, 5, 148, 21}, - {12, 230, 13, 5, 148, 21}, - {15, 0, 4, 5, 148, 12}, - {21, 0, 4, 5, 148, 12}, - {10, 0, 0, 5, 93, 21}, - {12, 0, 13, 5, 93, 21}, - {7, 0, 0, 5, 93, 12}, - {12, 9, 13, 5, 93, 21}, - {21, 0, 0, 5, 93, 17}, - {21, 0, 0, 5, 93, 12}, - {15, 0, 18, 5, 93, 12}, - {13, 0, 0, 5, 93, 11}, - {12, 0, 13, 5, 91, 21}, - {10, 0, 0, 5, 91, 21}, - {7, 0, 0, 5, 91, 12}, - {12, 9, 13, 5, 91, 21}, - {12, 7, 13, 5, 91, 21}, - {21, 0, 0, 5, 91, 12}, - {1, 0, 0, 5, 91, 12}, - {21, 0, 0, 5, 91, 17}, - {7, 0, 0, 5, 100, 12}, - {13, 0, 0, 5, 100, 11}, - {12, 230, 13, 5, 95, 21}, - {7, 0, 0, 5, 95, 12}, - {12, 0, 13, 5, 95, 21}, - {10, 0, 0, 5, 95, 21}, - {12, 9, 13, 5, 95, 21}, - {13, 0, 0, 5, 95, 11}, - {21, 0, 0, 5, 95, 17}, - {7, 0, 0, 5, 111, 12}, - {12, 7, 13, 5, 111, 21}, - {21, 0, 0, 5, 111, 12}, - {21, 0, 0, 5, 111, 18}, - {12, 0, 13, 5, 99, 21}, - {10, 0, 0, 5, 99, 21}, - {7, 0, 0, 5, 99, 12}, - {10, 9, 0, 5, 99, 21}, - {21, 0, 0, 5, 99, 17}, - {21, 0, 0, 5, 99, 12}, - {12, 7, 13, 5, 99, 21}, - {13, 0, 0, 5, 99, 11}, - {21, 0, 0, 5, 99, 18}, - {15, 0, 0, 5, 18, 12}, - {7, 0, 0, 5, 108, 12}, - {10, 0, 0, 5, 108, 21}, - {12, 0, 13, 5, 108, 21}, - {10, 9, 0, 5, 108, 21}, - {12, 7, 13, 5, 108, 21}, - {21, 0, 0, 5, 108, 17}, - {21, 0, 0, 5, 108, 12}, - {7, 0, 0, 5, 129, 12}, - {21, 0, 0, 5, 129, 17}, - {7, 0, 0, 5, 109, 12}, - {12, 0, 13, 5, 109, 21}, - {10, 0, 0, 5, 109, 21}, - {12, 7, 13, 5, 109, 21}, - {12, 9, 13, 5, 109, 21}, - {13, 0, 0, 5, 109, 11}, - {12, 0, 13, 5, 107, 21}, - {10, 0, 0, 5, 107, 21}, - {7, 0, 0, 5, 107, 12}, - {12, 7, 13, 5, 40, 21}, - {12, 7, 13, 5, 107, 21}, - {10, 9, 0, 5, 107, 21}, - {12, 230, 13, 5, 107, 21}, - {7, 0, 0, 5, 135, 12}, - {10, 0, 0, 5, 135, 21}, - {12, 0, 13, 5, 135, 21}, - {12, 9, 13, 5, 135, 21}, - {12, 7, 13, 5, 135, 21}, - {21, 0, 0, 5, 135, 17}, - {21, 0, 0, 5, 135, 12}, - {13, 0, 0, 5, 135, 11}, - {12, 230, 13, 5, 135, 21}, - {7, 0, 0, 5, 124, 12}, - {10, 0, 0, 5, 124, 21}, - {12, 0, 13, 5, 124, 21}, - {12, 9, 13, 5, 124, 21}, - {12, 7, 13, 5, 124, 21}, - {21, 0, 0, 5, 124, 12}, - {13, 0, 0, 5, 124, 11}, - {7, 0, 0, 5, 123, 12}, - {10, 0, 0, 5, 123, 21}, - {12, 0, 13, 5, 123, 21}, - {12, 9, 13, 5, 123, 21}, - {12, 7, 13, 5, 123, 21}, - {21, 0, 0, 5, 123, 18}, - {21, 0, 0, 5, 123, 17}, - {21, 0, 0, 5, 123, 6}, - {21, 0, 0, 5, 123, 12}, - {7, 0, 0, 5, 114, 12}, - {10, 0, 0, 5, 114, 21}, - {12, 0, 13, 5, 114, 21}, - {12, 9, 13, 5, 114, 21}, - {21, 0, 0, 5, 114, 17}, - {21, 0, 0, 5, 114, 12}, - {13, 0, 0, 5, 114, 11}, - {21, 0, 18, 5, 31, 18}, - {7, 0, 0, 5, 101, 12}, - {12, 0, 13, 5, 101, 21}, - {10, 0, 0, 5, 101, 21}, - {10, 9, 0, 5, 101, 21}, - {12, 7, 13, 5, 101, 21}, - {13, 0, 0, 5, 101, 11}, - {7, 0, 0, 5, 126, 36}, - {12, 0, 13, 5, 126, 36}, - {10, 0, 0, 5, 126, 36}, - {12, 9, 13, 5, 126, 36}, - {13, 0, 0, 5, 126, 11}, - {15, 0, 0, 5, 126, 36}, - {21, 0, 0, 5, 126, 17}, - {26, 0, 0, 5, 126, 36}, - {7, 0, 0, 5, 142, 12}, - {10, 0, 0, 5, 142, 21}, - {12, 0, 13, 5, 142, 21}, - {12, 9, 13, 5, 142, 21}, - {12, 7, 13, 5, 142, 21}, - {21, 0, 0, 5, 142, 12}, - {9, 0, 0, 5, 125, 12}, - {5, 0, 0, 5, 125, 12}, - {13, 0, 0, 5, 125, 11}, - {15, 0, 0, 5, 125, 12}, - {7, 0, 0, 5, 125, 12}, - {7, 0, 0, 5, 141, 12}, - {12, 0, 13, 5, 141, 21}, - {12, 0, 0, 5, 141, 21}, - {12, 9, 13, 5, 141, 21}, - {10, 0, 0, 5, 141, 21}, - {21, 0, 0, 5, 141, 18}, - {21, 0, 0, 5, 141, 12}, - {21, 0, 0, 5, 141, 17}, - {7, 0, 0, 5, 140, 12}, - {12, 0, 13, 5, 140, 21}, - {10, 0, 0, 5, 140, 21}, - {12, 9, 13, 5, 140, 21}, - {21, 0, 0, 5, 140, 17}, - {21, 0, 0, 5, 140, 18}, - {7, 0, 0, 5, 121, 12}, - {7, 0, 0, 5, 133, 12}, - {10, 0, 0, 5, 133, 21}, - {12, 0, 13, 5, 133, 21}, - {12, 9, 0, 5, 133, 21}, - {21, 0, 0, 5, 133, 17}, - {13, 0, 0, 5, 133, 11}, - {15, 0, 0, 5, 133, 12}, - {21, 0, 0, 5, 134, 18}, - {21, 0, 0, 5, 134, 6}, - {7, 0, 0, 5, 134, 12}, - {12, 0, 13, 5, 134, 21}, - {10, 0, 0, 5, 134, 21}, - {7, 0, 0, 5, 138, 12}, - {12, 0, 13, 5, 138, 21}, - {12, 7, 13, 5, 138, 21}, - {12, 9, 13, 5, 138, 21}, - {13, 0, 0, 5, 138, 11}, - {7, 0, 0, 5, 143, 12}, - {10, 0, 0, 5, 143, 21}, - {12, 0, 13, 5, 143, 21}, - {12, 9, 13, 5, 143, 21}, - {13, 0, 0, 5, 143, 11}, - {7, 0, 0, 5, 145, 12}, - {12, 0, 13, 5, 145, 21}, - {10, 0, 0, 5, 145, 21}, - {21, 0, 0, 5, 145, 12}, - {7, 0, 0, 5, 62, 12}, - {14, 0, 0, 5, 62, 12}, - {21, 0, 0, 5, 62, 17}, - {7, 0, 0, 5, 80, 12}, - {7, 0, 0, 5, 80, 0}, - {7, 0, 0, 5, 80, 1}, - {7, 0, 0, 5, 127, 12}, - {7, 0, 0, 5, 127, 0}, - {7, 0, 0, 5, 127, 1}, - {7, 0, 0, 5, 115, 12}, - {13, 0, 0, 5, 115, 11}, - {21, 0, 0, 5, 115, 17}, - {7, 0, 0, 5, 103, 12}, - {12, 1, 13, 5, 103, 21}, - {21, 0, 0, 5, 103, 17}, - {7, 0, 0, 5, 119, 12}, - {12, 230, 13, 5, 119, 21}, - {21, 0, 0, 5, 119, 17}, - {21, 0, 0, 5, 119, 12}, - {26, 0, 0, 5, 119, 12}, - {6, 0, 0, 5, 119, 12}, - {13, 0, 0, 5, 119, 11}, - {15, 0, 0, 5, 119, 12}, - {9, 0, 0, 5, 146, 12}, - {5, 0, 0, 5, 146, 12}, - {15, 0, 0, 5, 146, 12}, - {21, 0, 0, 5, 146, 17}, - {21, 0, 0, 5, 146, 12}, - {7, 0, 0, 5, 98, 12}, - {10, 0, 0, 5, 98, 21}, - {12, 0, 13, 5, 98, 21}, - {6, 0, 0, 5, 98, 12}, - {6, 0, 0, 2, 137, 5}, - {6, 0, 0, 2, 139, 5}, - {7, 0, 0, 2, 137, 14}, - {7, 0, 0, 2, 139, 14}, - {7, 0, 0, 5, 105, 12}, - {26, 0, 0, 5, 105, 12}, - {12, 0, 13, 5, 105, 21}, - {12, 1, 13, 5, 105, 21}, - {21, 0, 0, 5, 105, 17}, - {10, 216, 0, 5, 0, 21}, - {10, 226, 0, 5, 0, 21}, - {12, 230, 13, 5, 2, 21}, - {25, 0, 0, 5, 0, 12}, - {13, 0, 8, 5, 0, 11}, - {26, 0, 0, 5, 131, 12}, - {12, 0, 13, 5, 131, 21}, - {21, 0, 0, 5, 131, 17}, - {21, 0, 0, 5, 131, 12}, - {12, 230, 13, 5, 56, 21}, - {7, 0, 3, 5, 113, 12}, - {15, 0, 3, 5, 113, 12}, - {12, 220, 13, 5, 113, 21}, - {9, 0, 3, 5, 132, 12}, - {5, 0, 3, 5, 132, 12}, - {12, 230, 13, 5, 132, 21}, - {12, 7, 13, 5, 132, 21}, - {13, 0, 3, 5, 132, 11}, - {21, 0, 3, 5, 132, 0}, - {15, 0, 4, 5, 0, 12}, - {26, 0, 4, 5, 0, 10}, - {23, 0, 4, 5, 0, 10}, - {2, 0, 18, 5, 102, 14}, - {26, 0, 0, 2, 0, 29}, - {26, 0, 0, 5, 0, 28}, - {26, 0, 0, 2, 32, 14}, - {24, 0, 18, 2, 0, 42}, - {26, 0, 18, 5, 0, 5}, -}; - -#define BIDI_MIRROR_LEN 420 -static const MirrorPair mirror_pairs[] = { - {40, 41}, - {41, 40}, - {60, 62}, - {62, 60}, - {91, 93}, - {93, 91}, - {123, 125}, - {125, 123}, - {171, 187}, - {187, 171}, - {3898, 3899}, - {3899, 3898}, - {3900, 3901}, - {3901, 3900}, - {5787, 5788}, - {5788, 5787}, - {8249, 8250}, - {8250, 8249}, - {8261, 8262}, - {8262, 8261}, - {8317, 8318}, - {8318, 8317}, - {8333, 8334}, - {8334, 8333}, - {8712, 8715}, - {8713, 8716}, - {8714, 8717}, - {8715, 8712}, - {8716, 8713}, - {8717, 8714}, - {8725, 10741}, - {8735, 11262}, - {8736, 10659}, - {8737, 10651}, - {8738, 10656}, - {8740, 10990}, - {8764, 8765}, - {8765, 8764}, - {8771, 8909}, - {8773, 8780}, - {8780, 8773}, - {8786, 8787}, - {8787, 8786}, - {8788, 8789}, - {8789, 8788}, - {8804, 8805}, - {8805, 8804}, - {8806, 8807}, - {8807, 8806}, - {8808, 8809}, - {8809, 8808}, - {8810, 8811}, - {8811, 8810}, - {8814, 8815}, - {8815, 8814}, - {8816, 8817}, - {8817, 8816}, - {8818, 8819}, - {8819, 8818}, - {8820, 8821}, - {8821, 8820}, - {8822, 8823}, - {8823, 8822}, - {8824, 8825}, - {8825, 8824}, - {8826, 8827}, - {8827, 8826}, - {8828, 8829}, - {8829, 8828}, - {8830, 8831}, - {8831, 8830}, - {8832, 8833}, - {8833, 8832}, - {8834, 8835}, - {8835, 8834}, - {8836, 8837}, - {8837, 8836}, - {8838, 8839}, - {8839, 8838}, - {8840, 8841}, - {8841, 8840}, - {8842, 8843}, - {8843, 8842}, - {8847, 8848}, - {8848, 8847}, - {8849, 8850}, - {8850, 8849}, - {8856, 10680}, - {8866, 8867}, - {8867, 8866}, - {8870, 10974}, - {8872, 10980}, - {8873, 10979}, - {8875, 10981}, - {8880, 8881}, - {8881, 8880}, - {8882, 8883}, - {8883, 8882}, - {8884, 8885}, - {8885, 8884}, - {8886, 8887}, - {8887, 8886}, - {8888, 10204}, - {8905, 8906}, - {8906, 8905}, - {8907, 8908}, - {8908, 8907}, - {8909, 8771}, - {8912, 8913}, - {8913, 8912}, - {8918, 8919}, - {8919, 8918}, - {8920, 8921}, - {8921, 8920}, - {8922, 8923}, - {8923, 8922}, - {8924, 8925}, - {8925, 8924}, - {8926, 8927}, - {8927, 8926}, - {8928, 8929}, - {8929, 8928}, - {8930, 8931}, - {8931, 8930}, - {8932, 8933}, - {8933, 8932}, - {8934, 8935}, - {8935, 8934}, - {8936, 8937}, - {8937, 8936}, - {8938, 8939}, - {8939, 8938}, - {8940, 8941}, - {8941, 8940}, - {8944, 8945}, - {8945, 8944}, - {8946, 8954}, - {8947, 8955}, - {8948, 8956}, - {8950, 8957}, - {8951, 8958}, - {8954, 8946}, - {8955, 8947}, - {8956, 8948}, - {8957, 8950}, - {8958, 8951}, - {8968, 8969}, - {8969, 8968}, - {8970, 8971}, - {8971, 8970}, - {9001, 9002}, - {9002, 9001}, - {10088, 10089}, - {10089, 10088}, - {10090, 10091}, - {10091, 10090}, - {10092, 10093}, - {10093, 10092}, - {10094, 10095}, - {10095, 10094}, - {10096, 10097}, - {10097, 10096}, - {10098, 10099}, - {10099, 10098}, - {10100, 10101}, - {10101, 10100}, - {10179, 10180}, - {10180, 10179}, - {10181, 10182}, - {10182, 10181}, - {10184, 10185}, - {10185, 10184}, - {10187, 10189}, - {10189, 10187}, - {10197, 10198}, - {10198, 10197}, - {10204, 8888}, - {10205, 10206}, - {10206, 10205}, - {10210, 10211}, - {10211, 10210}, - {10212, 10213}, - {10213, 10212}, - {10214, 10215}, - {10215, 10214}, - {10216, 10217}, - {10217, 10216}, - {10218, 10219}, - {10219, 10218}, - {10220, 10221}, - {10221, 10220}, - {10222, 10223}, - {10223, 10222}, - {10627, 10628}, - {10628, 10627}, - {10629, 10630}, - {10630, 10629}, - {10631, 10632}, - {10632, 10631}, - {10633, 10634}, - {10634, 10633}, - {10635, 10636}, - {10636, 10635}, - {10637, 10640}, - {10638, 10639}, - {10639, 10638}, - {10640, 10637}, - {10641, 10642}, - {10642, 10641}, - {10643, 10644}, - {10644, 10643}, - {10645, 10646}, - {10646, 10645}, - {10647, 10648}, - {10648, 10647}, - {10651, 8737}, - {10656, 8738}, - {10659, 8736}, - {10660, 10661}, - {10661, 10660}, - {10664, 10665}, - {10665, 10664}, - {10666, 10667}, - {10667, 10666}, - {10668, 10669}, - {10669, 10668}, - {10670, 10671}, - {10671, 10670}, - {10680, 8856}, - {10688, 10689}, - {10689, 10688}, - {10692, 10693}, - {10693, 10692}, - {10703, 10704}, - {10704, 10703}, - {10705, 10706}, - {10706, 10705}, - {10708, 10709}, - {10709, 10708}, - {10712, 10713}, - {10713, 10712}, - {10714, 10715}, - {10715, 10714}, - {10728, 10729}, - {10729, 10728}, - {10741, 8725}, - {10744, 10745}, - {10745, 10744}, - {10748, 10749}, - {10749, 10748}, - {10795, 10796}, - {10796, 10795}, - {10797, 10798}, - {10798, 10797}, - {10804, 10805}, - {10805, 10804}, - {10812, 10813}, - {10813, 10812}, - {10852, 10853}, - {10853, 10852}, - {10873, 10874}, - {10874, 10873}, - {10875, 10876}, - {10876, 10875}, - {10877, 10878}, - {10878, 10877}, - {10879, 10880}, - {10880, 10879}, - {10881, 10882}, - {10882, 10881}, - {10883, 10884}, - {10884, 10883}, - {10885, 10886}, - {10886, 10885}, - {10887, 10888}, - {10888, 10887}, - {10889, 10890}, - {10890, 10889}, - {10891, 10892}, - {10892, 10891}, - {10893, 10894}, - {10894, 10893}, - {10895, 10896}, - {10896, 10895}, - {10897, 10898}, - {10898, 10897}, - {10899, 10900}, - {10900, 10899}, - {10901, 10902}, - {10902, 10901}, - {10903, 10904}, - {10904, 10903}, - {10905, 10906}, - {10906, 10905}, - {10907, 10908}, - {10908, 10907}, - {10909, 10910}, - {10910, 10909}, - {10911, 10912}, - {10912, 10911}, - {10913, 10914}, - {10914, 10913}, - {10918, 10919}, - {10919, 10918}, - {10920, 10921}, - {10921, 10920}, - {10922, 10923}, - {10923, 10922}, - {10924, 10925}, - {10925, 10924}, - {10927, 10928}, - {10928, 10927}, - {10929, 10930}, - {10930, 10929}, - {10931, 10932}, - {10932, 10931}, - {10933, 10934}, - {10934, 10933}, - {10935, 10936}, - {10936, 10935}, - {10937, 10938}, - {10938, 10937}, - {10939, 10940}, - {10940, 10939}, - {10941, 10942}, - {10942, 10941}, - {10943, 10944}, - {10944, 10943}, - {10945, 10946}, - {10946, 10945}, - {10947, 10948}, - {10948, 10947}, - {10949, 10950}, - {10950, 10949}, - {10951, 10952}, - {10952, 10951}, - {10953, 10954}, - {10954, 10953}, - {10955, 10956}, - {10956, 10955}, - {10957, 10958}, - {10958, 10957}, - {10959, 10960}, - {10960, 10959}, - {10961, 10962}, - {10962, 10961}, - {10963, 10964}, - {10964, 10963}, - {10965, 10966}, - {10966, 10965}, - {10974, 8870}, - {10979, 8873}, - {10980, 8872}, - {10981, 8875}, - {10988, 10989}, - {10989, 10988}, - {10990, 8740}, - {10999, 11000}, - {11000, 10999}, - {11001, 11002}, - {11002, 11001}, - {11262, 8735}, - {11778, 11779}, - {11779, 11778}, - {11780, 11781}, - {11781, 11780}, - {11785, 11786}, - {11786, 11785}, - {11788, 11789}, - {11789, 11788}, - {11804, 11805}, - {11805, 11804}, - {11808, 11809}, - {11809, 11808}, - {11810, 11811}, - {11811, 11810}, - {11812, 11813}, - {11813, 11812}, - {11814, 11815}, - {11815, 11814}, - {11816, 11817}, - {11817, 11816}, - {12296, 12297}, - {12297, 12296}, - {12298, 12299}, - {12299, 12298}, - {12300, 12301}, - {12301, 12300}, - {12302, 12303}, - {12303, 12302}, - {12304, 12305}, - {12305, 12304}, - {12308, 12309}, - {12309, 12308}, - {12310, 12311}, - {12311, 12310}, - {12312, 12313}, - {12313, 12312}, - {12314, 12315}, - {12315, 12314}, - {65113, 65114}, - {65114, 65113}, - {65115, 65116}, - {65116, 65115}, - {65117, 65118}, - {65118, 65117}, - {65124, 65125}, - {65125, 65124}, - {65288, 65289}, - {65289, 65288}, - {65308, 65310}, - {65310, 65308}, - {65339, 65341}, - {65341, 65339}, - {65371, 65373}, - {65373, 65371}, - {65375, 65376}, - {65376, 65375}, - {65378, 65379}, - {65379, 65378}, -}; - -#define BIDI_BRACKET_LEN 120 -static const BracketPair bracket_pairs[] = { - {40, 41, 0}, - {41, 40, 1}, - {91, 93, 0}, - {93, 91, 1}, - {123, 125, 0}, - {125, 123, 1}, - {3898, 3899, 0}, - {3899, 3898, 1}, - {3900, 3901, 0}, - {3901, 3900, 1}, - {5787, 5788, 0}, - {5788, 5787, 1}, - {8261, 8262, 0}, - {8262, 8261, 1}, - {8317, 8318, 0}, - {8318, 8317, 1}, - {8333, 8334, 0}, - {8334, 8333, 1}, - {8968, 8969, 0}, - {8969, 8968, 1}, - {8970, 8971, 0}, - {8971, 8970, 1}, - {9001, 9002, 0}, - {9002, 9001, 1}, - {10088, 10089, 0}, - {10089, 10088, 1}, - {10090, 10091, 0}, - {10091, 10090, 1}, - {10092, 10093, 0}, - {10093, 10092, 1}, - {10094, 10095, 0}, - {10095, 10094, 1}, - {10096, 10097, 0}, - {10097, 10096, 1}, - {10098, 10099, 0}, - {10099, 10098, 1}, - {10100, 10101, 0}, - {10101, 10100, 1}, - {10181, 10182, 0}, - {10182, 10181, 1}, - {10214, 10215, 0}, - {10215, 10214, 1}, - {10216, 10217, 0}, - {10217, 10216, 1}, - {10218, 10219, 0}, - {10219, 10218, 1}, - {10220, 10221, 0}, - {10221, 10220, 1}, - {10222, 10223, 0}, - {10223, 10222, 1}, - {10627, 10628, 0}, - {10628, 10627, 1}, - {10629, 10630, 0}, - {10630, 10629, 1}, - {10631, 10632, 0}, - {10632, 10631, 1}, - {10633, 10634, 0}, - {10634, 10633, 1}, - {10635, 10636, 0}, - {10636, 10635, 1}, - {10637, 10640, 0}, - {10638, 10639, 1}, - {10639, 10638, 0}, - {10640, 10637, 1}, - {10641, 10642, 0}, - {10642, 10641, 1}, - {10643, 10644, 0}, - {10644, 10643, 1}, - {10645, 10646, 0}, - {10646, 10645, 1}, - {10647, 10648, 0}, - {10648, 10647, 1}, - {10712, 10713, 0}, - {10713, 10712, 1}, - {10714, 10715, 0}, - {10715, 10714, 1}, - {10748, 10749, 0}, - {10749, 10748, 1}, - {11810, 11811, 0}, - {11811, 11810, 1}, - {11812, 11813, 0}, - {11813, 11812, 1}, - {11814, 11815, 0}, - {11815, 11814, 1}, - {11816, 11817, 0}, - {11817, 11816, 1}, - {12296, 12297, 0}, - {12297, 12296, 1}, - {12298, 12299, 0}, - {12299, 12298, 1}, - {12300, 12301, 0}, - {12301, 12300, 1}, - {12302, 12303, 0}, - {12303, 12302, 1}, - {12304, 12305, 0}, - {12305, 12304, 1}, - {12308, 12309, 0}, - {12309, 12308, 1}, - {12310, 12311, 0}, - {12311, 12310, 1}, - {12312, 12313, 0}, - {12313, 12312, 1}, - {12314, 12315, 0}, - {12315, 12314, 1}, - {65113, 65114, 0}, - {65114, 65113, 1}, - {65115, 65116, 0}, - {65116, 65115, 1}, - {65117, 65118, 0}, - {65118, 65117, 1}, - {65288, 65289, 0}, - {65289, 65288, 1}, - {65339, 65341, 0}, - {65341, 65339, 1}, - {65371, 65373, 0}, - {65373, 65371, 1}, - {65375, 65376, 0}, - {65376, 65375, 1}, - {65378, 65379, 0}, - {65379, 65378, 1}, -}; - -/* Reindexing of NFC first characters. */ -#define TOTAL_FIRST 376 -#define TOTAL_LAST 62 -static const Reindex nfc_first[] = { - { 60, 2, 0}, - { 65, 15, 3}, - { 82, 8, 19}, - { 97, 15, 28}, - { 114, 8, 44}, - { 168, 0, 53}, - { 194, 0, 54}, - { 196, 3, 55}, - { 202, 0, 59}, - { 207, 0, 60}, - { 212, 2, 61}, - { 216, 0, 64}, - { 220, 0, 65}, - { 226, 0, 66}, - { 228, 3, 67}, - { 234, 0, 71}, - { 239, 0, 72}, - { 244, 2, 73}, - { 248, 0, 76}, - { 252, 0, 77}, - { 258, 1, 78}, - { 274, 1, 80}, - { 332, 1, 82}, - { 346, 1, 84}, - { 352, 1, 86}, - { 360, 3, 88}, - { 383, 0, 92}, - { 416, 1, 93}, - { 431, 1, 95}, - { 439, 0, 97}, - { 490, 1, 98}, - { 550, 3, 100}, - { 558, 1, 104}, - { 658, 0, 106}, - { 913, 0, 107}, - { 917, 0, 108}, - { 919, 0, 109}, - { 921, 0, 110}, - { 927, 0, 111}, - { 929, 0, 112}, - { 933, 0, 113}, - { 937, 0, 114}, - { 940, 0, 115}, - { 942, 0, 116}, - { 945, 0, 117}, - { 949, 0, 118}, - { 951, 0, 119}, - { 953, 0, 120}, - { 959, 0, 121}, - { 961, 0, 122}, - { 965, 0, 123}, - { 969, 2, 124}, - { 974, 0, 127}, - { 978, 0, 128}, - { 1030, 0, 129}, - { 1040, 0, 130}, - { 1043, 0, 131}, - { 1045, 3, 132}, - { 1050, 0, 136}, - { 1054, 0, 137}, - { 1059, 0, 138}, - { 1063, 0, 139}, - { 1067, 0, 140}, - { 1069, 0, 141}, - { 1072, 0, 142}, - { 1075, 0, 143}, - { 1077, 3, 144}, - { 1082, 0, 148}, - { 1086, 0, 149}, - { 1091, 0, 150}, - { 1095, 0, 151}, - { 1099, 0, 152}, - { 1101, 0, 153}, - { 1110, 0, 154}, - { 1140, 1, 155}, - { 1240, 1, 157}, - { 1256, 1, 159}, - { 1575, 0, 161}, - { 1608, 0, 162}, - { 1610, 0, 163}, - { 1729, 0, 164}, - { 1746, 0, 165}, - { 1749, 0, 166}, - { 2344, 0, 167}, - { 2352, 0, 168}, - { 2355, 0, 169}, - { 2503, 0, 170}, - { 2887, 0, 171}, - { 2962, 0, 172}, - { 3014, 1, 173}, - { 3142, 0, 175}, - { 3263, 0, 176}, - { 3270, 0, 177}, - { 3274, 0, 178}, - { 3398, 1, 179}, - { 3545, 0, 181}, - { 3548, 0, 182}, - { 4133, 0, 183}, - { 6917, 0, 184}, - { 6919, 0, 185}, - { 6921, 0, 186}, - { 6923, 0, 187}, - { 6925, 0, 188}, - { 6929, 0, 189}, - { 6970, 0, 190}, - { 6972, 0, 191}, - { 6974, 1, 192}, - { 6978, 0, 194}, - { 7734, 1, 195}, - { 7770, 1, 197}, - { 7778, 1, 199}, - { 7840, 1, 201}, - { 7864, 1, 203}, - { 7884, 1, 205}, - { 7936, 17, 207}, - { 7960, 1, 225}, - { 7968, 17, 227}, - { 7992, 1, 245}, - { 8000, 1, 247}, - { 8008, 1, 249}, - { 8016, 1, 251}, - { 8025, 0, 253}, - { 8032, 16, 254}, - { 8052, 0, 271}, - { 8060, 0, 272}, - { 8118, 0, 273}, - { 8127, 0, 274}, - { 8134, 0, 275}, - { 8182, 0, 276}, - { 8190, 0, 277}, - { 8592, 0, 278}, - { 8594, 0, 279}, - { 8596, 0, 280}, - { 8656, 0, 281}, - { 8658, 0, 282}, - { 8660, 0, 283}, - { 8707, 0, 284}, - { 8712, 0, 285}, - { 8715, 0, 286}, - { 8739, 0, 287}, - { 8741, 0, 288}, - { 8764, 0, 289}, - { 8771, 0, 290}, - { 8773, 0, 291}, - { 8776, 0, 292}, - { 8781, 0, 293}, - { 8801, 0, 294}, - { 8804, 1, 295}, - { 8818, 1, 297}, - { 8822, 1, 299}, - { 8826, 3, 301}, - { 8834, 1, 305}, - { 8838, 1, 307}, - { 8849, 1, 309}, - { 8866, 0, 311}, - { 8872, 1, 312}, - { 8875, 0, 314}, - { 8882, 3, 315}, - { 12358, 0, 319}, - { 12363, 0, 320}, - { 12365, 0, 321}, - { 12367, 0, 322}, - { 12369, 0, 323}, - { 12371, 0, 324}, - { 12373, 0, 325}, - { 12375, 0, 326}, - { 12377, 0, 327}, - { 12379, 0, 328}, - { 12381, 0, 329}, - { 12383, 0, 330}, - { 12385, 0, 331}, - { 12388, 0, 332}, - { 12390, 0, 333}, - { 12392, 0, 334}, - { 12399, 0, 335}, - { 12402, 0, 336}, - { 12405, 0, 337}, - { 12408, 0, 338}, - { 12411, 0, 339}, - { 12445, 0, 340}, - { 12454, 0, 341}, - { 12459, 0, 342}, - { 12461, 0, 343}, - { 12463, 0, 344}, - { 12465, 0, 345}, - { 12467, 0, 346}, - { 12469, 0, 347}, - { 12471, 0, 348}, - { 12473, 0, 349}, - { 12475, 0, 350}, - { 12477, 0, 351}, - { 12479, 0, 352}, - { 12481, 0, 353}, - { 12484, 0, 354}, - { 12486, 0, 355}, - { 12488, 0, 356}, - { 12495, 0, 357}, - { 12498, 0, 358}, - { 12501, 0, 359}, - { 12504, 0, 360}, - { 12507, 0, 361}, - { 12527, 3, 362}, - { 12541, 0, 366}, - { 69785, 0, 367}, - { 69787, 0, 368}, - { 69797, 0, 369}, - { 69937, 1, 370}, - { 70471, 0, 372}, - { 70841, 0, 373}, - { 71096, 1, 374}, - {0,0,0} -}; - -static const Reindex nfc_last[] = { - { 768, 4, 0}, - { 774, 6, 5}, - { 783, 0, 12}, - { 785, 0, 13}, - { 787, 1, 14}, - { 795, 0, 16}, - { 803, 5, 17}, - { 813, 1, 23}, - { 816, 1, 25}, - { 824, 0, 27}, - { 834, 0, 28}, - { 837, 0, 29}, - { 1619, 2, 30}, - { 2364, 0, 33}, - { 2494, 0, 34}, - { 2519, 0, 35}, - { 2878, 0, 36}, - { 2902, 1, 37}, - { 3006, 0, 39}, - { 3031, 0, 40}, - { 3158, 0, 41}, - { 3266, 0, 42}, - { 3285, 1, 43}, - { 3390, 0, 45}, - { 3415, 0, 46}, - { 3530, 0, 47}, - { 3535, 0, 48}, - { 3551, 0, 49}, - { 4142, 0, 50}, - { 6965, 0, 51}, - { 12441, 1, 52}, - { 69818, 0, 54}, - { 69927, 0, 55}, - { 70462, 0, 56}, - { 70487, 0, 57}, - { 70832, 0, 58}, - { 70842, 0, 59}, - { 70845, 0, 60}, - { 71087, 0, 61}, - {0,0,0} -}; - -#define UCDN_EAST_ASIAN_F 0 -#define UCDN_EAST_ASIAN_H 1 -#define UCDN_EAST_ASIAN_W 2 -#define UCDN_EAST_ASIAN_NA 3 -#define UCDN_EAST_ASIAN_A 4 -#define UCDN_EAST_ASIAN_N 5 - -#define UCDN_SCRIPT_COMMON 0 -#define UCDN_SCRIPT_LATIN 1 -#define UCDN_SCRIPT_GREEK 2 -#define UCDN_SCRIPT_CYRILLIC 3 -#define UCDN_SCRIPT_ARMENIAN 4 -#define UCDN_SCRIPT_HEBREW 5 -#define UCDN_SCRIPT_ARABIC 6 -#define UCDN_SCRIPT_SYRIAC 7 -#define UCDN_SCRIPT_THAANA 8 -#define UCDN_SCRIPT_DEVANAGARI 9 -#define UCDN_SCRIPT_BENGALI 10 -#define UCDN_SCRIPT_GURMUKHI 11 -#define UCDN_SCRIPT_GUJARATI 12 -#define UCDN_SCRIPT_ORIYA 13 -#define UCDN_SCRIPT_TAMIL 14 -#define UCDN_SCRIPT_TELUGU 15 -#define UCDN_SCRIPT_KANNADA 16 -#define UCDN_SCRIPT_MALAYALAM 17 -#define UCDN_SCRIPT_SINHALA 18 -#define UCDN_SCRIPT_THAI 19 -#define UCDN_SCRIPT_LAO 20 -#define UCDN_SCRIPT_TIBETAN 21 -#define UCDN_SCRIPT_MYANMAR 22 -#define UCDN_SCRIPT_GEORGIAN 23 -#define UCDN_SCRIPT_HANGUL 24 -#define UCDN_SCRIPT_ETHIOPIC 25 -#define UCDN_SCRIPT_CHEROKEE 26 -#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27 -#define UCDN_SCRIPT_OGHAM 28 -#define UCDN_SCRIPT_RUNIC 29 -#define UCDN_SCRIPT_KHMER 30 -#define UCDN_SCRIPT_MONGOLIAN 31 -#define UCDN_SCRIPT_HIRAGANA 32 -#define UCDN_SCRIPT_KATAKANA 33 -#define UCDN_SCRIPT_BOPOMOFO 34 -#define UCDN_SCRIPT_HAN 35 -#define UCDN_SCRIPT_YI 36 -#define UCDN_SCRIPT_OLD_ITALIC 37 -#define UCDN_SCRIPT_GOTHIC 38 -#define UCDN_SCRIPT_DESERET 39 -#define UCDN_SCRIPT_INHERITED 40 -#define UCDN_SCRIPT_TAGALOG 41 -#define UCDN_SCRIPT_HANUNOO 42 -#define UCDN_SCRIPT_BUHID 43 -#define UCDN_SCRIPT_TAGBANWA 44 -#define UCDN_SCRIPT_LIMBU 45 -#define UCDN_SCRIPT_TAI_LE 46 -#define UCDN_SCRIPT_LINEAR_B 47 -#define UCDN_SCRIPT_UGARITIC 48 -#define UCDN_SCRIPT_SHAVIAN 49 -#define UCDN_SCRIPT_OSMANYA 50 -#define UCDN_SCRIPT_CYPRIOT 51 -#define UCDN_SCRIPT_BRAILLE 52 -#define UCDN_SCRIPT_BUGINESE 53 -#define UCDN_SCRIPT_COPTIC 54 -#define UCDN_SCRIPT_NEW_TAI_LUE 55 -#define UCDN_SCRIPT_GLAGOLITIC 56 -#define UCDN_SCRIPT_TIFINAGH 57 -#define UCDN_SCRIPT_SYLOTI_NAGRI 58 -#define UCDN_SCRIPT_OLD_PERSIAN 59 -#define UCDN_SCRIPT_KHAROSHTHI 60 -#define UCDN_SCRIPT_BALINESE 61 -#define UCDN_SCRIPT_CUNEIFORM 62 -#define UCDN_SCRIPT_PHOENICIAN 63 -#define UCDN_SCRIPT_PHAGS_PA 64 -#define UCDN_SCRIPT_NKO 65 -#define UCDN_SCRIPT_SUNDANESE 66 -#define UCDN_SCRIPT_LEPCHA 67 -#define UCDN_SCRIPT_OL_CHIKI 68 -#define UCDN_SCRIPT_VAI 69 -#define UCDN_SCRIPT_SAURASHTRA 70 -#define UCDN_SCRIPT_KAYAH_LI 71 -#define UCDN_SCRIPT_REJANG 72 -#define UCDN_SCRIPT_LYCIAN 73 -#define UCDN_SCRIPT_CARIAN 74 -#define UCDN_SCRIPT_LYDIAN 75 -#define UCDN_SCRIPT_CHAM 76 -#define UCDN_SCRIPT_TAI_THAM 77 -#define UCDN_SCRIPT_TAI_VIET 78 -#define UCDN_SCRIPT_AVESTAN 79 -#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80 -#define UCDN_SCRIPT_SAMARITAN 81 -#define UCDN_SCRIPT_LISU 82 -#define UCDN_SCRIPT_BAMUM 83 -#define UCDN_SCRIPT_JAVANESE 84 -#define UCDN_SCRIPT_MEETEI_MAYEK 85 -#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86 -#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87 -#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88 -#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89 -#define UCDN_SCRIPT_OLD_TURKIC 90 -#define UCDN_SCRIPT_KAITHI 91 -#define UCDN_SCRIPT_BATAK 92 -#define UCDN_SCRIPT_BRAHMI 93 -#define UCDN_SCRIPT_MANDAIC 94 -#define UCDN_SCRIPT_CHAKMA 95 -#define UCDN_SCRIPT_MEROITIC_CURSIVE 96 -#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97 -#define UCDN_SCRIPT_MIAO 98 -#define UCDN_SCRIPT_SHARADA 99 -#define UCDN_SCRIPT_SORA_SOMPENG 100 -#define UCDN_SCRIPT_TAKRI 101 -#define UCDN_SCRIPT_UNKNOWN 102 -#define UCDN_SCRIPT_BASSA_VAH 103 -#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104 -#define UCDN_SCRIPT_DUPLOYAN 105 -#define UCDN_SCRIPT_ELBASAN 106 -#define UCDN_SCRIPT_GRANTHA 107 -#define UCDN_SCRIPT_KHOJKI 108 -#define UCDN_SCRIPT_KHUDAWADI 109 -#define UCDN_SCRIPT_LINEAR_A 110 -#define UCDN_SCRIPT_MAHAJANI 111 -#define UCDN_SCRIPT_MANICHAEAN 112 -#define UCDN_SCRIPT_MENDE_KIKAKUI 113 -#define UCDN_SCRIPT_MODI 114 -#define UCDN_SCRIPT_MRO 115 -#define UCDN_SCRIPT_NABATAEAN 116 -#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117 -#define UCDN_SCRIPT_OLD_PERMIC 118 -#define UCDN_SCRIPT_PAHAWH_HMONG 119 -#define UCDN_SCRIPT_PALMYRENE 120 -#define UCDN_SCRIPT_PAU_CIN_HAU 121 -#define UCDN_SCRIPT_PSALTER_PAHLAVI 122 -#define UCDN_SCRIPT_SIDDHAM 123 -#define UCDN_SCRIPT_TIRHUTA 124 -#define UCDN_SCRIPT_WARANG_CITI 125 -#define UCDN_SCRIPT_AHOM 126 -#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127 -#define UCDN_SCRIPT_HATRAN 128 -#define UCDN_SCRIPT_MULTANI 129 -#define UCDN_SCRIPT_OLD_HUNGARIAN 130 -#define UCDN_SCRIPT_SIGNWRITING 131 -#define UCDN_SCRIPT_ADLAM 132 -#define UCDN_SCRIPT_BHAIKSUKI 133 -#define UCDN_SCRIPT_MARCHEN 134 -#define UCDN_SCRIPT_NEWA 135 -#define UCDN_SCRIPT_OSAGE 136 -#define UCDN_SCRIPT_TANGUT 137 -#define UCDN_SCRIPT_MASARAM_GONDI 138 -#define UCDN_SCRIPT_NUSHU 139 -#define UCDN_SCRIPT_SOYOMBO 140 -#define UCDN_SCRIPT_ZANABAZAR_SQUARE 141 -#define UCDN_SCRIPT_DOGRA 142 -#define UCDN_SCRIPT_GUNJALA_GONDI 143 -#define UCDN_SCRIPT_HANIFI_ROHINGYA 144 -#define UCDN_SCRIPT_MAKASAR 145 -#define UCDN_SCRIPT_MEDEFAIDRIN 146 -#define UCDN_SCRIPT_OLD_SOGDIAN 147 -#define UCDN_SCRIPT_SOGDIAN 148 - -#define UCDN_GENERAL_CATEGORY_CC 0 -#define UCDN_GENERAL_CATEGORY_CF 1 -#define UCDN_GENERAL_CATEGORY_CN 2 -#define UCDN_GENERAL_CATEGORY_CO 3 -#define UCDN_GENERAL_CATEGORY_CS 4 -#define UCDN_GENERAL_CATEGORY_LL 5 -#define UCDN_GENERAL_CATEGORY_LM 6 -#define UCDN_GENERAL_CATEGORY_LO 7 -#define UCDN_GENERAL_CATEGORY_LT 8 -#define UCDN_GENERAL_CATEGORY_LU 9 -#define UCDN_GENERAL_CATEGORY_MC 10 -#define UCDN_GENERAL_CATEGORY_ME 11 -#define UCDN_GENERAL_CATEGORY_MN 12 -#define UCDN_GENERAL_CATEGORY_ND 13 -#define UCDN_GENERAL_CATEGORY_NL 14 -#define UCDN_GENERAL_CATEGORY_NO 15 -#define UCDN_GENERAL_CATEGORY_PC 16 -#define UCDN_GENERAL_CATEGORY_PD 17 -#define UCDN_GENERAL_CATEGORY_PE 18 -#define UCDN_GENERAL_CATEGORY_PF 19 -#define UCDN_GENERAL_CATEGORY_PI 20 -#define UCDN_GENERAL_CATEGORY_PO 21 -#define UCDN_GENERAL_CATEGORY_PS 22 -#define UCDN_GENERAL_CATEGORY_SC 23 -#define UCDN_GENERAL_CATEGORY_SK 24 -#define UCDN_GENERAL_CATEGORY_SM 25 -#define UCDN_GENERAL_CATEGORY_SO 26 -#define UCDN_GENERAL_CATEGORY_ZL 27 -#define UCDN_GENERAL_CATEGORY_ZP 28 -#define UCDN_GENERAL_CATEGORY_ZS 29 - -#define UCDN_BIDI_CLASS_L 0 -#define UCDN_BIDI_CLASS_LRE 1 -#define UCDN_BIDI_CLASS_LRO 2 -#define UCDN_BIDI_CLASS_R 3 -#define UCDN_BIDI_CLASS_AL 4 -#define UCDN_BIDI_CLASS_RLE 5 -#define UCDN_BIDI_CLASS_RLO 6 -#define UCDN_BIDI_CLASS_PDF 7 -#define UCDN_BIDI_CLASS_EN 8 -#define UCDN_BIDI_CLASS_ES 9 -#define UCDN_BIDI_CLASS_ET 10 -#define UCDN_BIDI_CLASS_AN 11 -#define UCDN_BIDI_CLASS_CS 12 -#define UCDN_BIDI_CLASS_NSM 13 -#define UCDN_BIDI_CLASS_BN 14 -#define UCDN_BIDI_CLASS_B 15 -#define UCDN_BIDI_CLASS_S 16 -#define UCDN_BIDI_CLASS_WS 17 -#define UCDN_BIDI_CLASS_ON 18 -#define UCDN_BIDI_CLASS_LRI 19 -#define UCDN_BIDI_CLASS_RLI 20 -#define UCDN_BIDI_CLASS_FSI 21 -#define UCDN_BIDI_CLASS_PDI 22 - -/* index tables for the database records */ -#define SHIFT1 5 -#define SHIFT2 3 -static const unsigned char index0[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 53, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 54, 55, 56, 56, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 65, 66, 67, 68, - 69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, - 66, 67, 68, 69, 70, 71, 65, 66, 67, 68, 69, 70, 71, 65, 72, 73, 73, 73, - 73, 73, 73, 73, 73, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 52, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 106, 108, 109, 110, 106, - 111, 111, 111, 112, 113, 114, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 115, 115, 116, 117, 118, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 119, 120, 121, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 122, 122, 123, 124, 106, 106, 125, 126, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 128, 127, 127, 129, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 130, 131, 132, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 133, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 142, 143, 106, 106, 106, 106, 106, 144, 106, 106, 106, - 106, 106, 106, 106, 145, 146, 106, 106, 147, 106, 148, 106, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 160, 160, 160, 161, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 162, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 163, 164, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 165, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, - 166, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 52, 52, - 168, 167, 167, 167, 167, 169, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 169, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 170, 171, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, - 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 106, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 172, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 172, -}; - -static const unsigned short index1[] = { - 0, 1, 0, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 11, 12, 13, 0, 0, 0, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 29, 31, 32, - 33, 34, 35, 27, 30, 29, 27, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 27, 27, 49, 27, 27, 27, 27, 27, 27, 27, 50, 51, 52, 27, 53, 54, - 53, 54, 54, 54, 54, 54, 55, 54, 54, 54, 56, 57, 58, 59, 60, 61, 62, 63, - 64, 64, 65, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 65, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 97, 97, 97, 98, 98, 98, 98, 99, 100, 101, 101, 101, 101, 102, 103, - 101, 101, 101, 101, 101, 101, 104, 105, 101, 101, 101, 101, 101, 101, - 101, 101, 101, 101, 101, 101, 106, 107, 107, 107, 108, 109, 110, 110, - 110, 110, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 120, - 120, 121, 122, 119, 123, 124, 125, 126, 127, 127, 127, 127, 128, 129, - 130, 131, 132, 133, 134, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 144, 144, - 145, 146, 147, 148, 127, 127, 127, 127, 127, 127, 149, 149, 149, 149, - 150, 151, 152, 119, 153, 154, 155, 155, 155, 156, 157, 158, 159, 159, - 160, 161, 162, 163, 164, 165, 166, 166, 166, 167, 144, 168, 119, 119, - 119, 119, 119, 119, 127, 127, 169, 170, 119, 119, 171, 125, 172, 173, - 174, 175, 176, 177, 177, 177, 177, 177, 177, 178, 179, 180, 181, 177, - 182, 183, 184, 177, 185, 186, 187, 188, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 119, 214, 215, 216, 217, 217, 218, - 219, 220, 221, 222, 223, 119, 224, 225, 226, 227, 228, 229, 230, 231, - 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 119, 242, 243, - 244, 245, 246, 243, 247, 248, 249, 250, 251, 119, 252, 253, 254, 255, - 256, 257, 258, 259, 259, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 119, 267, 268, 269, 270, 271, 271, 270, 272, 273, 274, 275, 276, 277, - 278, 279, 280, 119, 281, 282, 283, 284, 284, 284, 284, 285, 286, 287, - 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 295, 295, 298, 299, - 296, 300, 301, 302, 303, 304, 305, 119, 306, 307, 307, 307, 307, 307, - 308, 309, 310, 311, 312, 313, 119, 119, 119, 119, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 119, 119, 119, 119, 326, 327, - 328, 329, 330, 331, 332, 333, 334, 335, 334, 334, 334, 336, 337, 338, - 339, 340, 341, 342, 341, 341, 341, 343, 344, 345, 346, 347, 119, 119, - 119, 119, 348, 348, 348, 348, 348, 349, 350, 351, 352, 353, 354, 355, - 356, 357, 358, 348, 359, 360, 352, 361, 362, 362, 362, 362, 363, 364, - 365, 365, 365, 365, 365, 366, 367, 367, 367, 367, 367, 367, 367, 367, - 367, 367, 367, 367, 368, 368, 368, 368, 368, 368, 368, 368, 368, 369, - 369, 369, 369, 369, 369, 369, 369, 369, 369, 369, 370, 370, 370, 370, - 370, 370, 370, 370, 370, 371, 372, 371, 370, 370, 370, 370, 370, 371, - 370, 370, 370, 370, 371, 372, 371, 370, 372, 370, 370, 370, 370, 370, - 370, 370, 371, 370, 370, 370, 370, 370, 370, 370, 370, 373, 374, 375, - 376, 377, 370, 370, 378, 379, 380, 380, 380, 380, 380, 380, 380, 380, - 380, 380, 381, 382, 383, 384, 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, - 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 384, 385, 384, 384, - 386, 387, 387, 388, 389, 389, 389, 389, 389, 389, 389, 389, 389, 390, - 391, 392, 393, 394, 395, 119, 396, 396, 397, 119, 398, 398, 399, 119, - 400, 401, 402, 119, 403, 403, 403, 403, 403, 403, 404, 405, 406, 407, - 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 418, 418, 418, - 419, 418, 418, 418, 418, 418, 418, 420, 421, 418, 418, 418, 418, 422, - 384, 384, 384, 384, 384, 384, 384, 384, 423, 119, 424, 424, 424, 425, - 426, 427, 428, 429, 430, 431, 432, 432, 432, 433, 434, 119, 435, 435, - 435, 435, 435, 436, 435, 435, 435, 437, 438, 439, 440, 440, 440, 440, - 441, 441, 442, 443, 444, 444, 444, 444, 444, 444, 445, 446, 447, 448, - 449, 450, 451, 452, 451, 452, 453, 454, 455, 456, 119, 119, 119, 119, - 119, 119, 119, 119, 457, 458, 458, 458, 458, 458, 459, 460, 461, 462, - 463, 464, 465, 466, 467, 468, 469, 470, 470, 470, 471, 472, 473, 474, - 475, 475, 475, 475, 476, 477, 478, 479, 480, 480, 480, 480, 481, 482, - 483, 484, 485, 486, 487, 488, 489, 489, 489, 490, 100, 491, 362, 362, - 362, 362, 362, 492, 493, 119, 494, 495, 496, 497, 498, 499, 54, 54, 54, - 54, 500, 501, 56, 56, 56, 56, 56, 502, 503, 504, 54, 505, 54, 54, 54, - 506, 56, 56, 56, 507, 508, 509, 510, 511, 511, 511, 512, 513, 27, 27, 27, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 514, 515, 27, - 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 516, 517, 518, 519, 516, 517, - 516, 517, 518, 519, 516, 520, 516, 517, 516, 518, 516, 521, 516, 521, - 516, 521, 522, 523, 524, 525, 526, 527, 516, 528, 529, 530, 531, 532, - 533, 534, 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, 545, 546, - 547, 548, 56, 549, 550, 551, 552, 553, 554, 554, 555, 556, 557, 558, 559, - 119, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, - 573, 572, 574, 575, 576, 577, 578, 579, 580, 581, 582, 581, 583, 584, - 581, 585, 581, 586, 587, 588, 589, 590, 591, 592, 593, 594, 595, 587, - 596, 597, 587, 598, 599, 587, 587, 599, 587, 600, 601, 600, 587, 587, - 602, 587, 587, 587, 587, 587, 603, 587, 587, 581, 604, 605, 606, 607, - 608, 609, 610, 610, 610, 610, 610, 610, 610, 610, 611, 581, 581, 612, - 613, 587, 587, 614, 581, 581, 581, 581, 586, 607, 615, 616, 581, 581, - 581, 581, 581, 617, 119, 119, 119, 581, 618, 119, 119, 619, 619, 619, - 619, 619, 620, 620, 621, 622, 622, 622, 622, 622, 622, 622, 622, 622, - 623, 619, 624, 625, 625, 625, 625, 625, 625, 625, 625, 625, 626, 625, - 625, 625, 625, 627, 581, 625, 625, 628, 581, 629, 630, 631, 632, 633, - 634, 630, 581, 628, 635, 581, 636, 637, 638, 639, 640, 581, 581, 581, - 641, 642, 643, 644, 581, 645, 646, 581, 647, 581, 581, 648, 649, 650, - 651, 581, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 581, - 581, 581, 663, 581, 664, 581, 665, 666, 667, 668, 669, 670, 619, 671, - 671, 672, 581, 581, 581, 663, 673, 674, 587, 587, 587, 675, 676, 587, - 587, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, - 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, 677, - 677, 677, 677, 677, 677, 587, 587, 587, 587, 587, 587, 587, 587, 587, - 587, 587, 587, 587, 587, 587, 587, 678, 679, 679, 680, 587, 587, 587, - 587, 587, 587, 587, 681, 587, 587, 587, 682, 587, 587, 587, 587, 587, - 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, - 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 581, - 581, 581, 683, 581, 581, 587, 587, 684, 685, 686, 630, 581, 581, 687, - 581, 581, 581, 688, 581, 581, 581, 581, 581, 581, 689, 581, 581, 581, - 581, 581, 617, 690, 690, 690, 690, 690, 691, 692, 692, 692, 692, 692, - 693, 694, 695, 696, 697, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, - 698, 699, 700, 701, 365, 365, 365, 365, 702, 703, 704, 704, 704, 704, - 704, 704, 704, 705, 706, 707, 370, 370, 372, 119, 372, 372, 372, 372, - 372, 372, 372, 372, 708, 708, 708, 708, 709, 710, 711, 712, 713, 714, - 715, 716, 717, 718, 119, 119, 119, 119, 119, 119, 719, 719, 719, 720, - 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 721, 119, 719, 719, - 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, - 719, 719, 719, 719, 719, 719, 719, 719, 719, 719, 722, 119, 119, 119, - 723, 724, 725, 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, 735, - 736, 735, 735, 735, 737, 738, 739, 740, 741, 742, 743, 743, 744, 743, - 743, 743, 745, 746, 747, 748, 749, 750, 750, 750, 750, 750, 751, 752, - 752, 752, 752, 752, 752, 752, 752, 752, 752, 753, 754, 755, 750, 750, - 750, 756, 723, 723, 723, 723, 724, 119, 757, 757, 758, 758, 758, 759, - 760, 761, 755, 755, 755, 762, 763, 764, 758, 758, 758, 765, 760, 761, - 755, 755, 755, 755, 766, 764, 755, 767, 768, 768, 768, 768, 768, 769, - 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 768, 755, 755, 755, - 770, 771, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 755, 772, - 755, 755, 755, 770, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 774, 775, 581, 581, 581, 581, 581, 581, 581, 581, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 775, 775, 776, 776, 777, 776, 776, 776, 776, 776, 776, 776, 776, 776, - 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, - 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, - 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, - 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, - 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 776, 778, - 779, 779, 779, 779, 779, 779, 780, 119, 781, 781, 781, 781, 781, 782, - 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, - 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, 783, - 783, 783, 783, 783, 783, 784, 783, 783, 785, 786, 119, 119, 101, 101, - 101, 101, 101, 787, 788, 789, 101, 101, 101, 790, 791, 791, 791, 791, - 791, 791, 791, 791, 792, 793, 794, 119, 64, 64, 795, 796, 797, 27, 798, - 27, 27, 27, 27, 27, 27, 27, 799, 800, 27, 801, 802, 27, 27, 803, 804, - 805, 119, 119, 119, 119, 119, 119, 806, 807, 808, 809, 810, 810, 811, - 812, 813, 814, 815, 815, 815, 815, 815, 815, 816, 119, 817, 818, 818, - 818, 818, 818, 819, 820, 821, 822, 823, 824, 825, 825, 826, 827, 828, - 829, 830, 830, 831, 832, 833, 833, 834, 835, 836, 837, 367, 367, 367, - 838, 839, 840, 840, 840, 840, 840, 841, 842, 843, 844, 845, 846, 847, - 348, 352, 848, 849, 849, 849, 849, 849, 850, 851, 119, 852, 853, 854, - 855, 348, 348, 856, 857, 858, 858, 858, 858, 858, 858, 859, 860, 861, - 119, 119, 862, 863, 864, 865, 119, 866, 866, 866, 119, 372, 372, 54, 54, - 54, 54, 54, 867, 868, 119, 869, 869, 869, 869, 869, 869, 869, 869, 869, - 869, 863, 863, 863, 863, 870, 871, 872, 873, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, - 875, 875, 874, 875, 875, 876, 875, 875, 875, 875, 875, 875, 874, 875, - 875, 876, 875, 875, 875, 874, 875, 875, 876, 875, 875, 875, 874, 875, - 875, 877, 119, 368, 368, 878, 879, 369, 369, 369, 369, 369, 880, 881, - 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, - 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, 881, - 881, 881, 881, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, - 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, - 882, 882, 882, 882, 882, 882, 882, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 774, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 883, 775, 775, 775, 775, 884, 119, 885, - 886, 120, 887, 888, 889, 890, 120, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 891, 892, 893, 119, 894, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 895, 119, - 119, 127, 127, 127, 127, 127, 127, 127, 127, 896, 127, 127, 127, 127, - 127, 127, 119, 119, 119, 119, 119, 127, 897, 898, 898, 899, 900, 901, - 902, 903, 904, 905, 906, 907, 908, 909, 910, 169, 127, 127, 127, 127, - 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 911, 912, - 913, 914, 915, 916, 917, 917, 918, 919, 920, 920, 921, 922, 923, 924, - 925, 925, 925, 925, 926, 927, 927, 927, 928, 929, 929, 929, 930, 931, - 932, 119, 933, 934, 935, 934, 934, 936, 934, 934, 937, 934, 938, 934, - 938, 119, 119, 119, 119, 934, 934, 934, 934, 934, 934, 934, 934, 934, - 934, 934, 934, 934, 934, 934, 939, 940, 941, 941, 941, 941, 941, 942, - 610, 943, 943, 943, 943, 943, 943, 944, 945, 946, 947, 581, 948, 949, - 119, 119, 119, 119, 119, 610, 610, 610, 610, 610, 950, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 951, - 951, 951, 952, 953, 953, 953, 953, 953, 953, 954, 119, 955, 956, 956, - 957, 958, 958, 958, 958, 959, 960, 961, 961, 962, 963, 964, 964, 964, - 964, 965, 966, 967, 967, 967, 968, 969, 969, 969, 969, 970, 969, 971, - 119, 119, 119, 119, 119, 972, 972, 972, 972, 972, 973, 973, 973, 973, - 973, 974, 974, 974, 974, 974, 974, 975, 975, 975, 976, 977, 978, 979, - 979, 979, 979, 980, 981, 981, 981, 981, 982, 983, 983, 983, 983, 983, - 119, 984, 984, 984, 984, 984, 984, 985, 986, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 987, - 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, - 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, 987, - 987, 987, 987, 987, 987, 987, 987, 987, 987, 988, 119, 987, 987, 989, - 119, 987, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 990, 991, 992, 992, 992, 992, 993, - 994, 995, 995, 996, 997, 998, 998, 999, 1000, 1001, 1001, 1001, 1002, - 1003, 1004, 119, 119, 119, 119, 119, 119, 1005, 1005, 1006, 1007, 1008, - 1008, 1009, 1010, 1011, 1011, 1011, 1012, 119, 119, 119, 119, 119, 119, - 119, 119, 1013, 1013, 1013, 1013, 1014, 1014, 1014, 1015, 1016, 1016, - 1017, 1016, 1016, 1016, 1016, 1016, 1018, 1019, 1020, 1021, 1022, 1022, - 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1029, 1029, 1030, 1031, 1031, - 1031, 1032, 119, 119, 119, 119, 1033, 1034, 1033, 1033, 1035, 1036, 1037, - 119, 1038, 1038, 1038, 1038, 1038, 1038, 1039, 1040, 1041, 1041, 1042, - 1043, 1044, 1044, 1045, 1046, 1047, 1047, 1048, 1049, 119, 1050, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 1051, 1051, 1051, 1051, - 1051, 1051, 1051, 1051, 1051, 1052, 119, 119, 119, 119, 119, 119, 1053, - 1053, 1053, 1053, 1053, 1053, 1054, 119, 1055, 1055, 1055, 1055, 1055, - 1055, 1056, 1057, 1058, 1058, 1058, 1058, 1059, 119, 1060, 1061, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 1062, 1062, 1062, 1063, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1064, - 1064, 1064, 1065, 1066, 119, 1067, 1067, 1068, 1069, 1070, 1071, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 1072, 1073, 1073, 1073, 1073, 1073, 1073, 1074, - 1075, 1076, 1077, 1078, 1079, 1080, 119, 1081, 1082, 1083, 1083, 1083, - 1083, 1083, 1084, 1085, 1086, 1087, 1088, 1088, 1088, 1089, 1090, 1091, - 1092, 1093, 1093, 1093, 1094, 1095, 1096, 1097, 1098, 119, 1099, 1099, - 1099, 1099, 1100, 119, 1101, 1102, 1102, 1102, 1102, 1102, 1103, 1104, - 1105, 1106, 1107, 1108, 1109, 1110, 1111, 119, 1112, 1112, 1113, 1112, - 1112, 1114, 1115, 1116, 119, 119, 119, 119, 119, 119, 119, 119, 1117, - 1118, 1119, 1120, 1119, 1121, 1122, 1122, 1122, 1122, 1122, 1123, 1124, - 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1131, 1132, 1133, 1134, 1135, - 1136, 1137, 1138, 1139, 1140, 1140, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1141, 1141, 1141, 1141, - 1141, 1141, 1142, 1143, 1144, 1145, 1146, 1147, 119, 119, 119, 119, 1148, - 1148, 1148, 1148, 1148, 1148, 1149, 1150, 1151, 119, 1152, 1153, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 1154, 1154, 1154, 1154, 1154, 1155, 1156, 1157, - 1158, 1159, 1160, 1161, 119, 119, 119, 119, 1162, 1162, 1162, 1162, 1162, - 1162, 1163, 1164, 1165, 119, 1166, 1167, 1168, 1169, 119, 119, 1170, - 1170, 1170, 1170, 1170, 1171, 1172, 119, 1173, 1174, 119, 119, 119, 119, - 119, 119, 1175, 1175, 1175, 1176, 1177, 1178, 1179, 1180, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 1181, 1181, 1181, 1181, 1181, 1182, - 1183, 1184, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 1185, 1185, 1185, 1185, 1186, 1186, 1186, 1186, 1187, 1188, 1189, 1190, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 1191, 1192, 1193, 1193, 1193, 1193, 1194, 1195, 1196, - 119, 1197, 1198, 1199, 1199, 1199, 1199, 1200, 1201, 1202, 1203, 1204, - 119, 119, 119, 1205, 1205, 1205, 1205, 1205, 1205, 1205, 1206, 1207, - 1208, 1207, 1207, 1207, 1209, 1210, 1211, 1212, 119, 1213, 1214, 1215, - 1216, 1217, 1218, 1218, 1218, 1219, 1220, 1220, 1221, 1222, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 1223, 1224, 1225, 1225, 1225, 1225, - 1226, 1227, 1228, 119, 1229, 1230, 1231, 1232, 1233, 1233, 1233, 1234, - 1235, 1236, 1237, 1238, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 1239, 1239, 1240, 1241, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, - 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, - 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, - 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, - 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1243, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 1244, 1244, 1244, 1244, 1244, 1244, - 1244, 1244, 1244, 1244, 1244, 1244, 1244, 1245, 1246, 119, 1242, 1242, - 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, - 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1247, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 1248, 1248, 1248, 1248, 1248, - 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, - 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, - 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, - 1248, 1248, 1249, 1248, 1248, 1248, 1248, 1250, 1251, 1248, 1248, 1248, - 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, - 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, - 1248, 1248, 1252, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, - 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, 1248, - 1253, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1254, - 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, - 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1255, 1254, 1254, 1254, - 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1254, 1256, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 791, 791, 791, 791, 791, - 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, - 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, 791, - 791, 791, 791, 791, 791, 791, 1257, 1258, 1258, 1258, 1259, 1260, 1261, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1262, 1262, - 1262, 1263, 1264, 119, 1265, 1265, 1265, 1265, 1265, 1265, 1266, 1267, - 1268, 119, 1269, 1270, 1271, 1265, 1265, 1272, 1265, 1265, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 1273, 1273, 1273, 1273, 1274, 1274, 1274, 1274, - 1275, 1275, 1276, 1277, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1278, 1279, 119, - 1280, 1281, 1281, 1281, 1281, 1282, 119, 1283, 1284, 1285, 119, 119, 119, - 119, 119, 119, 119, 119, 1286, 119, 119, 119, 1287, 1287, 1287, 1287, - 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, - 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, - 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, - 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, - 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1288, 119, - 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, - 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, - 1287, 1287, 1287, 1287, 1287, 1287, 1289, 119, 1290, 735, 735, 735, 735, - 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, - 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, 735, - 735, 735, 1291, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1292, - 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, - 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, - 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, - 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, 1292, - 1293, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, 1294, - 1294, 1294, 1295, 1294, 1296, 1294, 1297, 1294, 1298, 1299, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 610, 610, 610, 610, 610, - 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, - 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 610, 1300, 119, 610, - 610, 610, 610, 1301, 1302, 610, 610, 610, 610, 610, 610, 1303, 1304, - 1305, 1306, 1307, 1308, 610, 610, 610, 1309, 610, 610, 610, 610, 610, - 610, 610, 1310, 119, 119, 946, 946, 946, 946, 946, 946, 946, 946, 1311, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 941, 941, 1312, 119, 581, 581, 581, 581, 581, - 581, 581, 581, 581, 581, 617, 119, 941, 941, 941, 1313, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1314, - 1314, 1314, 1315, 1316, 1316, 1317, 1314, 1314, 1318, 1319, 1316, 1316, - 1314, 1314, 1314, 1315, 1316, 1316, 1320, 1321, 1322, 1318, 1323, 1324, - 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1325, 1326, 1327, 1328, 1316, - 1316, 1316, 1329, 1330, 1331, 1332, 1316, 1316, 1317, 1314, 1314, 1318, - 1316, 1316, 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1317, 1314, 1314, - 1318, 1316, 1316, 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1317, 1314, - 1314, 1318, 1316, 1316, 1316, 1314, 1314, 1314, 1315, 1316, 1316, 1333, - 1314, 1314, 1314, 1334, 1316, 1316, 1335, 1336, 1314, 1314, 1337, 1316, - 1316, 1338, 1317, 1314, 1314, 1339, 1316, 1316, 1340, 1341, 1314, 1314, - 1342, 1316, 1316, 1316, 1343, 1314, 1314, 1314, 1334, 1316, 1316, 1335, - 1344, 1345, 1345, 1345, 1345, 1345, 1345, 1346, 1346, 1346, 1346, 1346, - 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, - 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, 1346, - 1346, 1346, 1346, 1347, 1347, 1347, 1347, 1347, 1347, 1348, 1349, 1347, - 1347, 1347, 1347, 1347, 1350, 1351, 1346, 1352, 1353, 119, 1354, 1355, - 1347, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 1356, 1357, 1357, - 1358, 1359, 1360, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, - 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, 1361, - 1361, 1362, 1363, 1364, 119, 119, 119, 119, 119, 1365, 1365, 1365, 1365, - 1366, 1367, 1367, 1367, 1368, 1369, 1370, 1371, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 1372, 1373, 1373, 1373, 1373, 1373, 1373, 1374, 1375, 119, 119, 119, - 119, 119, 119, 119, 119, 119, 1376, 127, 127, 127, 1377, 1378, 1379, - 1380, 1381, 1382, 1377, 1383, 1377, 1379, 1379, 1384, 127, 1385, 127, - 1386, 1387, 1385, 127, 1386, 119, 119, 119, 119, 119, 119, 1388, 119, - 1389, 1390, 1390, 1390, 1390, 1391, 1390, 1390, 1390, 1390, 1390, 1390, - 1390, 1390, 1390, 1390, 1390, 1390, 1391, 1392, 1390, 1393, 1394, 1390, - 1394, 1395, 1394, 1390, 1390, 1390, 1396, 1392, 620, 1397, 622, 622, 622, - 1398, 622, 622, 622, 622, 622, 622, 622, 1399, 622, 622, 622, 1400, 1401, - 1402, 622, 1403, 1392, 1392, 1392, 1392, 1392, 1392, 1404, 1405, 1405, - 1405, 1406, 1392, 755, 755, 755, 755, 755, 1407, 755, 1408, 1409, 1392, - 1410, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, - 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 723, 723, 723, 723, 1411, - 1412, 1413, 723, 723, 723, 723, 723, 723, 723, 723, 1414, 1415, 723, - 1416, 1417, 723, 723, 1418, 1419, 1420, 1421, 1416, 1390, 723, 723, 1422, - 1423, 723, 723, 723, 723, 723, 723, 723, 1424, 1425, 1426, 1427, 723, - 1428, 1429, 1426, 1430, 1431, 723, 723, 723, 1432, 1433, 1434, 723, 723, - 723, 723, 723, 723, 723, 723, 1435, 1436, 723, 1437, 643, 1438, 723, - 1439, 1440, 581, 1441, 723, 723, 723, 1390, 1442, 1443, 1390, 1390, 1444, - 1390, 1389, 1390, 1390, 1390, 1390, 1390, 1445, 1446, 1390, 1390, 1445, - 1447, 723, 723, 723, 723, 723, 723, 723, 723, 1448, 1449, 581, 581, 581, - 581, 1450, 1451, 723, 723, 723, 723, 1452, 723, 1453, 723, 1454, 1455, - 1456, 1392, 1390, 1457, 1458, 1459, 581, 581, 581, 581, 581, 581, 581, - 581, 581, 581, 581, 581, 581, 581, 1460, 1392, 581, 581, 581, 581, 581, - 581, 581, 581, 581, 581, 1461, 1462, 1392, 1392, 1392, 1392, 581, 1460, - 581, 581, 581, 581, 581, 581, 581, 1392, 581, 1463, 581, 581, 581, 581, - 581, 1392, 581, 581, 581, 1464, 1392, 1392, 1392, 1392, 1392, 1392, 1392, - 1392, 1392, 1392, 581, 1460, 723, 1465, 1466, 723, 1426, 1467, 723, 723, - 723, 723, 723, 723, 1468, 1469, 723, 723, 723, 723, 1470, 1392, 1471, - 1472, 1470, 1392, 1473, 1474, 723, 723, 723, 723, 1392, 1392, 1392, 1392, - 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1390, 1396, 1392, 1392, - 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, - 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, - 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, - 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, - 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, - 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1392, - 1392, 1392, 1392, 1392, 1392, 1392, 1392, 1475, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 1476, 775, 775, 775, 775, 775, 773, - 773, 773, 773, 773, 773, 1477, 775, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 774, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 883, - 775, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, - 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 773, 1478, 775, 775, - 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, - 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, - 775, 775, 775, 775, 775, 773, 773, 773, 774, 775, 775, 775, 775, 775, - 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, - 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, - 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, - 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 775, 1479, 1480, - 119, 119, 119, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, 1481, - 1481, 1481, 1481, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 119, 119, 119, 119, 119, 898, 898, 898, 898, 898, 898, 898, 898, 898, - 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, 898, - 898, 898, 898, 898, 898, 898, 898, 119, 119, 882, 882, 882, 882, 882, - 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, - 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 882, 1482, -}; - -static const unsigned short index2[] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 1, 1, 1, 1, 1, 1, 7, 7, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 11, 16, 17, 15, 18, 19, 20, 19, 21, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 19, 23, 24, 24, 24, 10, 15, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 16, 26, 17, - 27, 28, 27, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 16, 30, 31, 24, 1, 1, 1, 1, 1, 1, 32, 1, 1, 33, 34, 35, 13, - 36, 13, 37, 38, 39, 40, 41, 42, 24, 43, 44, 27, 45, 46, 47, 47, 48, 49, - 38, 38, 39, 47, 41, 50, 51, 51, 51, 34, 52, 52, 52, 52, 52, 52, 53, 52, - 52, 52, 52, 52, 52, 52, 52, 52, 53, 52, 52, 52, 52, 52, 52, 54, 53, 52, - 52, 52, 52, 52, 53, 55, 55, 55, 56, 56, 56, 56, 55, 56, 55, 55, 55, 56, - 55, 55, 56, 56, 55, 56, 55, 55, 56, 56, 56, 54, 55, 55, 55, 56, 55, 56, - 55, 56, 52, 55, 52, 56, 52, 56, 52, 56, 52, 56, 52, 56, 52, 56, 52, 56, - 52, 55, 52, 55, 52, 56, 52, 56, 52, 56, 52, 55, 52, 56, 52, 56, 52, 56, - 52, 56, 52, 56, 53, 55, 52, 55, 53, 55, 52, 56, 52, 56, 55, 52, 56, 52, - 56, 52, 56, 53, 55, 53, 55, 52, 55, 52, 56, 52, 55, 55, 53, 55, 52, 55, - 52, 56, 52, 56, 53, 55, 52, 56, 52, 56, 52, 52, 56, 52, 56, 52, 56, 56, - 56, 52, 52, 56, 52, 56, 52, 52, 56, 52, 52, 52, 56, 56, 52, 52, 52, 52, - 56, 52, 52, 56, 52, 52, 52, 56, 56, 56, 52, 52, 56, 52, 52, 56, 52, 56, - 52, 56, 52, 52, 56, 52, 56, 56, 52, 56, 52, 52, 56, 52, 52, 52, 56, 52, - 56, 52, 52, 56, 56, 57, 52, 56, 56, 56, 57, 57, 57, 57, 52, 58, 56, 52, - 58, 56, 52, 58, 56, 52, 55, 52, 55, 52, 55, 52, 55, 52, 55, 52, 55, 52, - 55, 52, 55, 56, 52, 56, 56, 52, 58, 56, 52, 56, 52, 52, 52, 56, 52, 56, - 56, 56, 56, 56, 56, 56, 52, 52, 56, 52, 52, 56, 56, 52, 56, 52, 52, 52, - 52, 56, 56, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 57, 56, 56, 56, 59, 59, 59, 59, 59, 59, 59, 59, 59, 60, - 60, 61, 61, 61, 61, 61, 61, 61, 62, 62, 63, 62, 60, 64, 65, 64, 64, 64, - 65, 64, 60, 60, 66, 61, 62, 62, 62, 62, 62, 62, 39, 39, 39, 39, 62, 39, - 62, 48, 59, 59, 59, 59, 59, 62, 62, 62, 62, 62, 67, 67, 60, 62, 61, 62, - 62, 62, 62, 62, 62, 62, 62, 62, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, - 68, 68, 68, 69, 70, 70, 70, 70, 69, 71, 70, 70, 70, 70, 70, 72, 72, 70, - 70, 70, 70, 72, 72, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 70, 73, 73, - 73, 73, 73, 70, 70, 70, 70, 68, 68, 68, 68, 68, 68, 68, 68, 74, 68, 70, - 70, 70, 68, 68, 68, 70, 70, 75, 68, 68, 68, 70, 70, 70, 70, 68, 69, 70, - 70, 68, 76, 77, 77, 76, 77, 77, 76, 68, 68, 68, 68, 68, 78, 79, 78, 79, - 60, 80, 78, 79, 81, 81, 82, 79, 79, 79, 83, 78, 81, 81, 81, 81, 80, 62, - 78, 84, 78, 78, 78, 81, 78, 81, 78, 78, 79, 85, 85, 85, 85, 85, 85, 85, - 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 81, 85, 85, 85, 85, 85, 85, 85, - 78, 78, 79, 79, 79, 79, 79, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, - 86, 86, 86, 86, 86, 86, 79, 86, 86, 86, 86, 86, 86, 86, 79, 79, 79, 79, - 79, 78, 79, 79, 78, 78, 78, 79, 79, 79, 78, 79, 78, 79, 78, 79, 78, 79, - 78, 79, 87, 88, 87, 88, 87, 88, 87, 88, 87, 88, 87, 88, 87, 88, 79, 79, - 79, 79, 78, 79, 89, 78, 79, 78, 78, 79, 79, 78, 78, 78, 90, 91, 90, 90, - 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 90, 91, 91, 91, 91, 91, 91, - 91, 91, 92, 92, 92, 92, 92, 92, 92, 92, 93, 92, 93, 93, 93, 93, 93, 93, - 93, 93, 93, 93, 93, 93, 93, 93, 90, 93, 90, 93, 90, 93, 90, 93, 90, 93, - 94, 95, 95, 96, 96, 95, 97, 97, 90, 93, 90, 93, 90, 93, 90, 90, 93, 90, - 93, 90, 93, 90, 93, 90, 93, 90, 93, 90, 93, 93, 81, 98, 98, 98, 98, 98, - 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 81, - 81, 99, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, - 101, 101, 102, 103, 81, 81, 104, 104, 105, 81, 106, 107, 107, 107, 107, - 106, 107, 107, 107, 108, 106, 107, 107, 107, 107, 107, 107, 106, 106, - 106, 106, 106, 106, 107, 107, 106, 107, 107, 108, 109, 107, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 125, 107, 106, 128, 118, 81, 81, 81, 81, 81, 81, 81, 81, - 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 81, 81, 81, 81, - 129, 129, 129, 129, 125, 125, 81, 81, 81, 130, 130, 130, 130, 130, 131, - 132, 132, 133, 134, 134, 135, 136, 137, 138, 138, 139, 139, 139, 139, - 139, 139, 139, 139, 140, 141, 142, 143, 144, 81, 145, 143, 146, 146, 146, - 146, 146, 146, 146, 146, 147, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 148, 149, 150, 151, 152, 153, 154, 155, 96, 96, 156, 157, 139, - 139, 139, 139, 139, 157, 139, 139, 157, 158, 158, 158, 158, 158, 158, - 158, 158, 158, 158, 134, 159, 159, 160, 146, 146, 161, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 145, 146, 139, 139, 139, 139, - 139, 139, 139, 131, 138, 139, 139, 139, 139, 157, 139, 162, 162, 139, - 139, 138, 157, 139, 139, 157, 146, 146, 163, 163, 163, 163, 163, 163, - 163, 163, 163, 163, 146, 146, 146, 164, 164, 146, 165, 165, 165, 165, - 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 81, 166, 167, 168, 167, - 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 169, - 170, 169, 169, 170, 169, 169, 170, 170, 170, 169, 170, 170, 169, 170, - 169, 169, 169, 170, 169, 170, 169, 170, 169, 170, 169, 169, 81, 81, 167, - 167, 167, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, - 171, 171, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, 171, 81, - 81, 81, 81, 81, 81, 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, 174, - 174, 174, 174, 175, 175, 175, 175, 175, 175, 175, 176, 175, 177, 177, - 178, 179, 180, 181, 177, 81, 81, 176, 182, 182, 183, 183, 183, 183, 183, - 183, 183, 183, 183, 183, 183, 183, 183, 183, 184, 184, 184, 184, 185, - 184, 184, 184, 184, 184, 184, 184, 184, 184, 185, 184, 184, 184, 185, - 184, 184, 184, 184, 184, 81, 81, 186, 186, 186, 186, 186, 186, 186, 186, - 186, 186, 186, 186, 186, 186, 186, 81, 187, 187, 187, 187, 187, 187, 187, - 187, 187, 188, 188, 188, 81, 81, 189, 81, 167, 167, 167, 81, 81, 81, 81, - 81, 146, 146, 146, 146, 146, 81, 146, 146, 146, 146, 146, 146, 146, 146, - 81, 81, 81, 81, 81, 157, 139, 139, 139, 139, 139, 139, 131, 157, 139, - 139, 157, 139, 139, 157, 139, 139, 139, 157, 157, 157, 190, 191, 192, - 139, 139, 139, 157, 139, 139, 157, 157, 139, 139, 139, 139, 139, 193, - 193, 193, 194, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, - 195, 195, 195, 193, 194, 196, 195, 194, 194, 194, 193, 193, 193, 193, - 193, 193, 193, 193, 194, 194, 194, 194, 197, 194, 194, 195, 96, 156, 198, - 198, 193, 193, 193, 195, 195, 193, 193, 199, 199, 200, 200, 200, 200, - 200, 200, 200, 200, 200, 200, 201, 202, 195, 195, 195, 195, 195, 195, - 203, 204, 205, 205, 81, 203, 203, 203, 203, 203, 203, 203, 203, 81, 81, - 203, 203, 81, 81, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, 203, - 203, 203, 203, 81, 203, 203, 203, 203, 203, 203, 203, 81, 203, 81, 81, - 81, 203, 203, 203, 203, 81, 81, 206, 203, 205, 205, 205, 204, 204, 204, - 204, 81, 81, 205, 205, 81, 81, 205, 205, 207, 203, 81, 81, 81, 81, 81, - 81, 81, 81, 205, 81, 81, 81, 81, 203, 203, 81, 203, 203, 203, 204, 204, - 81, 81, 208, 208, 208, 208, 208, 208, 208, 208, 208, 208, 203, 203, 209, - 209, 210, 210, 210, 210, 210, 211, 212, 213, 203, 214, 215, 81, 81, 216, - 216, 217, 81, 218, 218, 218, 218, 218, 218, 81, 81, 81, 81, 218, 218, 81, - 81, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, 218, - 81, 218, 218, 218, 218, 218, 218, 218, 81, 218, 218, 81, 218, 218, 81, - 218, 218, 81, 81, 219, 81, 217, 217, 217, 216, 216, 81, 81, 81, 81, 216, - 216, 81, 81, 216, 216, 220, 81, 81, 81, 216, 81, 81, 81, 81, 81, 81, 81, - 218, 218, 218, 218, 81, 218, 81, 81, 81, 81, 81, 81, 81, 221, 221, 221, - 221, 221, 221, 221, 221, 221, 221, 216, 216, 218, 218, 218, 216, 222, 81, - 81, 223, 223, 224, 81, 225, 225, 225, 225, 225, 225, 225, 225, 225, 81, - 225, 225, 225, 81, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, 225, - 225, 225, 225, 81, 225, 225, 225, 225, 225, 225, 225, 81, 225, 225, 81, - 225, 225, 225, 225, 225, 81, 81, 226, 225, 224, 224, 224, 223, 223, 223, - 223, 223, 81, 223, 223, 224, 81, 224, 224, 227, 81, 81, 225, 81, 81, 81, - 81, 81, 81, 81, 225, 225, 223, 223, 81, 81, 228, 228, 228, 228, 228, 228, - 228, 228, 228, 228, 229, 230, 81, 81, 81, 81, 81, 81, 81, 225, 223, 223, - 223, 223, 223, 223, 81, 231, 232, 232, 81, 233, 233, 233, 233, 233, 233, - 233, 233, 81, 81, 233, 233, 81, 81, 233, 233, 233, 233, 233, 233, 233, - 233, 233, 233, 233, 233, 233, 233, 81, 233, 233, 233, 233, 233, 233, 233, - 81, 233, 233, 81, 233, 233, 233, 233, 233, 81, 81, 234, 233, 232, 231, - 232, 231, 231, 231, 231, 81, 81, 232, 232, 81, 81, 232, 232, 235, 81, 81, - 81, 81, 81, 81, 81, 81, 231, 232, 81, 81, 81, 81, 233, 233, 81, 233, 233, - 233, 231, 231, 81, 81, 236, 236, 236, 236, 236, 236, 236, 236, 236, 236, - 237, 233, 238, 238, 238, 238, 238, 238, 81, 81, 239, 240, 81, 240, 240, - 240, 240, 240, 240, 81, 81, 81, 240, 240, 240, 81, 240, 240, 240, 240, - 81, 81, 81, 240, 240, 81, 240, 81, 240, 240, 81, 81, 81, 240, 240, 81, - 81, 81, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 81, 81, 81, 81, - 241, 241, 239, 241, 241, 81, 81, 81, 241, 241, 241, 81, 241, 241, 241, - 242, 81, 81, 240, 81, 81, 81, 81, 81, 81, 241, 81, 81, 81, 81, 81, 81, - 243, 243, 243, 243, 243, 243, 243, 243, 243, 243, 244, 244, 244, 245, - 245, 245, 245, 245, 245, 246, 245, 81, 81, 81, 81, 81, 247, 248, 248, - 248, 247, 249, 249, 249, 249, 249, 249, 249, 249, 81, 249, 249, 249, 81, - 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, 249, - 249, 249, 81, 81, 81, 249, 247, 247, 247, 248, 248, 248, 248, 81, 247, - 247, 247, 81, 247, 247, 247, 250, 81, 81, 81, 81, 81, 81, 81, 251, 252, - 81, 249, 249, 249, 81, 81, 81, 81, 81, 249, 249, 247, 247, 81, 81, 253, - 253, 253, 253, 253, 253, 253, 253, 253, 253, 254, 254, 254, 254, 254, - 254, 254, 255, 256, 257, 258, 258, 259, 256, 256, 256, 256, 256, 256, - 256, 256, 81, 256, 256, 256, 81, 256, 256, 256, 256, 256, 256, 256, 256, - 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 81, 256, 256, 256, 256, - 256, 81, 81, 260, 256, 258, 261, 258, 258, 258, 258, 258, 81, 261, 258, - 258, 81, 258, 258, 257, 262, 81, 81, 81, 81, 81, 81, 81, 258, 258, 81, - 81, 81, 81, 81, 81, 81, 256, 81, 256, 256, 257, 257, 81, 81, 263, 263, - 263, 263, 263, 263, 263, 263, 263, 263, 81, 256, 256, 81, 81, 81, 81, 81, - 264, 264, 265, 265, 81, 266, 266, 266, 266, 266, 266, 266, 266, 81, 266, - 266, 266, 81, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, 266, - 266, 266, 266, 266, 266, 267, 267, 266, 265, 265, 265, 264, 264, 264, - 264, 81, 265, 265, 265, 81, 265, 265, 265, 267, 266, 268, 81, 81, 81, 81, - 266, 266, 266, 265, 269, 269, 269, 269, 269, 269, 269, 266, 266, 266, - 264, 264, 81, 81, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 269, - 269, 269, 269, 269, 269, 269, 269, 269, 271, 266, 266, 266, 266, 266, - 266, 81, 81, 272, 272, 81, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 273, 273, 273, 273, 273, 273, 273, 273, 273, 81, 81, 81, 273, 273, 273, - 273, 273, 273, 273, 273, 81, 273, 273, 273, 273, 273, 273, 273, 273, 273, - 81, 273, 81, 81, 81, 81, 274, 81, 81, 81, 81, 272, 272, 272, 275, 275, - 275, 81, 275, 81, 272, 272, 272, 272, 272, 272, 272, 272, 81, 81, 81, 81, - 81, 81, 276, 276, 276, 276, 276, 276, 276, 276, 276, 276, 81, 81, 272, - 272, 277, 81, 81, 81, 81, 278, 278, 278, 278, 278, 278, 278, 278, 278, - 278, 278, 278, 278, 278, 278, 278, 279, 278, 278, 279, 279, 279, 279, - 280, 280, 281, 81, 81, 81, 81, 282, 278, 278, 278, 278, 278, 278, 283, - 279, 284, 284, 284, 284, 279, 279, 279, 285, 286, 286, 286, 286, 286, - 286, 286, 286, 286, 286, 287, 287, 81, 81, 81, 81, 81, 288, 288, 81, 288, - 81, 81, 288, 288, 81, 288, 81, 81, 288, 81, 81, 81, 81, 81, 81, 288, 288, - 288, 288, 81, 288, 288, 288, 288, 288, 288, 288, 81, 288, 288, 288, 81, - 288, 81, 288, 81, 81, 288, 288, 81, 288, 288, 288, 288, 289, 288, 288, - 289, 289, 289, 289, 290, 290, 81, 289, 289, 288, 81, 81, 288, 288, 288, - 288, 288, 81, 291, 81, 292, 292, 292, 292, 289, 289, 81, 81, 293, 293, - 293, 293, 293, 293, 293, 293, 293, 293, 81, 81, 288, 288, 288, 288, 294, - 295, 295, 295, 296, 297, 296, 296, 298, 296, 296, 299, 298, 300, 300, - 300, 300, 300, 298, 301, 300, 301, 301, 301, 302, 302, 301, 301, 301, - 301, 301, 301, 303, 303, 303, 303, 303, 303, 303, 303, 303, 303, 304, - 304, 304, 304, 304, 304, 304, 304, 304, 304, 305, 302, 301, 302, 301, - 306, 307, 308, 307, 308, 309, 309, 294, 294, 294, 294, 294, 294, 294, - 294, 81, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 294, 81, - 81, 81, 81, 310, 311, 312, 313, 312, 312, 312, 312, 312, 311, 311, 311, - 311, 312, 314, 311, 312, 315, 315, 316, 299, 315, 315, 294, 294, 294, - 294, 294, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 81, 312, - 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 312, 81, 305, 305, 301, - 301, 301, 301, 301, 301, 302, 301, 301, 301, 301, 301, 301, 81, 301, 301, - 296, 296, 299, 296, 297, 317, 317, 317, 317, 298, 298, 81, 81, 81, 81, - 81, 318, 318, 318, 318, 318, 318, 318, 318, 318, 318, 318, 319, 319, 320, - 320, 320, 320, 319, 320, 320, 320, 320, 320, 321, 319, 322, 322, 319, - 319, 320, 320, 318, 323, 323, 323, 323, 323, 323, 323, 323, 323, 323, - 324, 324, 325, 325, 325, 325, 318, 318, 318, 318, 318, 318, 319, 319, - 320, 320, 318, 318, 318, 318, 320, 320, 320, 318, 319, 319, 319, 318, - 318, 319, 319, 319, 319, 319, 319, 319, 318, 318, 318, 320, 320, 320, - 320, 318, 318, 318, 318, 318, 320, 319, 319, 320, 320, 319, 319, 319, - 319, 319, 319, 326, 318, 319, 323, 323, 319, 319, 319, 320, 327, 327, - 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 328, 81, - 328, 81, 81, 81, 81, 81, 328, 81, 81, 329, 329, 329, 329, 329, 329, 329, - 329, 329, 329, 329, 330, 331, 329, 329, 329, 332, 332, 332, 332, 332, - 332, 332, 332, 333, 333, 333, 333, 333, 333, 333, 333, 334, 334, 334, - 334, 334, 334, 334, 334, 335, 335, 335, 335, 335, 335, 335, 335, 335, 81, - 335, 335, 335, 335, 81, 81, 335, 335, 335, 335, 335, 335, 335, 81, 335, - 335, 335, 81, 81, 336, 336, 336, 337, 338, 337, 337, 337, 337, 337, 337, - 337, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, 339, - 339, 339, 339, 339, 339, 339, 339, 81, 81, 81, 340, 340, 340, 340, 340, - 340, 340, 340, 340, 340, 81, 81, 81, 81, 81, 81, 341, 341, 341, 341, 341, - 341, 341, 341, 341, 341, 341, 341, 341, 341, 81, 81, 342, 342, 342, 342, - 342, 342, 81, 81, 343, 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, - 344, 344, 344, 344, 344, 344, 344, 344, 344, 344, 345, 345, 344, 346, - 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, 347, - 347, 347, 347, 347, 348, 349, 81, 81, 81, 350, 350, 350, 350, 350, 350, - 350, 350, 350, 350, 350, 199, 199, 199, 351, 351, 351, 350, 350, 350, - 350, 350, 350, 350, 350, 81, 81, 81, 81, 81, 81, 81, 352, 352, 352, 352, - 352, 352, 352, 352, 352, 352, 352, 352, 352, 81, 352, 352, 352, 352, 353, - 353, 354, 81, 81, 81, 355, 355, 355, 355, 355, 355, 355, 355, 355, 355, - 356, 356, 357, 199, 199, 81, 358, 358, 358, 358, 358, 358, 358, 358, 358, - 358, 359, 359, 81, 81, 81, 81, 360, 360, 360, 360, 360, 360, 360, 360, - 360, 360, 360, 360, 360, 81, 360, 360, 360, 81, 361, 361, 81, 81, 81, 81, - 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 362, 363, 363, - 364, 363, 363, 363, 363, 363, 363, 363, 364, 364, 364, 364, 364, 364, - 364, 364, 363, 364, 364, 363, 363, 363, 363, 363, 363, 363, 363, 363, - 365, 363, 366, 366, 367, 368, 366, 369, 366, 370, 362, 371, 81, 81, 372, - 372, 372, 372, 372, 372, 372, 372, 372, 372, 81, 81, 81, 81, 81, 81, 373, - 373, 373, 373, 373, 373, 373, 373, 373, 373, 81, 81, 81, 81, 81, 81, 374, - 374, 375, 375, 376, 377, 378, 374, 379, 379, 374, 380, 380, 380, 381, 81, - 382, 382, 382, 382, 382, 382, 382, 382, 382, 382, 81, 81, 81, 81, 81, 81, - 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 383, 384, 383, 383, - 383, 383, 383, 81, 81, 81, 81, 81, 81, 81, 383, 383, 383, 383, 383, 380, - 380, 383, 383, 385, 383, 81, 81, 81, 81, 81, 344, 344, 344, 344, 344, - 344, 81, 81, 386, 386, 386, 386, 386, 386, 386, 386, 386, 386, 386, 386, - 386, 386, 386, 81, 387, 387, 387, 388, 388, 388, 388, 387, 387, 388, 388, - 388, 81, 81, 81, 81, 388, 388, 387, 388, 388, 388, 388, 388, 388, 389, - 390, 391, 81, 81, 81, 81, 392, 81, 81, 81, 393, 393, 394, 394, 394, 394, - 394, 394, 394, 394, 394, 394, 395, 395, 395, 395, 395, 395, 395, 395, - 395, 395, 395, 395, 395, 395, 81, 81, 395, 395, 395, 395, 395, 81, 81, - 81, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 396, 81, 81, - 81, 81, 396, 396, 81, 81, 81, 81, 81, 81, 397, 397, 397, 397, 397, 397, - 397, 397, 397, 397, 398, 81, 81, 81, 399, 399, 400, 400, 400, 400, 400, - 400, 400, 400, 401, 401, 401, 401, 401, 401, 401, 401, 401, 401, 401, - 401, 401, 401, 401, 402, 403, 404, 404, 405, 81, 81, 406, 406, 407, 407, - 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 407, 408, 409, 408, - 409, 409, 409, 409, 409, 409, 409, 81, 410, 408, 409, 408, 408, 409, 409, - 409, 409, 409, 409, 409, 409, 408, 408, 408, 408, 408, 408, 409, 409, - 411, 411, 411, 411, 411, 411, 411, 411, 81, 81, 412, 413, 413, 413, 413, - 413, 413, 413, 413, 413, 413, 81, 81, 81, 81, 81, 81, 414, 414, 414, 414, - 414, 414, 414, 415, 414, 414, 414, 414, 414, 414, 81, 81, 96, 96, 96, 96, - 96, 156, 156, 156, 156, 156, 156, 96, 96, 156, 416, 81, 417, 417, 417, - 417, 418, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, 419, - 419, 419, 419, 420, 418, 417, 417, 417, 417, 417, 418, 417, 418, 418, - 418, 418, 418, 417, 418, 421, 419, 419, 419, 419, 419, 419, 419, 81, 81, - 81, 81, 422, 422, 422, 422, 422, 422, 422, 422, 422, 422, 423, 423, 424, - 423, 423, 423, 423, 425, 425, 425, 425, 425, 425, 425, 425, 425, 425, - 426, 427, 426, 426, 426, 426, 426, 426, 426, 425, 425, 425, 425, 425, - 425, 425, 425, 425, 81, 81, 81, 428, 428, 429, 430, 430, 430, 430, 430, - 430, 430, 430, 430, 430, 430, 430, 430, 430, 429, 428, 428, 428, 428, - 429, 429, 428, 428, 431, 432, 428, 428, 430, 430, 433, 433, 433, 433, - 433, 433, 433, 433, 433, 433, 430, 430, 430, 430, 430, 430, 434, 434, - 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 434, 435, 436, - 437, 437, 436, 436, 436, 437, 436, 437, 437, 437, 438, 438, 81, 81, 81, - 81, 81, 81, 81, 81, 439, 439, 439, 439, 440, 440, 440, 440, 440, 440, - 440, 440, 440, 440, 440, 440, 441, 441, 441, 441, 441, 441, 441, 441, - 442, 442, 442, 442, 442, 442, 442, 442, 441, 441, 442, 443, 81, 81, 81, - 444, 444, 444, 444, 444, 445, 445, 445, 445, 445, 445, 445, 445, 445, - 445, 81, 81, 81, 440, 440, 440, 446, 446, 446, 446, 446, 446, 446, 446, - 446, 446, 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, 447, - 447, 447, 448, 448, 448, 448, 448, 448, 449, 449, 93, 81, 81, 81, 81, 81, - 81, 81, 328, 328, 328, 81, 81, 328, 328, 328, 450, 450, 450, 450, 450, - 450, 450, 450, 96, 96, 96, 330, 451, 156, 156, 156, 156, 156, 96, 96, - 156, 156, 156, 156, 96, 452, 451, 451, 451, 451, 451, 451, 451, 453, 453, - 453, 453, 156, 453, 453, 453, 453, 452, 452, 96, 453, 453, 452, 96, 96, - 81, 81, 81, 81, 81, 81, 56, 56, 56, 56, 56, 56, 79, 79, 79, 79, 79, 93, - 59, 59, 59, 59, 59, 59, 59, 59, 59, 82, 82, 82, 82, 82, 59, 59, 59, 59, - 82, 82, 82, 82, 82, 56, 56, 56, 56, 56, 454, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 59, 82, 96, 96, - 156, 96, 96, 96, 96, 96, 96, 96, 156, 96, 96, 455, 456, 156, 457, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 458, 459, 459, 156, 81, 96, 460, 156, 96, 156, 52, 56, 52, 56, 52, - 56, 56, 56, 56, 56, 56, 56, 56, 56, 52, 56, 79, 79, 79, 79, 79, 79, 79, - 79, 78, 78, 78, 78, 78, 78, 78, 78, 79, 79, 79, 79, 79, 79, 81, 81, 78, - 78, 78, 78, 78, 78, 81, 81, 81, 78, 81, 78, 81, 78, 81, 78, 461, 461, - 461, 461, 461, 461, 461, 461, 79, 79, 79, 79, 79, 81, 79, 79, 78, 78, 78, - 78, 461, 80, 79, 80, 80, 80, 79, 79, 79, 81, 79, 79, 78, 78, 78, 78, 461, - 80, 80, 80, 79, 79, 79, 79, 81, 81, 79, 79, 78, 78, 78, 78, 81, 80, 80, - 80, 78, 78, 78, 78, 78, 80, 80, 80, 81, 81, 79, 79, 79, 81, 79, 79, 78, - 78, 78, 78, 461, 462, 80, 81, 463, 463, 463, 463, 463, 463, 463, 464, - 463, 463, 463, 465, 466, 467, 468, 469, 470, 471, 472, 470, 473, 474, 38, - 84, 475, 476, 477, 42, 475, 476, 477, 42, 38, 38, 478, 84, 479, 479, 479, - 480, 481, 482, 483, 484, 485, 486, 487, 33, 488, 489, 488, 488, 489, 490, - 491, 491, 84, 42, 50, 38, 492, 492, 478, 493, 493, 84, 84, 84, 494, 477, - 495, 492, 492, 492, 84, 84, 84, 84, 84, 84, 84, 84, 496, 84, 493, 84, - 377, 84, 377, 377, 377, 377, 84, 377, 377, 463, 497, 498, 498, 498, 498, - 81, 499, 500, 501, 502, 503, 503, 503, 503, 503, 503, 504, 59, 81, 81, - 47, 504, 504, 504, 504, 504, 505, 505, 496, 477, 495, 506, 504, 47, 47, - 47, 47, 504, 504, 504, 504, 504, 505, 505, 496, 477, 495, 81, 59, 59, 59, - 59, 59, 81, 81, 81, 282, 282, 282, 282, 282, 282, 282, 507, 282, 508, - 282, 282, 36, 282, 282, 282, 282, 282, 282, 282, 282, 282, 507, 282, 282, - 282, 282, 507, 282, 282, 507, 282, 509, 509, 509, 509, 509, 509, 509, - 509, 96, 96, 451, 451, 96, 96, 96, 96, 451, 451, 451, 96, 96, 416, 416, - 416, 416, 96, 416, 416, 416, 451, 451, 96, 156, 96, 451, 451, 156, 156, - 156, 156, 96, 81, 81, 81, 81, 81, 81, 81, 40, 40, 510, 511, 40, 512, 40, - 510, 40, 511, 49, 510, 510, 510, 49, 49, 510, 510, 510, 513, 40, 510, - 514, 40, 496, 510, 510, 510, 510, 510, 40, 40, 40, 512, 512, 40, 510, 40, - 85, 40, 510, 40, 52, 515, 510, 510, 516, 49, 510, 510, 52, 510, 49, 453, - 453, 453, 453, 49, 40, 40, 49, 49, 510, 510, 496, 496, 496, 496, 496, - 510, 49, 49, 49, 49, 40, 496, 40, 40, 56, 317, 517, 517, 517, 518, 51, - 519, 517, 517, 517, 517, 517, 51, 518, 518, 51, 517, 520, 520, 520, 520, - 520, 520, 520, 520, 520, 520, 520, 520, 521, 521, 521, 521, 520, 520, - 521, 521, 521, 521, 521, 521, 521, 521, 521, 52, 56, 521, 521, 521, 521, - 51, 40, 40, 81, 81, 81, 81, 54, 54, 54, 54, 54, 512, 512, 512, 512, 512, - 496, 496, 40, 40, 40, 40, 496, 40, 40, 496, 40, 40, 496, 40, 40, 40, 40, - 40, 40, 40, 496, 40, 40, 40, 40, 40, 40, 40, 40, 40, 44, 44, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 40, 496, 496, 40, 40, 54, 40, 54, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 40, 44, 40, 40, 40, 40, 496, 496, 496, 496, - 496, 496, 496, 496, 496, 496, 496, 496, 54, 496, 54, 54, 496, 496, 496, - 54, 54, 496, 496, 54, 496, 496, 496, 54, 496, 54, 522, 523, 496, 54, 496, - 496, 496, 496, 54, 496, 496, 54, 54, 54, 54, 496, 496, 54, 496, 54, 496, - 54, 54, 54, 54, 54, 54, 496, 54, 496, 496, 496, 496, 496, 54, 54, 54, 54, - 496, 496, 496, 496, 54, 54, 496, 496, 54, 496, 496, 496, 54, 496, 496, - 496, 496, 496, 54, 496, 496, 496, 496, 496, 54, 54, 496, 496, 54, 54, 54, - 54, 496, 496, 54, 54, 496, 496, 54, 54, 496, 496, 496, 496, 496, 54, 496, - 496, 496, 54, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, 496, - 496, 54, 496, 496, 496, 496, 496, 496, 496, 524, 477, 495, 477, 495, 40, - 40, 40, 40, 40, 40, 512, 40, 40, 40, 40, 40, 40, 40, 525, 525, 40, 40, - 40, 40, 496, 496, 40, 40, 40, 40, 40, 40, 40, 526, 527, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 317, 317, 317, 317, 317, 317, 317, 317, 317, - 317, 317, 317, 317, 40, 496, 40, 40, 40, 40, 40, 40, 40, 40, 317, 40, 40, - 40, 40, 40, 496, 496, 496, 496, 496, 496, 496, 496, 496, 40, 40, 40, 40, - 40, 528, 528, 528, 528, 40, 40, 40, 525, 529, 529, 525, 40, 40, 40, 40, - 40, 40, 40, 40, 40, 40, 40, 81, 40, 40, 40, 81, 81, 81, 81, 81, 51, 51, - 51, 51, 51, 51, 51, 51, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, - 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, - 519, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 518, 512, 512, 512, - 512, 512, 512, 512, 512, 512, 512, 512, 512, 40, 40, 40, 40, 512, 512, - 512, 512, 531, 40, 40, 40, 40, 40, 512, 512, 512, 512, 40, 40, 512, 512, - 40, 512, 512, 512, 512, 512, 512, 512, 40, 40, 40, 40, 40, 40, 40, 40, - 512, 512, 40, 40, 512, 54, 40, 40, 40, 40, 512, 512, 40, 40, 512, 54, 40, - 40, 40, 40, 512, 512, 512, 40, 40, 512, 40, 40, 512, 512, 40, 40, 40, 40, - 40, 40, 40, 512, 496, 496, 496, 496, 496, 532, 532, 496, 529, 529, 529, - 529, 40, 512, 512, 40, 40, 512, 40, 40, 40, 40, 512, 512, 40, 40, 40, 40, - 525, 525, 531, 531, 529, 40, 529, 529, 533, 534, 533, 529, 40, 529, 529, - 529, 40, 40, 40, 40, 512, 40, 512, 40, 40, 40, 40, 40, 528, 528, 528, - 528, 528, 528, 528, 528, 528, 528, 528, 528, 40, 40, 40, 40, 512, 512, - 40, 512, 512, 512, 40, 512, 533, 512, 512, 40, 512, 512, 40, 54, 40, 40, - 40, 40, 40, 40, 40, 525, 40, 40, 40, 528, 40, 40, 40, 40, 40, 40, 40, 40, - 40, 40, 512, 512, 40, 528, 40, 40, 40, 40, 40, 40, 40, 40, 528, 528, 317, - 40, 40, 40, 40, 40, 40, 40, 40, 525, 525, 533, 529, 529, 529, 529, 525, - 525, 533, 533, 533, 512, 512, 512, 512, 533, 528, 533, 533, 533, 512, - 533, 525, 512, 512, 512, 533, 533, 512, 512, 533, 512, 512, 533, 533, - 533, 40, 512, 40, 40, 40, 40, 512, 512, 525, 512, 512, 512, 512, 512, - 512, 533, 525, 525, 533, 525, 512, 533, 533, 535, 525, 512, 512, 525, - 533, 533, 529, 529, 529, 529, 529, 528, 40, 40, 529, 529, 536, 536, 534, - 534, 40, 40, 528, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 44, 40, - 40, 40, 40, 40, 40, 528, 40, 528, 40, 40, 40, 40, 528, 528, 528, 40, 537, - 40, 40, 40, 538, 538, 538, 538, 538, 538, 40, 539, 539, 529, 40, 40, 40, - 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 51, - 51, 519, 519, 519, 519, 519, 519, 519, 519, 519, 519, 519, 519, 40, 528, - 528, 528, 40, 40, 40, 40, 40, 40, 40, 528, 496, 496, 496, 496, 496, 477, - 495, 496, 496, 496, 496, 496, 496, 496, 16, 31, 16, 31, 16, 31, 16, 31, - 477, 495, 540, 540, 540, 540, 540, 540, 540, 540, 496, 496, 496, 477, - 495, 16, 31, 477, 495, 477, 495, 477, 495, 477, 495, 477, 495, 496, 496, - 496, 496, 496, 496, 496, 477, 495, 477, 495, 496, 496, 496, 496, 496, - 496, 496, 496, 477, 495, 496, 496, 40, 40, 40, 528, 528, 40, 40, 40, 496, - 496, 496, 496, 496, 40, 40, 496, 496, 496, 496, 496, 496, 40, 40, 40, - 528, 40, 40, 40, 40, 537, 512, 512, 40, 40, 40, 40, 81, 81, 40, 40, 40, - 40, 40, 40, 40, 40, 81, 81, 40, 81, 40, 40, 40, 40, 40, 40, 541, 541, - 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 541, 81, 542, - 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 542, 81, - 52, 56, 52, 52, 52, 56, 56, 52, 56, 52, 56, 52, 56, 52, 52, 52, 52, 56, - 52, 56, 56, 52, 56, 56, 56, 56, 56, 56, 59, 59, 52, 52, 87, 88, 87, 88, - 88, 543, 543, 543, 543, 543, 543, 87, 88, 87, 88, 544, 544, 544, 87, 88, - 81, 81, 81, 81, 81, 545, 546, 546, 546, 547, 545, 546, 329, 329, 329, - 329, 329, 329, 81, 329, 81, 81, 81, 81, 81, 329, 81, 81, 548, 548, 548, - 548, 548, 548, 548, 548, 81, 81, 81, 81, 81, 81, 81, 549, 550, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 551, 95, 95, 95, 95, 95, - 95, 95, 95, 552, 552, 42, 50, 42, 50, 552, 552, 552, 42, 50, 552, 42, 50, - 377, 377, 377, 377, 377, 377, 377, 377, 84, 472, 553, 377, 554, 84, 42, - 50, 84, 84, 42, 50, 477, 495, 477, 495, 477, 495, 477, 495, 377, 377, - 377, 377, 375, 60, 377, 377, 84, 377, 377, 84, 84, 84, 84, 84, 555, 555, - 377, 377, 377, 84, 472, 377, 477, 377, 377, 377, 377, 377, 377, 377, 377, - 84, 377, 84, 377, 81, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, - 81, 556, 556, 556, 556, 556, 556, 556, 556, 556, 81, 81, 81, 81, 556, - 556, 556, 556, 556, 556, 81, 81, 525, 525, 525, 525, 525, 525, 525, 525, - 525, 525, 525, 525, 81, 81, 81, 81, 557, 558, 558, 559, 525, 560, 561, - 562, 526, 527, 526, 527, 526, 527, 526, 527, 526, 527, 525, 525, 526, - 527, 526, 527, 526, 527, 526, 527, 563, 526, 527, 527, 525, 562, 562, - 562, 562, 562, 562, 562, 562, 562, 564, 565, 566, 567, 568, 568, 569, - 570, 570, 570, 570, 571, 525, 525, 562, 562, 562, 560, 572, 559, 525, - 529, 81, 573, 574, 573, 574, 573, 574, 573, 574, 573, 574, 574, 574, 574, - 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 574, 573, - 574, 574, 574, 574, 574, 574, 574, 573, 574, 573, 574, 573, 574, 574, - 574, 574, 574, 574, 573, 574, 574, 574, 574, 574, 574, 573, 573, 81, 81, - 575, 575, 576, 576, 577, 577, 574, 563, 578, 579, 578, 579, 578, 579, - 578, 579, 578, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, 579, - 579, 579, 579, 579, 579, 579, 578, 579, 579, 579, 579, 579, 579, 579, - 578, 579, 578, 579, 578, 579, 579, 579, 579, 579, 579, 578, 579, 579, - 579, 579, 579, 579, 578, 578, 579, 579, 579, 579, 580, 581, 582, 582, - 579, 81, 81, 81, 81, 81, 583, 583, 583, 583, 583, 583, 583, 583, 583, - 583, 583, 81, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, - 584, 584, 584, 584, 584, 584, 584, 584, 584, 584, 81, 585, 585, 586, 586, - 586, 586, 585, 585, 585, 585, 585, 585, 585, 585, 585, 585, 583, 583, - 583, 81, 81, 81, 81, 81, 578, 578, 578, 578, 578, 578, 578, 578, 587, - 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 587, 588, 588, 81, - 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, 585, 585, 585, 585, - 585, 585, 589, 589, 589, 589, 589, 589, 589, 589, 525, 590, 590, 590, - 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 590, 587, 587, - 587, 587, 588, 588, 588, 585, 585, 590, 590, 590, 590, 590, 590, 590, - 585, 585, 585, 585, 525, 525, 525, 525, 591, 591, 591, 591, 591, 591, - 591, 591, 591, 591, 591, 591, 591, 591, 591, 81, 585, 585, 585, 585, 585, - 585, 585, 525, 525, 525, 525, 585, 585, 585, 585, 585, 585, 585, 585, - 585, 585, 585, 525, 525, 592, 592, 592, 592, 592, 592, 592, 592, 592, - 592, 592, 592, 592, 592, 593, 593, 593, 593, 593, 593, 593, 593, 593, - 593, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, 594, - 595, 594, 594, 594, 594, 594, 594, 594, 81, 81, 81, 596, 596, 596, 596, - 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 596, 81, 597, 597, 597, - 597, 597, 597, 597, 597, 598, 598, 598, 598, 598, 598, 599, 599, 600, - 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 601, 602, 603, - 602, 604, 604, 604, 604, 604, 604, 604, 604, 604, 604, 600, 600, 81, 81, - 81, 81, 90, 93, 90, 93, 90, 93, 605, 95, 97, 97, 97, 606, 95, 95, 95, 95, - 95, 95, 95, 95, 95, 95, 606, 607, 90, 93, 90, 93, 454, 454, 95, 95, 608, - 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 608, 609, - 609, 609, 609, 609, 609, 609, 609, 609, 609, 610, 610, 611, 612, 612, - 612, 612, 612, 62, 62, 62, 62, 62, 62, 62, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 62, 62, 52, 56, 52, 56, 52, 56, 56, 56, 52, 56, 52, 56, 52, 56, - 59, 56, 56, 56, 56, 56, 56, 56, 56, 52, 56, 52, 56, 52, 52, 56, 60, 613, - 613, 52, 56, 52, 56, 57, 52, 56, 52, 56, 56, 56, 52, 56, 52, 56, 52, 52, - 52, 52, 52, 56, 52, 52, 52, 52, 52, 56, 52, 56, 52, 56, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 57, 59, 59, 56, 57, 57, 57, 57, 57, - 614, 614, 615, 614, 614, 614, 616, 614, 614, 614, 614, 615, 614, 614, - 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 614, 617, - 617, 615, 615, 617, 618, 618, 618, 618, 81, 81, 81, 81, 619, 619, 619, - 619, 619, 619, 317, 317, 507, 516, 81, 81, 81, 81, 81, 81, 620, 620, 620, - 620, 620, 620, 620, 620, 620, 620, 620, 620, 621, 621, 622, 622, 623, - 623, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, 624, - 624, 624, 624, 624, 624, 623, 623, 623, 623, 623, 623, 623, 623, 623, - 623, 623, 623, 623, 623, 623, 623, 625, 626, 81, 81, 81, 81, 81, 81, 81, - 81, 627, 627, 628, 628, 628, 628, 628, 628, 628, 628, 628, 628, 81, 81, - 81, 81, 81, 81, 198, 198, 198, 198, 198, 198, 198, 198, 198, 198, 195, - 195, 195, 195, 195, 195, 201, 201, 201, 195, 629, 195, 195, 193, 630, - 630, 630, 630, 630, 630, 630, 630, 630, 630, 631, 631, 631, 631, 631, - 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, 631, - 631, 632, 632, 632, 632, 632, 633, 633, 633, 199, 634, 635, 635, 635, - 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 635, 636, 636, - 636, 636, 636, 636, 636, 636, 636, 636, 636, 637, 638, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 639, 332, 332, 332, 332, 332, 81, 81, 81, - 640, 640, 640, 641, 642, 642, 642, 642, 642, 642, 642, 642, 642, 642, - 642, 642, 642, 642, 642, 643, 641, 641, 640, 640, 640, 640, 641, 641, - 640, 641, 641, 641, 644, 645, 645, 645, 645, 645, 645, 646, 646, 646, - 645, 645, 645, 645, 81, 61, 647, 647, 647, 647, 647, 647, 647, 647, 647, - 647, 81, 81, 81, 81, 645, 645, 318, 318, 318, 318, 318, 320, 648, 318, - 323, 323, 318, 318, 318, 318, 318, 81, 649, 649, 649, 649, 649, 649, 649, - 649, 649, 650, 650, 650, 650, 650, 650, 651, 651, 650, 650, 651, 651, - 650, 650, 81, 649, 649, 649, 650, 649, 649, 649, 649, 649, 649, 649, 649, - 650, 651, 81, 81, 652, 652, 652, 652, 652, 652, 652, 652, 652, 652, 81, - 81, 653, 654, 654, 654, 648, 318, 318, 318, 318, 318, 318, 327, 327, 327, - 318, 319, 320, 319, 318, 318, 655, 655, 655, 655, 655, 655, 655, 655, - 656, 655, 656, 656, 657, 655, 655, 656, 656, 655, 655, 655, 655, 655, - 656, 656, 655, 656, 655, 81, 81, 81, 81, 81, 81, 81, 81, 655, 655, 658, - 659, 659, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 660, 661, - 662, 662, 661, 661, 663, 663, 660, 664, 664, 661, 665, 81, 81, 335, 335, - 335, 335, 335, 335, 81, 56, 56, 56, 613, 59, 59, 59, 59, 56, 56, 56, 56, - 56, 79, 81, 81, 342, 342, 342, 342, 342, 342, 342, 342, 660, 660, 660, - 661, 661, 662, 661, 661, 662, 661, 661, 663, 661, 665, 81, 81, 666, 666, - 666, 666, 666, 666, 666, 666, 666, 666, 81, 81, 81, 81, 81, 81, 667, 668, - 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, 668, - 668, 668, 668, 668, 667, 668, 668, 668, 668, 668, 668, 668, 81, 81, 81, - 81, 333, 333, 333, 333, 333, 333, 333, 81, 81, 81, 81, 334, 334, 334, - 334, 334, 334, 334, 334, 334, 81, 81, 81, 81, 669, 669, 669, 669, 669, - 669, 669, 669, 670, 670, 670, 670, 670, 670, 670, 670, 592, 592, 593, - 593, 593, 593, 593, 593, 56, 56, 56, 56, 56, 56, 56, 81, 81, 81, 81, 101, - 101, 101, 101, 101, 81, 81, 81, 81, 81, 129, 671, 129, 129, 672, 129, - 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 129, 81, 129, 129, - 129, 129, 129, 81, 129, 81, 129, 129, 81, 129, 129, 81, 129, 129, 146, - 146, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, 673, - 673, 673, 673, 81, 81, 81, 81, 81, 81, 81, 81, 81, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 495, 477, 81, 81, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 135, 138, 81, 81, 674, 674, 674, 674, 674, - 674, 674, 674, 675, 558, 558, 675, 675, 676, 676, 526, 527, 677, 81, 81, - 81, 81, 81, 81, 96, 96, 96, 96, 96, 96, 96, 156, 156, 156, 156, 156, 156, - 156, 95, 95, 559, 569, 569, 678, 678, 526, 527, 526, 527, 526, 527, 526, - 527, 526, 527, 526, 527, 526, 527, 526, 527, 559, 559, 526, 527, 559, - 559, 559, 559, 678, 678, 678, 679, 559, 679, 81, 580, 680, 676, 676, 569, - 526, 527, 526, 527, 526, 527, 681, 559, 559, 682, 683, 684, 684, 684, 81, - 559, 685, 686, 559, 81, 81, 81, 81, 146, 146, 146, 146, 146, 81, 81, 497, - 81, 687, 688, 689, 690, 691, 688, 688, 692, 693, 688, 694, 695, 696, 695, - 697, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698, 699, 700, 701, - 701, 701, 687, 688, 702, 702, 702, 702, 702, 702, 702, 702, 702, 702, - 702, 702, 702, 702, 702, 702, 702, 702, 692, 688, 693, 703, 704, 703, - 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, 705, - 705, 705, 705, 705, 692, 701, 693, 701, 692, 693, 706, 707, 708, 706, - 709, 710, 711, 711, 711, 711, 711, 711, 711, 711, 711, 712, 710, 710, - 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, 710, - 710, 710, 710, 710, 710, 713, 713, 714, 714, 714, 714, 714, 714, 714, - 714, 714, 714, 714, 714, 714, 714, 714, 81, 81, 81, 714, 714, 714, 714, - 714, 714, 81, 81, 714, 714, 714, 81, 81, 81, 715, 690, 701, 703, 716, - 690, 690, 81, 717, 718, 718, 718, 718, 717, 717, 81, 81, 719, 719, 719, - 720, 512, 81, 81, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, - 721, 81, 721, 721, 721, 721, 721, 721, 721, 721, 721, 721, 81, 721, 721, - 721, 81, 721, 721, 81, 721, 721, 721, 721, 721, 721, 721, 81, 81, 721, - 721, 721, 81, 81, 81, 81, 81, 199, 377, 199, 81, 81, 81, 81, 619, 619, - 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 619, 81, 81, 81, 317, - 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 722, 723, - 723, 723, 723, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, 724, - 724, 724, 724, 724, 724, 724, 723, 723, 724, 725, 725, 81, 40, 40, 40, - 40, 81, 81, 81, 81, 724, 81, 81, 81, 81, 81, 81, 81, 317, 317, 317, 317, - 317, 156, 81, 81, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, 726, - 726, 726, 81, 81, 81, 727, 727, 727, 727, 727, 727, 727, 727, 727, 81, - 81, 81, 81, 81, 81, 81, 156, 504, 504, 504, 504, 504, 504, 504, 504, 504, - 504, 504, 504, 504, 504, 504, 504, 504, 504, 504, 81, 81, 81, 81, 728, - 728, 728, 728, 728, 728, 728, 728, 729, 729, 729, 729, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 728, 728, 728, 730, 730, 730, 730, 730, 730, 730, - 730, 730, 731, 730, 730, 730, 730, 730, 730, 730, 730, 731, 81, 81, 81, - 81, 81, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, 732, - 732, 733, 733, 733, 733, 733, 81, 81, 81, 81, 81, 734, 734, 734, 734, - 734, 734, 734, 734, 734, 734, 734, 734, 734, 734, 81, 735, 736, 736, 736, - 736, 736, 736, 736, 736, 736, 736, 736, 736, 81, 81, 81, 81, 737, 738, - 738, 738, 738, 738, 81, 81, 739, 739, 739, 739, 739, 739, 739, 739, 740, - 740, 740, 740, 740, 740, 740, 740, 741, 741, 741, 741, 741, 741, 741, - 741, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, 742, - 742, 81, 81, 743, 743, 743, 743, 743, 743, 743, 743, 743, 743, 81, 81, - 81, 81, 81, 81, 744, 744, 744, 744, 744, 744, 744, 744, 744, 744, 744, - 744, 81, 81, 81, 81, 745, 745, 745, 745, 745, 745, 745, 745, 745, 745, - 745, 745, 81, 81, 81, 81, 746, 746, 746, 746, 746, 746, 746, 746, 747, - 747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 747, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 748, 749, 749, 749, 749, 749, 749, 749, 749, - 749, 749, 749, 749, 749, 749, 749, 81, 749, 749, 749, 749, 749, 749, 81, - 81, 750, 750, 750, 750, 750, 750, 81, 81, 750, 81, 750, 750, 750, 750, - 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, 750, - 750, 750, 81, 750, 750, 81, 81, 81, 750, 81, 81, 750, 751, 751, 751, 751, - 751, 751, 751, 751, 751, 751, 751, 751, 751, 751, 81, 752, 753, 753, 753, - 753, 753, 753, 753, 753, 754, 754, 754, 754, 754, 754, 754, 754, 754, - 754, 754, 754, 754, 754, 754, 755, 755, 756, 756, 756, 756, 756, 756, - 756, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, 757, - 757, 757, 81, 81, 81, 81, 81, 81, 81, 81, 758, 758, 758, 758, 758, 758, - 758, 758, 758, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 759, 81, - 759, 759, 81, 81, 81, 81, 81, 760, 760, 760, 760, 760, 761, 761, 761, - 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 761, 762, 762, 762, - 762, 762, 762, 81, 81, 81, 763, 764, 764, 764, 764, 764, 764, 764, 764, - 764, 764, 81, 81, 81, 81, 81, 765, 766, 766, 766, 766, 766, 766, 766, - 766, 767, 767, 767, 767, 767, 767, 767, 767, 81, 81, 81, 81, 768, 768, - 767, 767, 768, 768, 768, 768, 768, 768, 768, 768, 81, 81, 768, 768, 768, - 768, 768, 768, 769, 770, 770, 770, 81, 770, 770, 81, 81, 81, 81, 81, 770, - 771, 770, 772, 769, 769, 769, 769, 81, 769, 769, 769, 81, 769, 769, 769, - 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, 769, - 769, 769, 769, 769, 81, 81, 772, 773, 771, 81, 81, 81, 81, 774, 775, 775, - 775, 775, 775, 775, 775, 775, 775, 81, 81, 81, 81, 81, 81, 81, 776, 776, - 776, 776, 776, 776, 776, 776, 777, 81, 81, 81, 81, 81, 81, 81, 778, 778, - 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 778, 779, 779, 780, - 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 781, 782, - 782, 782, 783, 783, 783, 783, 783, 783, 783, 783, 784, 783, 783, 783, - 783, 783, 783, 783, 783, 783, 783, 783, 783, 785, 786, 81, 81, 81, 81, - 787, 787, 787, 787, 787, 788, 788, 788, 788, 788, 788, 789, 81, 790, 790, - 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 790, 81, 81, 81, - 791, 791, 791, 791, 791, 791, 791, 792, 792, 792, 792, 792, 792, 792, - 792, 792, 792, 792, 792, 792, 792, 81, 81, 793, 793, 793, 793, 793, 793, - 793, 793, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 794, 81, 81, - 81, 81, 81, 795, 795, 795, 795, 795, 795, 795, 795, 796, 796, 796, 796, - 796, 796, 796, 796, 796, 796, 81, 81, 81, 81, 81, 81, 81, 797, 797, 797, - 797, 81, 81, 81, 81, 798, 798, 798, 798, 798, 798, 798, 799, 799, 799, - 799, 799, 799, 799, 799, 799, 81, 81, 81, 81, 81, 81, 81, 800, 800, 800, - 800, 800, 800, 800, 800, 800, 800, 800, 81, 81, 81, 81, 81, 801, 801, - 801, 801, 801, 801, 801, 801, 801, 801, 801, 81, 81, 81, 81, 81, 81, 81, - 802, 802, 802, 802, 802, 802, 803, 803, 803, 803, 803, 803, 803, 803, - 803, 803, 803, 803, 804, 804, 804, 804, 805, 805, 805, 805, 805, 805, - 805, 805, 805, 805, 81, 81, 81, 81, 81, 81, 806, 806, 806, 806, 806, 806, - 806, 806, 806, 806, 806, 806, 806, 806, 806, 81, 807, 807, 807, 807, 807, - 807, 807, 807, 807, 807, 807, 807, 807, 808, 808, 808, 808, 808, 808, - 808, 808, 808, 808, 807, 809, 809, 809, 809, 809, 809, 809, 809, 809, - 809, 809, 809, 809, 809, 810, 810, 811, 811, 811, 810, 811, 810, 810, - 810, 810, 812, 812, 812, 812, 813, 813, 813, 813, 813, 81, 81, 81, 81, - 81, 81, 814, 815, 814, 816, 816, 816, 816, 816, 816, 816, 816, 816, 816, - 816, 816, 816, 815, 815, 815, 815, 815, 815, 815, 815, 815, 815, 815, - 815, 815, 815, 817, 818, 818, 819, 819, 819, 819, 819, 81, 81, 81, 81, - 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, 820, - 820, 820, 820, 820, 820, 820, 821, 821, 821, 821, 821, 821, 821, 821, - 821, 821, 81, 81, 81, 81, 81, 81, 81, 817, 822, 822, 823, 824, 824, 824, - 824, 824, 824, 824, 824, 824, 824, 824, 824, 824, 823, 823, 823, 822, - 822, 822, 822, 823, 823, 825, 826, 827, 827, 828, 829, 829, 829, 829, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, 828, 81, 81, 830, 830, 830, 830, - 830, 830, 830, 830, 830, 81, 81, 81, 81, 81, 81, 81, 831, 831, 831, 831, - 831, 831, 831, 831, 831, 831, 81, 81, 81, 81, 81, 81, 832, 832, 832, 833, - 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, 833, - 833, 833, 833, 833, 833, 834, 834, 834, 834, 834, 835, 834, 834, 834, - 834, 834, 834, 836, 836, 81, 837, 837, 837, 837, 837, 837, 837, 837, 837, - 837, 838, 838, 838, 838, 833, 835, 835, 81, 839, 839, 839, 839, 839, 839, - 839, 839, 839, 839, 839, 840, 841, 842, 839, 81, 843, 843, 844, 845, 845, - 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, 845, - 844, 844, 844, 843, 843, 843, 843, 843, 843, 843, 843, 843, 844, 846, - 845, 845, 845, 845, 847, 847, 848, 847, 843, 849, 843, 843, 848, 81, 81, - 850, 850, 850, 850, 850, 850, 850, 850, 850, 850, 845, 851, 845, 847, - 847, 847, 81, 852, 852, 852, 852, 852, 852, 852, 852, 852, 852, 852, 852, - 852, 852, 852, 852, 852, 852, 852, 852, 81, 81, 81, 853, 853, 853, 853, - 853, 853, 853, 853, 853, 853, 81, 853, 853, 853, 853, 853, 853, 853, 853, - 853, 854, 854, 854, 855, 855, 855, 854, 854, 855, 856, 857, 855, 858, - 858, 859, 858, 858, 859, 855, 81, 860, 860, 860, 860, 860, 860, 860, 81, - 860, 81, 860, 860, 860, 860, 81, 860, 860, 860, 860, 860, 860, 860, 860, - 860, 860, 860, 860, 860, 860, 860, 81, 860, 860, 861, 81, 81, 81, 81, 81, - 81, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, 862, - 862, 863, 864, 864, 864, 863, 863, 863, 863, 863, 863, 865, 866, 81, 81, - 81, 81, 81, 867, 867, 867, 867, 867, 867, 867, 867, 867, 867, 81, 81, 81, - 81, 81, 81, 868, 868, 869, 869, 81, 870, 870, 870, 870, 870, 870, 870, - 870, 81, 81, 870, 870, 81, 81, 870, 870, 870, 870, 870, 870, 870, 870, - 870, 870, 870, 870, 870, 870, 81, 870, 870, 870, 870, 870, 870, 870, 81, - 870, 870, 81, 870, 870, 870, 870, 870, 81, 871, 872, 870, 869, 869, 868, - 869, 869, 869, 869, 81, 81, 869, 869, 81, 81, 869, 869, 873, 81, 81, 870, - 81, 81, 81, 81, 81, 81, 869, 81, 81, 81, 81, 81, 870, 870, 870, 870, 870, - 869, 869, 81, 81, 874, 874, 874, 874, 874, 874, 874, 81, 81, 81, 875, - 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 875, 876, 876, - 876, 877, 877, 877, 877, 877, 877, 877, 877, 876, 876, 878, 877, 877, - 876, 879, 875, 875, 875, 875, 880, 880, 880, 880, 881, 882, 882, 882, - 882, 882, 882, 882, 882, 882, 882, 81, 880, 81, 881, 883, 81, 884, 884, - 884, 884, 884, 884, 884, 884, 885, 885, 885, 886, 886, 886, 886, 886, - 886, 885, 886, 885, 885, 885, 885, 886, 886, 885, 887, 888, 884, 884, - 889, 884, 890, 890, 890, 890, 890, 890, 890, 890, 890, 890, 81, 81, 81, - 81, 81, 81, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, 891, - 891, 891, 891, 892, 892, 892, 893, 893, 893, 893, 81, 81, 892, 892, 892, - 892, 893, 893, 892, 894, 895, 896, 897, 897, 898, 898, 899, 899, 899, - 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, 897, - 897, 891, 891, 891, 891, 893, 893, 81, 81, 900, 900, 900, 900, 900, 900, - 900, 900, 901, 901, 901, 902, 902, 902, 902, 902, 902, 902, 902, 901, - 901, 902, 901, 903, 902, 904, 904, 905, 900, 81, 81, 81, 906, 906, 906, - 906, 906, 906, 906, 906, 906, 906, 81, 81, 81, 81, 81, 81, 907, 907, 907, - 907, 907, 907, 907, 907, 907, 907, 907, 907, 907, 81, 81, 81, 908, 908, - 908, 908, 908, 908, 908, 908, 908, 908, 908, 909, 910, 909, 910, 910, - 909, 909, 909, 909, 909, 909, 911, 912, 913, 913, 913, 913, 913, 913, - 913, 913, 913, 913, 81, 81, 81, 81, 81, 81, 914, 914, 914, 914, 914, 914, - 914, 914, 914, 914, 914, 81, 81, 915, 915, 915, 916, 916, 915, 915, 915, - 915, 916, 915, 915, 915, 915, 917, 81, 81, 81, 81, 918, 918, 918, 918, - 918, 918, 918, 918, 918, 918, 919, 919, 920, 920, 920, 921, 922, 922, - 922, 922, 922, 922, 922, 922, 922, 922, 922, 922, 923, 923, 923, 924, - 924, 924, 924, 924, 924, 924, 924, 924, 923, 925, 926, 927, 81, 81, 81, - 81, 928, 928, 928, 928, 928, 928, 928, 928, 929, 929, 929, 929, 929, 929, - 929, 929, 930, 930, 930, 930, 930, 930, 930, 930, 930, 930, 931, 931, - 931, 931, 931, 931, 931, 931, 931, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 932, 933, 934, 934, 934, 934, 934, 934, 935, 935, 934, 934, - 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, 933, - 933, 933, 934, 936, 934, 934, 934, 934, 937, 933, 934, 934, 934, 934, - 938, 939, 940, 940, 940, 940, 938, 939, 936, 941, 942, 942, 942, 942, - 942, 942, 943, 943, 942, 942, 942, 941, 941, 941, 941, 941, 941, 941, - 941, 941, 941, 941, 941, 941, 941, 941, 941, 81, 81, 941, 941, 941, 941, - 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 942, 943, - 942, 944, 945, 945, 945, 941, 946, 946, 946, 945, 945, 81, 81, 81, 81, - 81, 947, 947, 947, 947, 947, 947, 947, 947, 947, 81, 81, 81, 81, 81, 81, - 81, 948, 948, 948, 948, 948, 948, 948, 948, 948, 81, 948, 948, 948, 948, - 948, 948, 948, 948, 948, 948, 948, 948, 948, 949, 950, 950, 950, 950, - 950, 950, 950, 81, 950, 950, 950, 950, 950, 950, 949, 951, 948, 952, 952, - 952, 952, 952, 81, 81, 953, 953, 953, 953, 953, 953, 953, 953, 953, 953, - 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, 954, - 954, 954, 954, 954, 954, 81, 81, 81, 955, 956, 957, 957, 957, 957, 957, - 957, 957, 957, 957, 957, 957, 957, 957, 957, 81, 81, 958, 958, 958, 958, - 958, 958, 958, 958, 958, 958, 958, 958, 958, 958, 81, 959, 958, 958, 958, - 958, 958, 958, 958, 959, 958, 958, 959, 958, 958, 81, 960, 960, 960, 960, - 960, 960, 960, 81, 960, 960, 81, 960, 960, 960, 960, 960, 960, 960, 960, - 960, 960, 960, 960, 960, 960, 961, 961, 961, 961, 961, 961, 81, 81, 81, - 961, 81, 961, 961, 81, 961, 961, 961, 962, 961, 963, 963, 960, 961, 964, - 964, 964, 964, 964, 964, 964, 964, 964, 964, 81, 81, 81, 81, 81, 81, 965, - 965, 965, 965, 965, 965, 81, 965, 965, 81, 965, 965, 965, 965, 965, 965, - 965, 965, 965, 965, 965, 965, 965, 965, 965, 965, 966, 966, 966, 966, - 966, 81, 967, 967, 81, 966, 966, 967, 966, 968, 965, 81, 81, 81, 81, 81, - 81, 81, 969, 969, 969, 969, 969, 969, 969, 969, 969, 969, 81, 81, 81, 81, - 81, 81, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 970, 971, 971, - 972, 972, 973, 973, 81, 81, 81, 81, 81, 81, 81, 974, 974, 974, 974, 974, - 974, 974, 974, 974, 974, 81, 81, 81, 81, 81, 81, 975, 975, 975, 975, 975, - 975, 975, 975, 975, 975, 975, 975, 975, 975, 975, 81, 976, 976, 976, 976, - 976, 81, 81, 81, 974, 974, 974, 974, 81, 81, 81, 81, 977, 977, 977, 977, - 977, 977, 977, 977, 978, 978, 978, 979, 979, 979, 977, 977, 977, 977, - 979, 977, 977, 977, 978, 979, 978, 979, 977, 977, 977, 977, 977, 977, - 977, 978, 979, 979, 977, 977, 977, 977, 977, 977, 977, 977, 977, 977, - 977, 81, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, 980, - 980, 981, 982, 980, 980, 980, 980, 980, 980, 980, 81, 608, 81, 81, 81, - 81, 81, 81, 81, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, 983, - 983, 983, 983, 983, 81, 984, 984, 984, 984, 984, 984, 984, 984, 984, 984, - 81, 81, 81, 81, 985, 985, 986, 986, 986, 986, 986, 986, 986, 986, 986, - 986, 986, 986, 986, 986, 81, 81, 987, 987, 987, 987, 987, 988, 81, 81, - 989, 989, 989, 989, 989, 989, 989, 989, 990, 990, 990, 990, 990, 990, - 990, 991, 991, 991, 992, 992, 993, 993, 993, 993, 994, 994, 994, 994, - 991, 993, 81, 81, 995, 995, 995, 995, 995, 995, 995, 995, 995, 995, 81, - 996, 996, 996, 996, 996, 996, 996, 81, 989, 989, 989, 989, 989, 81, 81, - 81, 81, 81, 989, 989, 989, 997, 997, 997, 997, 997, 997, 997, 997, 998, - 998, 998, 998, 998, 998, 998, 998, 999, 999, 999, 999, 999, 999, 999, - 999, 999, 999, 999, 999, 999, 999, 999, 1000, 1000, 1001, 1001, 81, 81, - 81, 81, 81, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, 1002, - 1002, 1002, 1002, 81, 81, 81, 1002, 1003, 1003, 1003, 1003, 1003, 1003, - 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, 1003, - 1003, 1003, 1003, 1003, 81, 81, 81, 81, 81, 81, 81, 81, 1004, 1004, 1004, - 1004, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, 1005, - 1005, 1005, 1006, 1007, 81, 81, 81, 81, 81, 81, 1008, 1008, 1008, 1008, - 1008, 1008, 1008, 1008, 1008, 1008, 81, 81, 81, 81, 81, 81, 1008, 1008, - 1008, 81, 81, 81, 81, 81, 579, 574, 574, 574, 574, 574, 574, 574, 574, - 574, 574, 574, 574, 574, 574, 81, 1009, 1009, 1009, 1009, 1009, 1009, - 1009, 1009, 1009, 1009, 1009, 1009, 81, 81, 81, 81, 1010, 1010, 1010, - 1010, 1010, 1010, 1010, 1010, 1010, 1010, 1010, 81, 81, 81, 81, 81, 1010, - 1010, 1010, 1010, 1010, 81, 81, 81, 1010, 81, 81, 81, 81, 81, 81, 81, - 1010, 1010, 81, 81, 1011, 1012, 1013, 1014, 503, 503, 503, 503, 81, 81, - 81, 81, 317, 317, 317, 317, 317, 317, 81, 81, 317, 317, 317, 317, 317, - 317, 317, 81, 81, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, 317, - 317, 1015, 1015, 451, 451, 451, 317, 317, 317, 1016, 1015, 1015, 1015, - 1015, 1015, 503, 503, 503, 503, 503, 503, 503, 503, 156, 156, 156, 156, - 156, 156, 156, 156, 317, 317, 96, 96, 96, 96, 96, 156, 156, 317, 317, - 317, 317, 317, 317, 96, 96, 96, 96, 317, 317, 317, 81, 81, 81, 81, 81, - 81, 81, 724, 724, 1017, 1017, 1017, 724, 81, 81, 619, 619, 619, 619, 81, - 81, 81, 81, 619, 81, 81, 81, 81, 81, 81, 81, 510, 510, 510, 510, 510, - 510, 510, 510, 510, 510, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 510, 510, 510, 510, 510, 510, 510, 510, 510, 510, - 49, 49, 49, 49, 49, 49, 49, 81, 49, 49, 49, 49, 49, 49, 510, 81, 510, - 510, 81, 81, 510, 81, 81, 510, 510, 81, 81, 510, 510, 510, 510, 81, 510, - 510, 49, 49, 81, 49, 81, 49, 49, 49, 49, 49, 49, 49, 81, 49, 49, 49, 49, - 49, 49, 49, 510, 510, 81, 510, 510, 510, 510, 81, 81, 510, 510, 510, 510, - 510, 510, 510, 510, 81, 510, 510, 510, 510, 510, 510, 510, 81, 49, 49, - 510, 510, 81, 510, 510, 510, 510, 81, 510, 510, 510, 510, 510, 81, 510, - 81, 81, 81, 510, 510, 510, 510, 510, 510, 510, 81, 49, 49, 49, 49, 49, - 49, 49, 49, 49, 49, 49, 49, 81, 81, 510, 1018, 49, 49, 49, 49, 49, 49, - 49, 49, 49, 496, 49, 49, 49, 49, 49, 49, 510, 510, 510, 510, 510, 510, - 510, 510, 510, 1018, 49, 49, 49, 49, 49, 49, 49, 49, 49, 496, 49, 49, - 510, 510, 510, 510, 510, 1018, 49, 49, 49, 49, 49, 49, 49, 49, 49, 496, - 49, 49, 49, 49, 49, 49, 510, 510, 510, 510, 510, 510, 510, 510, 510, - 1018, 49, 496, 49, 49, 49, 49, 49, 49, 49, 49, 510, 49, 81, 81, 1019, - 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1019, 1020, 1020, 1020, - 1020, 1020, 1020, 1020, 1020, 1021, 1021, 1021, 1021, 1021, 1021, 1021, - 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1020, 1020, 1020, 1020, - 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1021, 1020, 1020, - 1020, 1020, 1020, 1020, 1020, 1020, 1021, 1020, 1020, 1020, 1020, 1020, - 1020, 1021, 1020, 1020, 1022, 1022, 1022, 1022, 1023, 81, 81, 81, 81, 81, - 81, 81, 1021, 1021, 1021, 1021, 1021, 81, 1021, 1021, 1021, 1021, 1021, - 1021, 1021, 1024, 1024, 1024, 1024, 1024, 1024, 1024, 81, 1024, 1024, - 1024, 1024, 1024, 1024, 1024, 1024, 1024, 81, 81, 1024, 1024, 1024, 1024, - 1024, 1024, 1024, 81, 1024, 1024, 81, 1024, 1024, 1024, 1024, 1024, 81, - 81, 81, 81, 81, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, 1025, - 1025, 1025, 1025, 1025, 81, 81, 1026, 1026, 1026, 1026, 1026, 1026, 1026, - 1026, 1026, 1027, 1027, 1027, 1027, 1027, 1027, 1027, 81, 1028, 1028, - 1028, 1028, 1028, 1028, 1028, 1028, 1028, 1028, 1029, 1029, 1029, 1029, - 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, 1029, - 1029, 1029, 1030, 1030, 1030, 1030, 1030, 1030, 1031, 81, 81, 81, 81, 81, - 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 1032, 81, 81, 81, - 81, 1033, 1033, 81, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, - 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1035, 1034, - 1034, 1034, 1036, 1034, 1034, 1034, 1034, 81, 81, 81, 146, 146, 146, 146, - 81, 146, 146, 146, 81, 146, 146, 81, 146, 81, 81, 146, 81, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 81, 146, 146, 146, 146, 81, 146, 81, - 146, 81, 81, 81, 81, 81, 81, 146, 81, 81, 81, 81, 146, 81, 146, 81, 146, - 81, 146, 146, 146, 81, 146, 81, 146, 81, 146, 81, 146, 81, 146, 146, 146, - 146, 81, 146, 81, 146, 146, 81, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 81, 81, 81, 81, 81, 146, 146, 146, 81, 146, 146, 146, 132, 132, 81, - 81, 81, 81, 81, 81, 529, 529, 529, 529, 525, 529, 529, 529, 529, 529, - 529, 529, 529, 529, 529, 529, 529, 529, 529, 529, 1037, 1037, 1037, 1037, - 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 529, 529, 529, 529, 529, - 529, 529, 1037, 1037, 529, 529, 529, 529, 529, 529, 529, 529, 529, 529, - 529, 529, 529, 529, 525, 529, 529, 529, 529, 529, 529, 1037, 1037, 47, - 47, 47, 519, 519, 1037, 1037, 1037, 530, 530, 530, 530, 530, 530, 317, - 40, 530, 530, 40, 40, 1037, 1037, 1037, 1037, 530, 530, 530, 530, 530, - 530, 1038, 530, 530, 1038, 1038, 1038, 1038, 1038, 1038, 1038, 1038, - 1038, 1038, 530, 530, 530, 530, 530, 530, 530, 530, 530, 530, 1037, 1037, - 1037, 1037, 1037, 1037, 1037, 1037, 1037, 1039, 1039, 1039, 1039, 1039, - 1039, 1039, 1039, 1039, 1039, 1040, 585, 585, 1037, 1037, 1037, 1037, - 1037, 585, 585, 585, 585, 1037, 1037, 1037, 1037, 585, 1037, 1037, 1037, - 1037, 1037, 1037, 1037, 585, 585, 1037, 1037, 1037, 1037, 1037, 1037, - 525, 525, 525, 525, 525, 525, 1037, 1037, 525, 529, 529, 529, 529, 529, - 529, 529, 529, 529, 529, 529, 529, 525, 525, 525, 525, 525, 525, 525, - 525, 525, 529, 525, 525, 525, 525, 525, 525, 529, 525, 525, 525, 525, - 525, 525, 525, 536, 525, 525, 525, 525, 525, 525, 529, 529, 529, 529, - 529, 529, 529, 529, 40, 40, 529, 529, 525, 525, 525, 525, 525, 528, 528, - 525, 525, 525, 525, 525, 528, 525, 525, 525, 525, 525, 536, 536, 536, - 525, 525, 536, 525, 525, 536, 534, 534, 529, 529, 525, 525, 529, 529, - 529, 525, 529, 529, 529, 525, 525, 525, 1041, 1041, 1041, 1041, 1041, - 525, 525, 525, 525, 525, 525, 525, 529, 525, 529, 536, 536, 525, 525, - 536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 525, 525, 525, - 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 536, 536, 536, 536, - 525, 525, 525, 525, 536, 525, 536, 525, 525, 525, 536, 525, 525, 525, - 525, 536, 536, 536, 525, 536, 536, 536, 528, 525, 528, 525, 528, 525, - 525, 525, 525, 525, 536, 525, 525, 525, 525, 528, 525, 528, 528, 525, - 525, 525, 525, 525, 525, 525, 525, 525, 525, 529, 529, 525, 528, 528, - 528, 528, 528, 528, 528, 525, 525, 525, 525, 525, 525, 525, 525, 528, - 528, 528, 528, 528, 528, 525, 525, 525, 525, 525, 528, 528, 528, 528, - 528, 528, 528, 528, 528, 528, 528, 528, 40, 40, 40, 40, 529, 525, 525, - 525, 525, 529, 529, 529, 529, 529, 534, 534, 529, 529, 529, 529, 536, - 529, 529, 529, 529, 529, 534, 529, 529, 529, 529, 536, 536, 529, 529, - 529, 529, 529, 40, 40, 40, 40, 40, 40, 40, 40, 529, 529, 529, 529, 40, - 40, 529, 525, 525, 525, 525, 525, 525, 525, 525, 525, 525, 536, 536, 536, - 525, 525, 525, 536, 536, 536, 536, 536, 40, 40, 40, 40, 40, 40, 538, 538, - 538, 1042, 1042, 1042, 40, 40, 40, 40, 525, 525, 525, 536, 525, 525, 525, - 525, 525, 525, 525, 525, 536, 536, 536, 525, 536, 525, 525, 525, 525, - 525, 529, 529, 529, 529, 529, 529, 536, 529, 529, 529, 525, 525, 525, - 529, 529, 1037, 1037, 1037, 529, 529, 529, 525, 525, 1037, 1037, 1037, - 529, 529, 529, 529, 525, 525, 525, 525, 525, 525, 1037, 1037, 1037, 1037, - 1037, 1037, 40, 40, 40, 40, 1037, 1037, 1037, 1037, 40, 40, 40, 40, 40, - 529, 529, 529, 529, 1037, 1037, 1037, 1037, 1037, 1037, 1037, 40, 40, - 1037, 1037, 1037, 1037, 1037, 1037, 40, 40, 40, 40, 40, 40, 1037, 1037, - 536, 536, 536, 536, 536, 525, 536, 536, 525, 525, 525, 525, 525, 525, - 536, 525, 536, 536, 525, 525, 525, 536, 536, 1037, 525, 1037, 1037, 525, - 525, 525, 525, 1037, 1037, 1037, 525, 1037, 525, 525, 525, 525, 525, 525, - 525, 1037, 1037, 1037, 1037, 1037, 525, 525, 525, 525, 525, 536, 536, - 525, 536, 536, 1037, 1037, 1037, 1037, 1037, 1037, 525, 536, 536, 536, - 536, 536, 536, 536, 536, 536, 536, 536, 536, 536, 525, 525, 1037, 1037, - 1037, 1037, 1037, 1037, 81, 81, 592, 592, 592, 592, 592, 592, 592, 593, - 592, 592, 592, 592, 592, 593, 593, 593, 592, 593, 593, 593, 593, 593, - 593, 593, 593, 593, 593, 593, 593, 593, 81, 81, 81, 503, 81, 81, 81, 81, - 81, 81, 503, 503, 503, 503, 503, 503, 503, 503, 670, 670, 670, 670, 670, - 670, 81, 81, -}; - -/* decomposition data */ -static const unsigned short decomp_data[] = { - 0, 257, 32, 514, 32, 776, 259, 97, 514, 32, 772, 259, 50, 259, 51, 514, - 32, 769, 258, 956, 514, 32, 807, 259, 49, 259, 111, 772, 49, 8260, 52, - 772, 49, 8260, 50, 772, 51, 8260, 52, 512, 65, 768, 512, 65, 769, 512, - 65, 770, 512, 65, 771, 512, 65, 776, 512, 65, 778, 512, 67, 807, 512, 69, - 768, 512, 69, 769, 512, 69, 770, 512, 69, 776, 512, 73, 768, 512, 73, - 769, 512, 73, 770, 512, 73, 776, 512, 78, 771, 512, 79, 768, 512, 79, - 769, 512, 79, 770, 512, 79, 771, 512, 79, 776, 512, 85, 768, 512, 85, - 769, 512, 85, 770, 512, 85, 776, 512, 89, 769, 512, 97, 768, 512, 97, - 769, 512, 97, 770, 512, 97, 771, 512, 97, 776, 512, 97, 778, 512, 99, - 807, 512, 101, 768, 512, 101, 769, 512, 101, 770, 512, 101, 776, 512, - 105, 768, 512, 105, 769, 512, 105, 770, 512, 105, 776, 512, 110, 771, - 512, 111, 768, 512, 111, 769, 512, 111, 770, 512, 111, 771, 512, 111, - 776, 512, 117, 768, 512, 117, 769, 512, 117, 770, 512, 117, 776, 512, - 121, 769, 512, 121, 776, 512, 65, 772, 512, 97, 772, 512, 65, 774, 512, - 97, 774, 512, 65, 808, 512, 97, 808, 512, 67, 769, 512, 99, 769, 512, 67, - 770, 512, 99, 770, 512, 67, 775, 512, 99, 775, 512, 67, 780, 512, 99, - 780, 512, 68, 780, 512, 100, 780, 512, 69, 772, 512, 101, 772, 512, 69, - 774, 512, 101, 774, 512, 69, 775, 512, 101, 775, 512, 69, 808, 512, 101, - 808, 512, 69, 780, 512, 101, 780, 512, 71, 770, 512, 103, 770, 512, 71, - 774, 512, 103, 774, 512, 71, 775, 512, 103, 775, 512, 71, 807, 512, 103, - 807, 512, 72, 770, 512, 104, 770, 512, 73, 771, 512, 105, 771, 512, 73, - 772, 512, 105, 772, 512, 73, 774, 512, 105, 774, 512, 73, 808, 512, 105, - 808, 512, 73, 775, 514, 73, 74, 514, 105, 106, 512, 74, 770, 512, 106, - 770, 512, 75, 807, 512, 107, 807, 512, 76, 769, 512, 108, 769, 512, 76, - 807, 512, 108, 807, 512, 76, 780, 512, 108, 780, 514, 76, 183, 514, 108, - 183, 512, 78, 769, 512, 110, 769, 512, 78, 807, 512, 110, 807, 512, 78, - 780, 512, 110, 780, 514, 700, 110, 512, 79, 772, 512, 111, 772, 512, 79, - 774, 512, 111, 774, 512, 79, 779, 512, 111, 779, 512, 82, 769, 512, 114, - 769, 512, 82, 807, 512, 114, 807, 512, 82, 780, 512, 114, 780, 512, 83, - 769, 512, 115, 769, 512, 83, 770, 512, 115, 770, 512, 83, 807, 512, 115, - 807, 512, 83, 780, 512, 115, 780, 512, 84, 807, 512, 116, 807, 512, 84, - 780, 512, 116, 780, 512, 85, 771, 512, 117, 771, 512, 85, 772, 512, 117, - 772, 512, 85, 774, 512, 117, 774, 512, 85, 778, 512, 117, 778, 512, 85, - 779, 512, 117, 779, 512, 85, 808, 512, 117, 808, 512, 87, 770, 512, 119, - 770, 512, 89, 770, 512, 121, 770, 512, 89, 776, 512, 90, 769, 512, 122, - 769, 512, 90, 775, 512, 122, 775, 512, 90, 780, 512, 122, 780, 258, 115, - 512, 79, 795, 512, 111, 795, 512, 85, 795, 512, 117, 795, 514, 68, 381, - 514, 68, 382, 514, 100, 382, 514, 76, 74, 514, 76, 106, 514, 108, 106, - 514, 78, 74, 514, 78, 106, 514, 110, 106, 512, 65, 780, 512, 97, 780, - 512, 73, 780, 512, 105, 780, 512, 79, 780, 512, 111, 780, 512, 85, 780, - 512, 117, 780, 512, 220, 772, 512, 252, 772, 512, 220, 769, 512, 252, - 769, 512, 220, 780, 512, 252, 780, 512, 220, 768, 512, 252, 768, 512, - 196, 772, 512, 228, 772, 512, 550, 772, 512, 551, 772, 512, 198, 772, - 512, 230, 772, 512, 71, 780, 512, 103, 780, 512, 75, 780, 512, 107, 780, - 512, 79, 808, 512, 111, 808, 512, 490, 772, 512, 491, 772, 512, 439, 780, - 512, 658, 780, 512, 106, 780, 514, 68, 90, 514, 68, 122, 514, 100, 122, - 512, 71, 769, 512, 103, 769, 512, 78, 768, 512, 110, 768, 512, 197, 769, - 512, 229, 769, 512, 198, 769, 512, 230, 769, 512, 216, 769, 512, 248, - 769, 512, 65, 783, 512, 97, 783, 512, 65, 785, 512, 97, 785, 512, 69, - 783, 512, 101, 783, 512, 69, 785, 512, 101, 785, 512, 73, 783, 512, 105, - 783, 512, 73, 785, 512, 105, 785, 512, 79, 783, 512, 111, 783, 512, 79, - 785, 512, 111, 785, 512, 82, 783, 512, 114, 783, 512, 82, 785, 512, 114, - 785, 512, 85, 783, 512, 117, 783, 512, 85, 785, 512, 117, 785, 512, 83, - 806, 512, 115, 806, 512, 84, 806, 512, 116, 806, 512, 72, 780, 512, 104, - 780, 512, 65, 775, 512, 97, 775, 512, 69, 807, 512, 101, 807, 512, 214, - 772, 512, 246, 772, 512, 213, 772, 512, 245, 772, 512, 79, 775, 512, 111, - 775, 512, 558, 772, 512, 559, 772, 512, 89, 772, 512, 121, 772, 259, 104, - 259, 614, 259, 106, 259, 114, 259, 633, 259, 635, 259, 641, 259, 119, - 259, 121, 514, 32, 774, 514, 32, 775, 514, 32, 778, 514, 32, 808, 514, - 32, 771, 514, 32, 779, 259, 611, 259, 108, 259, 115, 259, 120, 259, 661, - 256, 768, 256, 769, 256, 787, 512, 776, 769, 256, 697, 514, 32, 837, 256, - 59, 514, 32, 769, 512, 168, 769, 512, 913, 769, 256, 183, 512, 917, 769, - 512, 919, 769, 512, 921, 769, 512, 927, 769, 512, 933, 769, 512, 937, - 769, 512, 970, 769, 512, 921, 776, 512, 933, 776, 512, 945, 769, 512, - 949, 769, 512, 951, 769, 512, 953, 769, 512, 971, 769, 512, 953, 776, - 512, 965, 776, 512, 959, 769, 512, 965, 769, 512, 969, 769, 258, 946, - 258, 952, 258, 933, 512, 978, 769, 512, 978, 776, 258, 966, 258, 960, - 258, 954, 258, 961, 258, 962, 258, 920, 258, 949, 258, 931, 512, 1045, - 768, 512, 1045, 776, 512, 1043, 769, 512, 1030, 776, 512, 1050, 769, 512, - 1048, 768, 512, 1059, 774, 512, 1048, 774, 512, 1080, 774, 512, 1077, - 768, 512, 1077, 776, 512, 1075, 769, 512, 1110, 776, 512, 1082, 769, 512, - 1080, 768, 512, 1091, 774, 512, 1140, 783, 512, 1141, 783, 512, 1046, - 774, 512, 1078, 774, 512, 1040, 774, 512, 1072, 774, 512, 1040, 776, 512, - 1072, 776, 512, 1045, 774, 512, 1077, 774, 512, 1240, 776, 512, 1241, - 776, 512, 1046, 776, 512, 1078, 776, 512, 1047, 776, 512, 1079, 776, 512, - 1048, 772, 512, 1080, 772, 512, 1048, 776, 512, 1080, 776, 512, 1054, - 776, 512, 1086, 776, 512, 1256, 776, 512, 1257, 776, 512, 1069, 776, 512, - 1101, 776, 512, 1059, 772, 512, 1091, 772, 512, 1059, 776, 512, 1091, - 776, 512, 1059, 779, 512, 1091, 779, 512, 1063, 776, 512, 1095, 776, 512, - 1067, 776, 512, 1099, 776, 514, 1381, 1410, 512, 1575, 1619, 512, 1575, - 1620, 512, 1608, 1620, 512, 1575, 1621, 512, 1610, 1620, 514, 1575, 1652, - 514, 1608, 1652, 514, 1735, 1652, 514, 1610, 1652, 512, 1749, 1620, 512, - 1729, 1620, 512, 1746, 1620, 512, 2344, 2364, 512, 2352, 2364, 512, 2355, - 2364, 512, 2325, 2364, 512, 2326, 2364, 512, 2327, 2364, 512, 2332, 2364, - 512, 2337, 2364, 512, 2338, 2364, 512, 2347, 2364, 512, 2351, 2364, 512, - 2503, 2494, 512, 2503, 2519, 512, 2465, 2492, 512, 2466, 2492, 512, 2479, - 2492, 512, 2610, 2620, 512, 2616, 2620, 512, 2582, 2620, 512, 2583, 2620, - 512, 2588, 2620, 512, 2603, 2620, 512, 2887, 2902, 512, 2887, 2878, 512, - 2887, 2903, 512, 2849, 2876, 512, 2850, 2876, 512, 2962, 3031, 512, 3014, - 3006, 512, 3015, 3006, 512, 3014, 3031, 512, 3142, 3158, 512, 3263, 3285, - 512, 3270, 3285, 512, 3270, 3286, 512, 3270, 3266, 512, 3274, 3285, 512, - 3398, 3390, 512, 3399, 3390, 512, 3398, 3415, 512, 3545, 3530, 512, 3545, - 3535, 512, 3548, 3530, 512, 3545, 3551, 514, 3661, 3634, 514, 3789, 3762, - 514, 3755, 3737, 514, 3755, 3745, 257, 3851, 512, 3906, 4023, 512, 3916, - 4023, 512, 3921, 4023, 512, 3926, 4023, 512, 3931, 4023, 512, 3904, 4021, - 512, 3953, 3954, 512, 3953, 3956, 512, 4018, 3968, 514, 4018, 3969, 512, - 4019, 3968, 514, 4019, 3969, 512, 3953, 3968, 512, 3986, 4023, 512, 3996, - 4023, 512, 4001, 4023, 512, 4006, 4023, 512, 4011, 4023, 512, 3984, 4021, - 512, 4133, 4142, 259, 4316, 512, 6917, 6965, 512, 6919, 6965, 512, 6921, - 6965, 512, 6923, 6965, 512, 6925, 6965, 512, 6929, 6965, 512, 6970, 6965, - 512, 6972, 6965, 512, 6974, 6965, 512, 6975, 6965, 512, 6978, 6965, 259, - 65, 259, 198, 259, 66, 259, 68, 259, 69, 259, 398, 259, 71, 259, 72, 259, - 73, 259, 74, 259, 75, 259, 76, 259, 77, 259, 78, 259, 79, 259, 546, 259, - 80, 259, 82, 259, 84, 259, 85, 259, 87, 259, 97, 259, 592, 259, 593, 259, - 7426, 259, 98, 259, 100, 259, 101, 259, 601, 259, 603, 259, 604, 259, - 103, 259, 107, 259, 109, 259, 331, 259, 111, 259, 596, 259, 7446, 259, - 7447, 259, 112, 259, 116, 259, 117, 259, 7453, 259, 623, 259, 118, 259, - 7461, 259, 946, 259, 947, 259, 948, 259, 966, 259, 967, 261, 105, 261, - 114, 261, 117, 261, 118, 261, 946, 261, 947, 261, 961, 261, 966, 261, - 967, 259, 1085, 259, 594, 259, 99, 259, 597, 259, 240, 259, 604, 259, - 102, 259, 607, 259, 609, 259, 613, 259, 616, 259, 617, 259, 618, 259, - 7547, 259, 669, 259, 621, 259, 7557, 259, 671, 259, 625, 259, 624, 259, - 626, 259, 627, 259, 628, 259, 629, 259, 632, 259, 642, 259, 643, 259, - 427, 259, 649, 259, 650, 259, 7452, 259, 651, 259, 652, 259, 122, 259, - 656, 259, 657, 259, 658, 259, 952, 512, 65, 805, 512, 97, 805, 512, 66, - 775, 512, 98, 775, 512, 66, 803, 512, 98, 803, 512, 66, 817, 512, 98, - 817, 512, 199, 769, 512, 231, 769, 512, 68, 775, 512, 100, 775, 512, 68, - 803, 512, 100, 803, 512, 68, 817, 512, 100, 817, 512, 68, 807, 512, 100, - 807, 512, 68, 813, 512, 100, 813, 512, 274, 768, 512, 275, 768, 512, 274, - 769, 512, 275, 769, 512, 69, 813, 512, 101, 813, 512, 69, 816, 512, 101, - 816, 512, 552, 774, 512, 553, 774, 512, 70, 775, 512, 102, 775, 512, 71, - 772, 512, 103, 772, 512, 72, 775, 512, 104, 775, 512, 72, 803, 512, 104, - 803, 512, 72, 776, 512, 104, 776, 512, 72, 807, 512, 104, 807, 512, 72, - 814, 512, 104, 814, 512, 73, 816, 512, 105, 816, 512, 207, 769, 512, 239, - 769, 512, 75, 769, 512, 107, 769, 512, 75, 803, 512, 107, 803, 512, 75, - 817, 512, 107, 817, 512, 76, 803, 512, 108, 803, 512, 7734, 772, 512, - 7735, 772, 512, 76, 817, 512, 108, 817, 512, 76, 813, 512, 108, 813, 512, - 77, 769, 512, 109, 769, 512, 77, 775, 512, 109, 775, 512, 77, 803, 512, - 109, 803, 512, 78, 775, 512, 110, 775, 512, 78, 803, 512, 110, 803, 512, - 78, 817, 512, 110, 817, 512, 78, 813, 512, 110, 813, 512, 213, 769, 512, - 245, 769, 512, 213, 776, 512, 245, 776, 512, 332, 768, 512, 333, 768, - 512, 332, 769, 512, 333, 769, 512, 80, 769, 512, 112, 769, 512, 80, 775, - 512, 112, 775, 512, 82, 775, 512, 114, 775, 512, 82, 803, 512, 114, 803, - 512, 7770, 772, 512, 7771, 772, 512, 82, 817, 512, 114, 817, 512, 83, - 775, 512, 115, 775, 512, 83, 803, 512, 115, 803, 512, 346, 775, 512, 347, - 775, 512, 352, 775, 512, 353, 775, 512, 7778, 775, 512, 7779, 775, 512, - 84, 775, 512, 116, 775, 512, 84, 803, 512, 116, 803, 512, 84, 817, 512, - 116, 817, 512, 84, 813, 512, 116, 813, 512, 85, 804, 512, 117, 804, 512, - 85, 816, 512, 117, 816, 512, 85, 813, 512, 117, 813, 512, 360, 769, 512, - 361, 769, 512, 362, 776, 512, 363, 776, 512, 86, 771, 512, 118, 771, 512, - 86, 803, 512, 118, 803, 512, 87, 768, 512, 119, 768, 512, 87, 769, 512, - 119, 769, 512, 87, 776, 512, 119, 776, 512, 87, 775, 512, 119, 775, 512, - 87, 803, 512, 119, 803, 512, 88, 775, 512, 120, 775, 512, 88, 776, 512, - 120, 776, 512, 89, 775, 512, 121, 775, 512, 90, 770, 512, 122, 770, 512, - 90, 803, 512, 122, 803, 512, 90, 817, 512, 122, 817, 512, 104, 817, 512, - 116, 776, 512, 119, 778, 512, 121, 778, 514, 97, 702, 512, 383, 775, 512, - 65, 803, 512, 97, 803, 512, 65, 777, 512, 97, 777, 512, 194, 769, 512, - 226, 769, 512, 194, 768, 512, 226, 768, 512, 194, 777, 512, 226, 777, - 512, 194, 771, 512, 226, 771, 512, 7840, 770, 512, 7841, 770, 512, 258, - 769, 512, 259, 769, 512, 258, 768, 512, 259, 768, 512, 258, 777, 512, - 259, 777, 512, 258, 771, 512, 259, 771, 512, 7840, 774, 512, 7841, 774, - 512, 69, 803, 512, 101, 803, 512, 69, 777, 512, 101, 777, 512, 69, 771, - 512, 101, 771, 512, 202, 769, 512, 234, 769, 512, 202, 768, 512, 234, - 768, 512, 202, 777, 512, 234, 777, 512, 202, 771, 512, 234, 771, 512, - 7864, 770, 512, 7865, 770, 512, 73, 777, 512, 105, 777, 512, 73, 803, - 512, 105, 803, 512, 79, 803, 512, 111, 803, 512, 79, 777, 512, 111, 777, - 512, 212, 769, 512, 244, 769, 512, 212, 768, 512, 244, 768, 512, 212, - 777, 512, 244, 777, 512, 212, 771, 512, 244, 771, 512, 7884, 770, 512, - 7885, 770, 512, 416, 769, 512, 417, 769, 512, 416, 768, 512, 417, 768, - 512, 416, 777, 512, 417, 777, 512, 416, 771, 512, 417, 771, 512, 416, - 803, 512, 417, 803, 512, 85, 803, 512, 117, 803, 512, 85, 777, 512, 117, - 777, 512, 431, 769, 512, 432, 769, 512, 431, 768, 512, 432, 768, 512, - 431, 777, 512, 432, 777, 512, 431, 771, 512, 432, 771, 512, 431, 803, - 512, 432, 803, 512, 89, 768, 512, 121, 768, 512, 89, 803, 512, 121, 803, - 512, 89, 777, 512, 121, 777, 512, 89, 771, 512, 121, 771, 512, 945, 787, - 512, 945, 788, 512, 7936, 768, 512, 7937, 768, 512, 7936, 769, 512, 7937, - 769, 512, 7936, 834, 512, 7937, 834, 512, 913, 787, 512, 913, 788, 512, - 7944, 768, 512, 7945, 768, 512, 7944, 769, 512, 7945, 769, 512, 7944, - 834, 512, 7945, 834, 512, 949, 787, 512, 949, 788, 512, 7952, 768, 512, - 7953, 768, 512, 7952, 769, 512, 7953, 769, 512, 917, 787, 512, 917, 788, - 512, 7960, 768, 512, 7961, 768, 512, 7960, 769, 512, 7961, 769, 512, 951, - 787, 512, 951, 788, 512, 7968, 768, 512, 7969, 768, 512, 7968, 769, 512, - 7969, 769, 512, 7968, 834, 512, 7969, 834, 512, 919, 787, 512, 919, 788, - 512, 7976, 768, 512, 7977, 768, 512, 7976, 769, 512, 7977, 769, 512, - 7976, 834, 512, 7977, 834, 512, 953, 787, 512, 953, 788, 512, 7984, 768, - 512, 7985, 768, 512, 7984, 769, 512, 7985, 769, 512, 7984, 834, 512, - 7985, 834, 512, 921, 787, 512, 921, 788, 512, 7992, 768, 512, 7993, 768, - 512, 7992, 769, 512, 7993, 769, 512, 7992, 834, 512, 7993, 834, 512, 959, - 787, 512, 959, 788, 512, 8000, 768, 512, 8001, 768, 512, 8000, 769, 512, - 8001, 769, 512, 927, 787, 512, 927, 788, 512, 8008, 768, 512, 8009, 768, - 512, 8008, 769, 512, 8009, 769, 512, 965, 787, 512, 965, 788, 512, 8016, - 768, 512, 8017, 768, 512, 8016, 769, 512, 8017, 769, 512, 8016, 834, 512, - 8017, 834, 512, 933, 788, 512, 8025, 768, 512, 8025, 769, 512, 8025, 834, - 512, 969, 787, 512, 969, 788, 512, 8032, 768, 512, 8033, 768, 512, 8032, - 769, 512, 8033, 769, 512, 8032, 834, 512, 8033, 834, 512, 937, 787, 512, - 937, 788, 512, 8040, 768, 512, 8041, 768, 512, 8040, 769, 512, 8041, 769, - 512, 8040, 834, 512, 8041, 834, 512, 945, 768, 256, 940, 512, 949, 768, - 256, 941, 512, 951, 768, 256, 942, 512, 953, 768, 256, 943, 512, 959, - 768, 256, 972, 512, 965, 768, 256, 973, 512, 969, 768, 256, 974, 512, - 7936, 837, 512, 7937, 837, 512, 7938, 837, 512, 7939, 837, 512, 7940, - 837, 512, 7941, 837, 512, 7942, 837, 512, 7943, 837, 512, 7944, 837, 512, - 7945, 837, 512, 7946, 837, 512, 7947, 837, 512, 7948, 837, 512, 7949, - 837, 512, 7950, 837, 512, 7951, 837, 512, 7968, 837, 512, 7969, 837, 512, - 7970, 837, 512, 7971, 837, 512, 7972, 837, 512, 7973, 837, 512, 7974, - 837, 512, 7975, 837, 512, 7976, 837, 512, 7977, 837, 512, 7978, 837, 512, - 7979, 837, 512, 7980, 837, 512, 7981, 837, 512, 7982, 837, 512, 7983, - 837, 512, 8032, 837, 512, 8033, 837, 512, 8034, 837, 512, 8035, 837, 512, - 8036, 837, 512, 8037, 837, 512, 8038, 837, 512, 8039, 837, 512, 8040, - 837, 512, 8041, 837, 512, 8042, 837, 512, 8043, 837, 512, 8044, 837, 512, - 8045, 837, 512, 8046, 837, 512, 8047, 837, 512, 945, 774, 512, 945, 772, - 512, 8048, 837, 512, 945, 837, 512, 940, 837, 512, 945, 834, 512, 8118, - 837, 512, 913, 774, 512, 913, 772, 512, 913, 768, 256, 902, 512, 913, - 837, 514, 32, 787, 256, 953, 514, 32, 787, 514, 32, 834, 512, 168, 834, - 512, 8052, 837, 512, 951, 837, 512, 942, 837, 512, 951, 834, 512, 8134, - 837, 512, 917, 768, 256, 904, 512, 919, 768, 256, 905, 512, 919, 837, - 512, 8127, 768, 512, 8127, 769, 512, 8127, 834, 512, 953, 774, 512, 953, - 772, 512, 970, 768, 256, 912, 512, 953, 834, 512, 970, 834, 512, 921, - 774, 512, 921, 772, 512, 921, 768, 256, 906, 512, 8190, 768, 512, 8190, - 769, 512, 8190, 834, 512, 965, 774, 512, 965, 772, 512, 971, 768, 256, - 944, 512, 961, 787, 512, 961, 788, 512, 965, 834, 512, 971, 834, 512, - 933, 774, 512, 933, 772, 512, 933, 768, 256, 910, 512, 929, 788, 512, - 168, 768, 256, 901, 256, 96, 512, 8060, 837, 512, 969, 837, 512, 974, - 837, 512, 969, 834, 512, 8182, 837, 512, 927, 768, 256, 908, 512, 937, - 768, 256, 911, 512, 937, 837, 256, 180, 514, 32, 788, 256, 8194, 256, - 8195, 258, 32, 258, 32, 258, 32, 258, 32, 258, 32, 257, 32, 258, 32, 258, - 32, 258, 32, 257, 8208, 514, 32, 819, 258, 46, 514, 46, 46, 770, 46, 46, - 46, 257, 32, 514, 8242, 8242, 770, 8242, 8242, 8242, 514, 8245, 8245, - 770, 8245, 8245, 8245, 514, 33, 33, 514, 32, 773, 514, 63, 63, 514, 63, - 33, 514, 33, 63, 1026, 8242, 8242, 8242, 8242, 258, 32, 259, 48, 259, - 105, 259, 52, 259, 53, 259, 54, 259, 55, 259, 56, 259, 57, 259, 43, 259, - 8722, 259, 61, 259, 40, 259, 41, 259, 110, 261, 48, 261, 49, 261, 50, - 261, 51, 261, 52, 261, 53, 261, 54, 261, 55, 261, 56, 261, 57, 261, 43, - 261, 8722, 261, 61, 261, 40, 261, 41, 261, 97, 261, 101, 261, 111, 261, - 120, 261, 601, 261, 104, 261, 107, 261, 108, 261, 109, 261, 110, 261, - 112, 261, 115, 261, 116, 514, 82, 115, 770, 97, 47, 99, 770, 97, 47, 115, - 262, 67, 514, 176, 67, 770, 99, 47, 111, 770, 99, 47, 117, 258, 400, 514, - 176, 70, 262, 103, 262, 72, 262, 72, 262, 72, 262, 104, 262, 295, 262, - 73, 262, 73, 262, 76, 262, 108, 262, 78, 514, 78, 111, 262, 80, 262, 81, - 262, 82, 262, 82, 262, 82, 515, 83, 77, 770, 84, 69, 76, 515, 84, 77, - 262, 90, 256, 937, 262, 90, 256, 75, 256, 197, 262, 66, 262, 67, 262, - 101, 262, 69, 262, 70, 262, 77, 262, 111, 258, 1488, 258, 1489, 258, - 1490, 258, 1491, 262, 105, 770, 70, 65, 88, 262, 960, 262, 947, 262, 915, - 262, 928, 262, 8721, 262, 68, 262, 100, 262, 101, 262, 105, 262, 106, - 772, 49, 8260, 55, 772, 49, 8260, 57, 1028, 49, 8260, 49, 48, 772, 49, - 8260, 51, 772, 50, 8260, 51, 772, 49, 8260, 53, 772, 50, 8260, 53, 772, - 51, 8260, 53, 772, 52, 8260, 53, 772, 49, 8260, 54, 772, 53, 8260, 54, - 772, 49, 8260, 56, 772, 51, 8260, 56, 772, 53, 8260, 56, 772, 55, 8260, - 56, 516, 49, 8260, 258, 73, 514, 73, 73, 770, 73, 73, 73, 514, 73, 86, - 258, 86, 514, 86, 73, 770, 86, 73, 73, 1026, 86, 73, 73, 73, 514, 73, 88, - 258, 88, 514, 88, 73, 770, 88, 73, 73, 258, 76, 258, 67, 258, 68, 258, - 77, 258, 105, 514, 105, 105, 770, 105, 105, 105, 514, 105, 118, 258, 118, - 514, 118, 105, 770, 118, 105, 105, 1026, 118, 105, 105, 105, 514, 105, - 120, 258, 120, 514, 120, 105, 770, 120, 105, 105, 258, 108, 258, 99, 258, - 100, 258, 109, 772, 48, 8260, 51, 512, 8592, 824, 512, 8594, 824, 512, - 8596, 824, 512, 8656, 824, 512, 8660, 824, 512, 8658, 824, 512, 8707, - 824, 512, 8712, 824, 512, 8715, 824, 512, 8739, 824, 512, 8741, 824, 514, - 8747, 8747, 770, 8747, 8747, 8747, 514, 8750, 8750, 770, 8750, 8750, - 8750, 512, 8764, 824, 512, 8771, 824, 512, 8773, 824, 512, 8776, 824, - 512, 61, 824, 512, 8801, 824, 512, 8781, 824, 512, 60, 824, 512, 62, 824, - 512, 8804, 824, 512, 8805, 824, 512, 8818, 824, 512, 8819, 824, 512, - 8822, 824, 512, 8823, 824, 512, 8826, 824, 512, 8827, 824, 512, 8834, - 824, 512, 8835, 824, 512, 8838, 824, 512, 8839, 824, 512, 8866, 824, 512, - 8872, 824, 512, 8873, 824, 512, 8875, 824, 512, 8828, 824, 512, 8829, - 824, 512, 8849, 824, 512, 8850, 824, 512, 8882, 824, 512, 8883, 824, 512, - 8884, 824, 512, 8885, 824, 256, 12296, 256, 12297, 263, 49, 263, 50, 263, - 51, 263, 52, 263, 53, 263, 54, 263, 55, 263, 56, 263, 57, 519, 49, 48, - 519, 49, 49, 519, 49, 50, 519, 49, 51, 519, 49, 52, 519, 49, 53, 519, 49, - 54, 519, 49, 55, 519, 49, 56, 519, 49, 57, 519, 50, 48, 770, 40, 49, 41, - 770, 40, 50, 41, 770, 40, 51, 41, 770, 40, 52, 41, 770, 40, 53, 41, 770, - 40, 54, 41, 770, 40, 55, 41, 770, 40, 56, 41, 770, 40, 57, 41, 1026, 40, - 49, 48, 41, 1026, 40, 49, 49, 41, 1026, 40, 49, 50, 41, 1026, 40, 49, 51, - 41, 1026, 40, 49, 52, 41, 1026, 40, 49, 53, 41, 1026, 40, 49, 54, 41, - 1026, 40, 49, 55, 41, 1026, 40, 49, 56, 41, 1026, 40, 49, 57, 41, 1026, - 40, 50, 48, 41, 514, 49, 46, 514, 50, 46, 514, 51, 46, 514, 52, 46, 514, - 53, 46, 514, 54, 46, 514, 55, 46, 514, 56, 46, 514, 57, 46, 770, 49, 48, - 46, 770, 49, 49, 46, 770, 49, 50, 46, 770, 49, 51, 46, 770, 49, 52, 46, - 770, 49, 53, 46, 770, 49, 54, 46, 770, 49, 55, 46, 770, 49, 56, 46, 770, - 49, 57, 46, 770, 50, 48, 46, 770, 40, 97, 41, 770, 40, 98, 41, 770, 40, - 99, 41, 770, 40, 100, 41, 770, 40, 101, 41, 770, 40, 102, 41, 770, 40, - 103, 41, 770, 40, 104, 41, 770, 40, 105, 41, 770, 40, 106, 41, 770, 40, - 107, 41, 770, 40, 108, 41, 770, 40, 109, 41, 770, 40, 110, 41, 770, 40, - 111, 41, 770, 40, 112, 41, 770, 40, 113, 41, 770, 40, 114, 41, 770, 40, - 115, 41, 770, 40, 116, 41, 770, 40, 117, 41, 770, 40, 118, 41, 770, 40, - 119, 41, 770, 40, 120, 41, 770, 40, 121, 41, 770, 40, 122, 41, 263, 65, - 263, 66, 263, 67, 263, 68, 263, 69, 263, 70, 263, 71, 263, 72, 263, 73, - 263, 74, 263, 75, 263, 76, 263, 77, 263, 78, 263, 79, 263, 80, 263, 81, - 263, 82, 263, 83, 263, 84, 263, 85, 263, 86, 263, 87, 263, 88, 263, 89, - 263, 90, 263, 97, 263, 98, 263, 99, 263, 100, 263, 101, 263, 102, 263, - 103, 263, 104, 263, 105, 263, 106, 263, 107, 263, 108, 263, 109, 263, - 110, 263, 111, 263, 112, 263, 113, 263, 114, 263, 115, 263, 116, 263, - 117, 263, 118, 263, 119, 263, 120, 263, 121, 263, 122, 263, 48, 1026, - 8747, 8747, 8747, 8747, 770, 58, 58, 61, 514, 61, 61, 770, 61, 61, 61, - 512, 10973, 824, 261, 106, 259, 86, 259, 11617, 258, 27597, 258, 40863, - 258, 19968, 258, 20008, 258, 20022, 258, 20031, 258, 20057, 258, 20101, - 258, 20108, 258, 20128, 258, 20154, 258, 20799, 258, 20837, 258, 20843, - 258, 20866, 258, 20886, 258, 20907, 258, 20960, 258, 20981, 258, 20992, - 258, 21147, 258, 21241, 258, 21269, 258, 21274, 258, 21304, 258, 21313, - 258, 21340, 258, 21353, 258, 21378, 258, 21430, 258, 21448, 258, 21475, - 258, 22231, 258, 22303, 258, 22763, 258, 22786, 258, 22794, 258, 22805, - 258, 22823, 258, 22899, 258, 23376, 258, 23424, 258, 23544, 258, 23567, - 258, 23586, 258, 23608, 258, 23662, 258, 23665, 258, 24027, 258, 24037, - 258, 24049, 258, 24062, 258, 24178, 258, 24186, 258, 24191, 258, 24308, - 258, 24318, 258, 24331, 258, 24339, 258, 24400, 258, 24417, 258, 24435, - 258, 24515, 258, 25096, 258, 25142, 258, 25163, 258, 25903, 258, 25908, - 258, 25991, 258, 26007, 258, 26020, 258, 26041, 258, 26080, 258, 26085, - 258, 26352, 258, 26376, 258, 26408, 258, 27424, 258, 27490, 258, 27513, - 258, 27571, 258, 27595, 258, 27604, 258, 27611, 258, 27663, 258, 27668, - 258, 27700, 258, 28779, 258, 29226, 258, 29238, 258, 29243, 258, 29247, - 258, 29255, 258, 29273, 258, 29275, 258, 29356, 258, 29572, 258, 29577, - 258, 29916, 258, 29926, 258, 29976, 258, 29983, 258, 29992, 258, 30000, - 258, 30091, 258, 30098, 258, 30326, 258, 30333, 258, 30382, 258, 30399, - 258, 30446, 258, 30683, 258, 30690, 258, 30707, 258, 31034, 258, 31160, - 258, 31166, 258, 31348, 258, 31435, 258, 31481, 258, 31859, 258, 31992, - 258, 32566, 258, 32593, 258, 32650, 258, 32701, 258, 32769, 258, 32780, - 258, 32786, 258, 32819, 258, 32895, 258, 32905, 258, 33251, 258, 33258, - 258, 33267, 258, 33276, 258, 33292, 258, 33307, 258, 33311, 258, 33390, - 258, 33394, 258, 33400, 258, 34381, 258, 34411, 258, 34880, 258, 34892, - 258, 34915, 258, 35198, 258, 35211, 258, 35282, 258, 35328, 258, 35895, - 258, 35910, 258, 35925, 258, 35960, 258, 35997, 258, 36196, 258, 36208, - 258, 36275, 258, 36523, 258, 36554, 258, 36763, 258, 36784, 258, 36789, - 258, 37009, 258, 37193, 258, 37318, 258, 37324, 258, 37329, 258, 38263, - 258, 38272, 258, 38428, 258, 38582, 258, 38585, 258, 38632, 258, 38737, - 258, 38750, 258, 38754, 258, 38761, 258, 38859, 258, 38893, 258, 38899, - 258, 38913, 258, 39080, 258, 39131, 258, 39135, 258, 39318, 258, 39321, - 258, 39340, 258, 39592, 258, 39640, 258, 39647, 258, 39717, 258, 39727, - 258, 39730, 258, 39740, 258, 39770, 258, 40165, 258, 40565, 258, 40575, - 258, 40613, 258, 40635, 258, 40643, 258, 40653, 258, 40657, 258, 40697, - 258, 40701, 258, 40718, 258, 40723, 258, 40736, 258, 40763, 258, 40778, - 258, 40786, 258, 40845, 258, 40860, 258, 40864, 264, 32, 258, 12306, 258, - 21313, 258, 21316, 258, 21317, 512, 12363, 12441, 512, 12365, 12441, 512, - 12367, 12441, 512, 12369, 12441, 512, 12371, 12441, 512, 12373, 12441, - 512, 12375, 12441, 512, 12377, 12441, 512, 12379, 12441, 512, 12381, - 12441, 512, 12383, 12441, 512, 12385, 12441, 512, 12388, 12441, 512, - 12390, 12441, 512, 12392, 12441, 512, 12399, 12441, 512, 12399, 12442, - 512, 12402, 12441, 512, 12402, 12442, 512, 12405, 12441, 512, 12405, - 12442, 512, 12408, 12441, 512, 12408, 12442, 512, 12411, 12441, 512, - 12411, 12442, 512, 12358, 12441, 514, 32, 12441, 514, 32, 12442, 512, - 12445, 12441, 521, 12424, 12426, 512, 12459, 12441, 512, 12461, 12441, - 512, 12463, 12441, 512, 12465, 12441, 512, 12467, 12441, 512, 12469, - 12441, 512, 12471, 12441, 512, 12473, 12441, 512, 12475, 12441, 512, - 12477, 12441, 512, 12479, 12441, 512, 12481, 12441, 512, 12484, 12441, - 512, 12486, 12441, 512, 12488, 12441, 512, 12495, 12441, 512, 12495, - 12442, 512, 12498, 12441, 512, 12498, 12442, 512, 12501, 12441, 512, - 12501, 12442, 512, 12504, 12441, 512, 12504, 12442, 512, 12507, 12441, - 512, 12507, 12442, 512, 12454, 12441, 512, 12527, 12441, 512, 12528, - 12441, 512, 12529, 12441, 512, 12530, 12441, 512, 12541, 12441, 521, - 12467, 12488, 258, 4352, 258, 4353, 258, 4522, 258, 4354, 258, 4524, 258, - 4525, 258, 4355, 258, 4356, 258, 4357, 258, 4528, 258, 4529, 258, 4530, - 258, 4531, 258, 4532, 258, 4533, 258, 4378, 258, 4358, 258, 4359, 258, - 4360, 258, 4385, 258, 4361, 258, 4362, 258, 4363, 258, 4364, 258, 4365, - 258, 4366, 258, 4367, 258, 4368, 258, 4369, 258, 4370, 258, 4449, 258, - 4450, 258, 4451, 258, 4452, 258, 4453, 258, 4454, 258, 4455, 258, 4456, - 258, 4457, 258, 4458, 258, 4459, 258, 4460, 258, 4461, 258, 4462, 258, - 4463, 258, 4464, 258, 4465, 258, 4466, 258, 4467, 258, 4468, 258, 4469, - 258, 4448, 258, 4372, 258, 4373, 258, 4551, 258, 4552, 258, 4556, 258, - 4558, 258, 4563, 258, 4567, 258, 4569, 258, 4380, 258, 4573, 258, 4575, - 258, 4381, 258, 4382, 258, 4384, 258, 4386, 258, 4387, 258, 4391, 258, - 4393, 258, 4395, 258, 4396, 258, 4397, 258, 4398, 258, 4399, 258, 4402, - 258, 4406, 258, 4416, 258, 4423, 258, 4428, 258, 4593, 258, 4594, 258, - 4439, 258, 4440, 258, 4441, 258, 4484, 258, 4485, 258, 4488, 258, 4497, - 258, 4498, 258, 4500, 258, 4510, 258, 4513, 259, 19968, 259, 20108, 259, - 19977, 259, 22235, 259, 19978, 259, 20013, 259, 19979, 259, 30002, 259, - 20057, 259, 19993, 259, 19969, 259, 22825, 259, 22320, 259, 20154, 770, - 40, 4352, 41, 770, 40, 4354, 41, 770, 40, 4355, 41, 770, 40, 4357, 41, - 770, 40, 4358, 41, 770, 40, 4359, 41, 770, 40, 4361, 41, 770, 40, 4363, - 41, 770, 40, 4364, 41, 770, 40, 4366, 41, 770, 40, 4367, 41, 770, 40, - 4368, 41, 770, 40, 4369, 41, 770, 40, 4370, 41, 1026, 40, 4352, 4449, 41, - 1026, 40, 4354, 4449, 41, 1026, 40, 4355, 4449, 41, 1026, 40, 4357, 4449, - 41, 1026, 40, 4358, 4449, 41, 1026, 40, 4359, 4449, 41, 1026, 40, 4361, - 4449, 41, 1026, 40, 4363, 4449, 41, 1026, 40, 4364, 4449, 41, 1026, 40, - 4366, 4449, 41, 1026, 40, 4367, 4449, 41, 1026, 40, 4368, 4449, 41, 1026, - 40, 4369, 4449, 41, 1026, 40, 4370, 4449, 41, 1026, 40, 4364, 4462, 41, - 1794, 40, 4363, 4457, 4364, 4453, 4523, 41, 1538, 40, 4363, 4457, 4370, - 4462, 41, 770, 40, 19968, 41, 770, 40, 20108, 41, 770, 40, 19977, 41, - 770, 40, 22235, 41, 770, 40, 20116, 41, 770, 40, 20845, 41, 770, 40, - 19971, 41, 770, 40, 20843, 41, 770, 40, 20061, 41, 770, 40, 21313, 41, - 770, 40, 26376, 41, 770, 40, 28779, 41, 770, 40, 27700, 41, 770, 40, - 26408, 41, 770, 40, 37329, 41, 770, 40, 22303, 41, 770, 40, 26085, 41, - 770, 40, 26666, 41, 770, 40, 26377, 41, 770, 40, 31038, 41, 770, 40, - 21517, 41, 770, 40, 29305, 41, 770, 40, 36001, 41, 770, 40, 31069, 41, - 770, 40, 21172, 41, 770, 40, 20195, 41, 770, 40, 21628, 41, 770, 40, - 23398, 41, 770, 40, 30435, 41, 770, 40, 20225, 41, 770, 40, 36039, 41, - 770, 40, 21332, 41, 770, 40, 31085, 41, 770, 40, 20241, 41, 770, 40, - 33258, 41, 770, 40, 33267, 41, 263, 21839, 263, 24188, 263, 25991, 263, - 31631, 778, 80, 84, 69, 519, 50, 49, 519, 50, 50, 519, 50, 51, 519, 50, - 52, 519, 50, 53, 519, 50, 54, 519, 50, 55, 519, 50, 56, 519, 50, 57, 519, - 51, 48, 519, 51, 49, 519, 51, 50, 519, 51, 51, 519, 51, 52, 519, 51, 53, - 263, 4352, 263, 4354, 263, 4355, 263, 4357, 263, 4358, 263, 4359, 263, - 4361, 263, 4363, 263, 4364, 263, 4366, 263, 4367, 263, 4368, 263, 4369, - 263, 4370, 519, 4352, 4449, 519, 4354, 4449, 519, 4355, 4449, 519, 4357, - 4449, 519, 4358, 4449, 519, 4359, 4449, 519, 4361, 4449, 519, 4363, 4449, - 519, 4364, 4449, 519, 4366, 4449, 519, 4367, 4449, 519, 4368, 4449, 519, - 4369, 4449, 519, 4370, 4449, 1287, 4366, 4449, 4535, 4352, 4457, 1031, - 4364, 4462, 4363, 4468, 519, 4363, 4462, 263, 19968, 263, 20108, 263, - 19977, 263, 22235, 263, 20116, 263, 20845, 263, 19971, 263, 20843, 263, - 20061, 263, 21313, 263, 26376, 263, 28779, 263, 27700, 263, 26408, 263, - 37329, 263, 22303, 263, 26085, 263, 26666, 263, 26377, 263, 31038, 263, - 21517, 263, 29305, 263, 36001, 263, 31069, 263, 21172, 263, 31192, 263, - 30007, 263, 22899, 263, 36969, 263, 20778, 263, 21360, 263, 27880, 263, - 38917, 263, 20241, 263, 20889, 263, 27491, 263, 19978, 263, 20013, 263, - 19979, 263, 24038, 263, 21491, 263, 21307, 263, 23447, 263, 23398, 263, - 30435, 263, 20225, 263, 36039, 263, 21332, 263, 22812, 519, 51, 54, 519, - 51, 55, 519, 51, 56, 519, 51, 57, 519, 52, 48, 519, 52, 49, 519, 52, 50, - 519, 52, 51, 519, 52, 52, 519, 52, 53, 519, 52, 54, 519, 52, 55, 519, 52, - 56, 519, 52, 57, 519, 53, 48, 514, 49, 26376, 514, 50, 26376, 514, 51, - 26376, 514, 52, 26376, 514, 53, 26376, 514, 54, 26376, 514, 55, 26376, - 514, 56, 26376, 514, 57, 26376, 770, 49, 48, 26376, 770, 49, 49, 26376, - 770, 49, 50, 26376, 522, 72, 103, 778, 101, 114, 103, 522, 101, 86, 778, - 76, 84, 68, 263, 12450, 263, 12452, 263, 12454, 263, 12456, 263, 12458, - 263, 12459, 263, 12461, 263, 12463, 263, 12465, 263, 12467, 263, 12469, - 263, 12471, 263, 12473, 263, 12475, 263, 12477, 263, 12479, 263, 12481, - 263, 12484, 263, 12486, 263, 12488, 263, 12490, 263, 12491, 263, 12492, - 263, 12493, 263, 12494, 263, 12495, 263, 12498, 263, 12501, 263, 12504, - 263, 12507, 263, 12510, 263, 12511, 263, 12512, 263, 12513, 263, 12514, - 263, 12516, 263, 12518, 263, 12520, 263, 12521, 263, 12522, 263, 12523, - 263, 12524, 263, 12525, 263, 12527, 263, 12528, 263, 12529, 263, 12530, - 1034, 12450, 12497, 12540, 12488, 1034, 12450, 12523, 12501, 12449, 1034, - 12450, 12531, 12506, 12450, 778, 12450, 12540, 12523, 1034, 12452, 12491, - 12531, 12464, 778, 12452, 12531, 12481, 778, 12454, 12457, 12531, 1290, - 12456, 12473, 12463, 12540, 12489, 1034, 12456, 12540, 12459, 12540, 778, - 12458, 12531, 12473, 778, 12458, 12540, 12512, 778, 12459, 12452, 12522, - 1034, 12459, 12521, 12483, 12488, 1034, 12459, 12525, 12522, 12540, 778, - 12460, 12525, 12531, 778, 12460, 12531, 12510, 522, 12462, 12460, 778, - 12462, 12491, 12540, 1034, 12461, 12517, 12522, 12540, 1034, 12462, - 12523, 12480, 12540, 522, 12461, 12525, 1290, 12461, 12525, 12464, 12521, - 12512, 1546, 12461, 12525, 12513, 12540, 12488, 12523, 1290, 12461, - 12525, 12527, 12483, 12488, 778, 12464, 12521, 12512, 1290, 12464, 12521, - 12512, 12488, 12531, 1290, 12463, 12523, 12476, 12452, 12525, 1034, - 12463, 12525, 12540, 12493, 778, 12465, 12540, 12473, 778, 12467, 12523, - 12490, 778, 12467, 12540, 12509, 1034, 12469, 12452, 12463, 12523, 1290, - 12469, 12531, 12481, 12540, 12512, 1034, 12471, 12522, 12531, 12464, 778, - 12475, 12531, 12481, 778, 12475, 12531, 12488, 778, 12480, 12540, 12473, - 522, 12487, 12471, 522, 12489, 12523, 522, 12488, 12531, 522, 12490, - 12494, 778, 12494, 12483, 12488, 778, 12495, 12452, 12484, 1290, 12497, - 12540, 12475, 12531, 12488, 778, 12497, 12540, 12484, 1034, 12496, 12540, - 12524, 12523, 1290, 12500, 12450, 12473, 12488, 12523, 778, 12500, 12463, - 12523, 522, 12500, 12467, 522, 12499, 12523, 1290, 12501, 12449, 12521, - 12483, 12489, 1034, 12501, 12451, 12540, 12488, 1290, 12502, 12483, - 12471, 12455, 12523, 778, 12501, 12521, 12531, 1290, 12504, 12463, 12479, - 12540, 12523, 522, 12506, 12477, 778, 12506, 12491, 12498, 778, 12504, - 12523, 12484, 778, 12506, 12531, 12473, 778, 12506, 12540, 12472, 778, - 12505, 12540, 12479, 1034, 12509, 12452, 12531, 12488, 778, 12508, 12523, - 12488, 522, 12507, 12531, 778, 12509, 12531, 12489, 778, 12507, 12540, - 12523, 778, 12507, 12540, 12531, 1034, 12510, 12452, 12463, 12525, 778, - 12510, 12452, 12523, 778, 12510, 12483, 12495, 778, 12510, 12523, 12463, - 1290, 12510, 12531, 12471, 12519, 12531, 1034, 12511, 12463, 12525, - 12531, 522, 12511, 12522, 1290, 12511, 12522, 12496, 12540, 12523, 522, - 12513, 12460, 1034, 12513, 12460, 12488, 12531, 1034, 12513, 12540, - 12488, 12523, 778, 12516, 12540, 12489, 778, 12516, 12540, 12523, 778, - 12518, 12450, 12531, 1034, 12522, 12483, 12488, 12523, 522, 12522, 12521, - 778, 12523, 12500, 12540, 1034, 12523, 12540, 12502, 12523, 522, 12524, - 12512, 1290, 12524, 12531, 12488, 12466, 12531, 778, 12527, 12483, 12488, - 514, 48, 28857, 514, 49, 28857, 514, 50, 28857, 514, 51, 28857, 514, 52, - 28857, 514, 53, 28857, 514, 54, 28857, 514, 55, 28857, 514, 56, 28857, - 514, 57, 28857, 770, 49, 48, 28857, 770, 49, 49, 28857, 770, 49, 50, - 28857, 770, 49, 51, 28857, 770, 49, 52, 28857, 770, 49, 53, 28857, 770, - 49, 54, 28857, 770, 49, 55, 28857, 770, 49, 56, 28857, 770, 49, 57, - 28857, 770, 50, 48, 28857, 770, 50, 49, 28857, 770, 50, 50, 28857, 770, - 50, 51, 28857, 770, 50, 52, 28857, 778, 104, 80, 97, 522, 100, 97, 522, - 65, 85, 778, 98, 97, 114, 522, 111, 86, 522, 112, 99, 522, 100, 109, 778, - 100, 109, 178, 778, 100, 109, 179, 522, 73, 85, 522, 24179, 25104, 522, - 26157, 21644, 522, 22823, 27491, 522, 26126, 27835, 1034, 26666, 24335, - 20250, 31038, 522, 112, 65, 522, 110, 65, 522, 956, 65, 522, 109, 65, - 522, 107, 65, 522, 75, 66, 522, 77, 66, 522, 71, 66, 778, 99, 97, 108, - 1034, 107, 99, 97, 108, 522, 112, 70, 522, 110, 70, 522, 956, 70, 522, - 956, 103, 522, 109, 103, 522, 107, 103, 522, 72, 122, 778, 107, 72, 122, - 778, 77, 72, 122, 778, 71, 72, 122, 778, 84, 72, 122, 522, 956, 8467, - 522, 109, 8467, 522, 100, 8467, 522, 107, 8467, 522, 102, 109, 522, 110, - 109, 522, 956, 109, 522, 109, 109, 522, 99, 109, 522, 107, 109, 778, 109, - 109, 178, 778, 99, 109, 178, 522, 109, 178, 778, 107, 109, 178, 778, 109, - 109, 179, 778, 99, 109, 179, 522, 109, 179, 778, 107, 109, 179, 778, 109, - 8725, 115, 1034, 109, 8725, 115, 178, 522, 80, 97, 778, 107, 80, 97, 778, - 77, 80, 97, 778, 71, 80, 97, 778, 114, 97, 100, 1290, 114, 97, 100, 8725, - 115, 1546, 114, 97, 100, 8725, 115, 178, 522, 112, 115, 522, 110, 115, - 522, 956, 115, 522, 109, 115, 522, 112, 86, 522, 110, 86, 522, 956, 86, - 522, 109, 86, 522, 107, 86, 522, 77, 86, 522, 112, 87, 522, 110, 87, 522, - 956, 87, 522, 109, 87, 522, 107, 87, 522, 77, 87, 522, 107, 937, 522, 77, - 937, 1034, 97, 46, 109, 46, 522, 66, 113, 522, 99, 99, 522, 99, 100, - 1034, 67, 8725, 107, 103, 778, 67, 111, 46, 522, 100, 66, 522, 71, 121, - 522, 104, 97, 522, 72, 80, 522, 105, 110, 522, 75, 75, 522, 75, 77, 522, - 107, 116, 522, 108, 109, 522, 108, 110, 778, 108, 111, 103, 522, 108, - 120, 522, 109, 98, 778, 109, 105, 108, 778, 109, 111, 108, 522, 80, 72, - 1034, 112, 46, 109, 46, 778, 80, 80, 77, 522, 80, 82, 522, 115, 114, 522, - 83, 118, 522, 87, 98, 778, 86, 8725, 109, 778, 65, 8725, 109, 514, 49, - 26085, 514, 50, 26085, 514, 51, 26085, 514, 52, 26085, 514, 53, 26085, - 514, 54, 26085, 514, 55, 26085, 514, 56, 26085, 514, 57, 26085, 770, 49, - 48, 26085, 770, 49, 49, 26085, 770, 49, 50, 26085, 770, 49, 51, 26085, - 770, 49, 52, 26085, 770, 49, 53, 26085, 770, 49, 54, 26085, 770, 49, 55, - 26085, 770, 49, 56, 26085, 770, 49, 57, 26085, 770, 50, 48, 26085, 770, - 50, 49, 26085, 770, 50, 50, 26085, 770, 50, 51, 26085, 770, 50, 52, - 26085, 770, 50, 53, 26085, 770, 50, 54, 26085, 770, 50, 55, 26085, 770, - 50, 56, 26085, 770, 50, 57, 26085, 770, 51, 48, 26085, 770, 51, 49, - 26085, 778, 103, 97, 108, 259, 1098, 259, 1100, 259, 42863, 259, 294, - 259, 339, 259, 42791, 259, 43831, 259, 619, 259, 43858, 256, 35912, 256, - 26356, 256, 36554, 256, 36040, 256, 28369, 256, 20018, 256, 21477, 256, - 40860, 256, 40860, 256, 22865, 256, 37329, 256, 21895, 256, 22856, 256, - 25078, 256, 30313, 256, 32645, 256, 34367, 256, 34746, 256, 35064, 256, - 37007, 256, 27138, 256, 27931, 256, 28889, 256, 29662, 256, 33853, 256, - 37226, 256, 39409, 256, 20098, 256, 21365, 256, 27396, 256, 29211, 256, - 34349, 256, 40478, 256, 23888, 256, 28651, 256, 34253, 256, 35172, 256, - 25289, 256, 33240, 256, 34847, 256, 24266, 256, 26391, 256, 28010, 256, - 29436, 256, 37070, 256, 20358, 256, 20919, 256, 21214, 256, 25796, 256, - 27347, 256, 29200, 256, 30439, 256, 32769, 256, 34310, 256, 34396, 256, - 36335, 256, 38706, 256, 39791, 256, 40442, 256, 30860, 256, 31103, 256, - 32160, 256, 33737, 256, 37636, 256, 40575, 256, 35542, 256, 22751, 256, - 24324, 256, 31840, 256, 32894, 256, 29282, 256, 30922, 256, 36034, 256, - 38647, 256, 22744, 256, 23650, 256, 27155, 256, 28122, 256, 28431, 256, - 32047, 256, 32311, 256, 38475, 256, 21202, 256, 32907, 256, 20956, 256, - 20940, 256, 31260, 256, 32190, 256, 33777, 256, 38517, 256, 35712, 256, - 25295, 256, 27138, 256, 35582, 256, 20025, 256, 23527, 256, 24594, 256, - 29575, 256, 30064, 256, 21271, 256, 30971, 256, 20415, 256, 24489, 256, - 19981, 256, 27852, 256, 25976, 256, 32034, 256, 21443, 256, 22622, 256, - 30465, 256, 33865, 256, 35498, 256, 27578, 256, 36784, 256, 27784, 256, - 25342, 256, 33509, 256, 25504, 256, 30053, 256, 20142, 256, 20841, 256, - 20937, 256, 26753, 256, 31975, 256, 33391, 256, 35538, 256, 37327, 256, - 21237, 256, 21570, 256, 22899, 256, 24300, 256, 26053, 256, 28670, 256, - 31018, 256, 38317, 256, 39530, 256, 40599, 256, 40654, 256, 21147, 256, - 26310, 256, 27511, 256, 36706, 256, 24180, 256, 24976, 256, 25088, 256, - 25754, 256, 28451, 256, 29001, 256, 29833, 256, 31178, 256, 32244, 256, - 32879, 256, 36646, 256, 34030, 256, 36899, 256, 37706, 256, 21015, 256, - 21155, 256, 21693, 256, 28872, 256, 35010, 256, 35498, 256, 24265, 256, - 24565, 256, 25467, 256, 27566, 256, 31806, 256, 29557, 256, 20196, 256, - 22265, 256, 23527, 256, 23994, 256, 24604, 256, 29618, 256, 29801, 256, - 32666, 256, 32838, 256, 37428, 256, 38646, 256, 38728, 256, 38936, 256, - 20363, 256, 31150, 256, 37300, 256, 38584, 256, 24801, 256, 20102, 256, - 20698, 256, 23534, 256, 23615, 256, 26009, 256, 27138, 256, 29134, 256, - 30274, 256, 34044, 256, 36988, 256, 40845, 256, 26248, 256, 38446, 256, - 21129, 256, 26491, 256, 26611, 256, 27969, 256, 28316, 256, 29705, 256, - 30041, 256, 30827, 256, 32016, 256, 39006, 256, 20845, 256, 25134, 256, - 38520, 256, 20523, 256, 23833, 256, 28138, 256, 36650, 256, 24459, 256, - 24900, 256, 26647, 256, 29575, 256, 38534, 256, 21033, 256, 21519, 256, - 23653, 256, 26131, 256, 26446, 256, 26792, 256, 27877, 256, 29702, 256, - 30178, 256, 32633, 256, 35023, 256, 35041, 256, 37324, 256, 38626, 256, - 21311, 256, 28346, 256, 21533, 256, 29136, 256, 29848, 256, 34298, 256, - 38563, 256, 40023, 256, 40607, 256, 26519, 256, 28107, 256, 33256, 256, - 31435, 256, 31520, 256, 31890, 256, 29376, 256, 28825, 256, 35672, 256, - 20160, 256, 33590, 256, 21050, 256, 20999, 256, 24230, 256, 25299, 256, - 31958, 256, 23429, 256, 27934, 256, 26292, 256, 36667, 256, 34892, 256, - 38477, 256, 35211, 256, 24275, 256, 20800, 256, 21952, 256, 22618, 256, - 26228, 256, 20958, 256, 29482, 256, 30410, 256, 31036, 256, 31070, 256, - 31077, 256, 31119, 256, 38742, 256, 31934, 256, 32701, 256, 34322, 256, - 35576, 256, 36920, 256, 37117, 256, 39151, 256, 39164, 256, 39208, 256, - 40372, 256, 37086, 256, 38583, 256, 20398, 256, 20711, 256, 20813, 256, - 21193, 256, 21220, 256, 21329, 256, 21917, 256, 22022, 256, 22120, 256, - 22592, 256, 22696, 256, 23652, 256, 23662, 256, 24724, 256, 24936, 256, - 24974, 256, 25074, 256, 25935, 256, 26082, 256, 26257, 256, 26757, 256, - 28023, 256, 28186, 256, 28450, 256, 29038, 256, 29227, 256, 29730, 256, - 30865, 256, 31038, 256, 31049, 256, 31048, 256, 31056, 256, 31062, 256, - 31069, 256, 31117, 256, 31118, 256, 31296, 256, 31361, 256, 31680, 256, - 32244, 256, 32265, 256, 32321, 256, 32626, 256, 32773, 256, 33261, 256, - 33401, 256, 33401, 256, 33879, 256, 35088, 256, 35222, 256, 35585, 256, - 35641, 256, 36051, 256, 36104, 256, 36790, 256, 36920, 256, 38627, 256, - 38911, 256, 38971, 256, 24693, 256, 55376, 57070, 256, 33304, 256, 20006, - 256, 20917, 256, 20840, 256, 20352, 256, 20805, 256, 20864, 256, 21191, - 256, 21242, 256, 21917, 256, 21845, 256, 21913, 256, 21986, 256, 22618, - 256, 22707, 256, 22852, 256, 22868, 256, 23138, 256, 23336, 256, 24274, - 256, 24281, 256, 24425, 256, 24493, 256, 24792, 256, 24910, 256, 24840, - 256, 24974, 256, 24928, 256, 25074, 256, 25140, 256, 25540, 256, 25628, - 256, 25682, 256, 25942, 256, 26228, 256, 26391, 256, 26395, 256, 26454, - 256, 27513, 256, 27578, 256, 27969, 256, 28379, 256, 28363, 256, 28450, - 256, 28702, 256, 29038, 256, 30631, 256, 29237, 256, 29359, 256, 29482, - 256, 29809, 256, 29958, 256, 30011, 256, 30237, 256, 30239, 256, 30410, - 256, 30427, 256, 30452, 256, 30538, 256, 30528, 256, 30924, 256, 31409, - 256, 31680, 256, 31867, 256, 32091, 256, 32244, 256, 32574, 256, 32773, - 256, 33618, 256, 33775, 256, 34681, 256, 35137, 256, 35206, 256, 35222, - 256, 35519, 256, 35576, 256, 35531, 256, 35585, 256, 35582, 256, 35565, - 256, 35641, 256, 35722, 256, 36104, 256, 36664, 256, 36978, 256, 37273, - 256, 37494, 256, 38524, 256, 38627, 256, 38742, 256, 38875, 256, 38911, - 256, 38923, 256, 38971, 256, 39698, 256, 40860, 256, 55370, 56394, 256, - 55370, 56388, 256, 55372, 57301, 256, 15261, 256, 16408, 256, 16441, 256, - 55380, 56905, 256, 55383, 56528, 256, 55391, 57043, 256, 40771, 256, - 40846, 514, 102, 102, 514, 102, 105, 514, 102, 108, 770, 102, 102, 105, - 770, 102, 102, 108, 514, 383, 116, 514, 115, 116, 514, 1396, 1398, 514, - 1396, 1381, 514, 1396, 1387, 514, 1406, 1398, 514, 1396, 1389, 512, 1497, - 1460, 512, 1522, 1463, 262, 1506, 262, 1488, 262, 1491, 262, 1492, 262, - 1499, 262, 1500, 262, 1501, 262, 1512, 262, 1514, 262, 43, 512, 1513, - 1473, 512, 1513, 1474, 512, 64329, 1473, 512, 64329, 1474, 512, 1488, - 1463, 512, 1488, 1464, 512, 1488, 1468, 512, 1489, 1468, 512, 1490, 1468, - 512, 1491, 1468, 512, 1492, 1468, 512, 1493, 1468, 512, 1494, 1468, 512, - 1496, 1468, 512, 1497, 1468, 512, 1498, 1468, 512, 1499, 1468, 512, 1500, - 1468, 512, 1502, 1468, 512, 1504, 1468, 512, 1505, 1468, 512, 1507, 1468, - 512, 1508, 1468, 512, 1510, 1468, 512, 1511, 1468, 512, 1512, 1468, 512, - 1513, 1468, 512, 1514, 1468, 512, 1493, 1465, 512, 1489, 1471, 512, 1499, - 1471, 512, 1508, 1471, 514, 1488, 1500, 267, 1649, 268, 1649, 267, 1659, - 268, 1659, 269, 1659, 270, 1659, 267, 1662, 268, 1662, 269, 1662, 270, - 1662, 267, 1664, 268, 1664, 269, 1664, 270, 1664, 267, 1658, 268, 1658, - 269, 1658, 270, 1658, 267, 1663, 268, 1663, 269, 1663, 270, 1663, 267, - 1657, 268, 1657, 269, 1657, 270, 1657, 267, 1700, 268, 1700, 269, 1700, - 270, 1700, 267, 1702, 268, 1702, 269, 1702, 270, 1702, 267, 1668, 268, - 1668, 269, 1668, 270, 1668, 267, 1667, 268, 1667, 269, 1667, 270, 1667, - 267, 1670, 268, 1670, 269, 1670, 270, 1670, 267, 1671, 268, 1671, 269, - 1671, 270, 1671, 267, 1677, 268, 1677, 267, 1676, 268, 1676, 267, 1678, - 268, 1678, 267, 1672, 268, 1672, 267, 1688, 268, 1688, 267, 1681, 268, - 1681, 267, 1705, 268, 1705, 269, 1705, 270, 1705, 267, 1711, 268, 1711, - 269, 1711, 270, 1711, 267, 1715, 268, 1715, 269, 1715, 270, 1715, 267, - 1713, 268, 1713, 269, 1713, 270, 1713, 267, 1722, 268, 1722, 267, 1723, - 268, 1723, 269, 1723, 270, 1723, 267, 1728, 268, 1728, 267, 1729, 268, - 1729, 269, 1729, 270, 1729, 267, 1726, 268, 1726, 269, 1726, 270, 1726, - 267, 1746, 268, 1746, 267, 1747, 268, 1747, 267, 1709, 268, 1709, 269, - 1709, 270, 1709, 267, 1735, 268, 1735, 267, 1734, 268, 1734, 267, 1736, - 268, 1736, 267, 1655, 267, 1739, 268, 1739, 267, 1733, 268, 1733, 267, - 1737, 268, 1737, 267, 1744, 268, 1744, 269, 1744, 270, 1744, 269, 1609, - 270, 1609, 523, 1574, 1575, 524, 1574, 1575, 523, 1574, 1749, 524, 1574, - 1749, 523, 1574, 1608, 524, 1574, 1608, 523, 1574, 1735, 524, 1574, 1735, - 523, 1574, 1734, 524, 1574, 1734, 523, 1574, 1736, 524, 1574, 1736, 523, - 1574, 1744, 524, 1574, 1744, 525, 1574, 1744, 523, 1574, 1609, 524, 1574, - 1609, 525, 1574, 1609, 267, 1740, 268, 1740, 269, 1740, 270, 1740, 523, - 1574, 1580, 523, 1574, 1581, 523, 1574, 1605, 523, 1574, 1609, 523, 1574, - 1610, 523, 1576, 1580, 523, 1576, 1581, 523, 1576, 1582, 523, 1576, 1605, - 523, 1576, 1609, 523, 1576, 1610, 523, 1578, 1580, 523, 1578, 1581, 523, - 1578, 1582, 523, 1578, 1605, 523, 1578, 1609, 523, 1578, 1610, 523, 1579, - 1580, 523, 1579, 1605, 523, 1579, 1609, 523, 1579, 1610, 523, 1580, 1581, - 523, 1580, 1605, 523, 1581, 1580, 523, 1581, 1605, 523, 1582, 1580, 523, - 1582, 1581, 523, 1582, 1605, 523, 1587, 1580, 523, 1587, 1581, 523, 1587, - 1582, 523, 1587, 1605, 523, 1589, 1581, 523, 1589, 1605, 523, 1590, 1580, - 523, 1590, 1581, 523, 1590, 1582, 523, 1590, 1605, 523, 1591, 1581, 523, - 1591, 1605, 523, 1592, 1605, 523, 1593, 1580, 523, 1593, 1605, 523, 1594, - 1580, 523, 1594, 1605, 523, 1601, 1580, 523, 1601, 1581, 523, 1601, 1582, - 523, 1601, 1605, 523, 1601, 1609, 523, 1601, 1610, 523, 1602, 1581, 523, - 1602, 1605, 523, 1602, 1609, 523, 1602, 1610, 523, 1603, 1575, 523, 1603, - 1580, 523, 1603, 1581, 523, 1603, 1582, 523, 1603, 1604, 523, 1603, 1605, - 523, 1603, 1609, 523, 1603, 1610, 523, 1604, 1580, 523, 1604, 1581, 523, - 1604, 1582, 523, 1604, 1605, 523, 1604, 1609, 523, 1604, 1610, 523, 1605, - 1580, 523, 1605, 1581, 523, 1605, 1582, 523, 1605, 1605, 523, 1605, 1609, - 523, 1605, 1610, 523, 1606, 1580, 523, 1606, 1581, 523, 1606, 1582, 523, - 1606, 1605, 523, 1606, 1609, 523, 1606, 1610, 523, 1607, 1580, 523, 1607, - 1605, 523, 1607, 1609, 523, 1607, 1610, 523, 1610, 1580, 523, 1610, 1581, - 523, 1610, 1582, 523, 1610, 1605, 523, 1610, 1609, 523, 1610, 1610, 523, - 1584, 1648, 523, 1585, 1648, 523, 1609, 1648, 779, 32, 1612, 1617, 779, - 32, 1613, 1617, 779, 32, 1614, 1617, 779, 32, 1615, 1617, 779, 32, 1616, - 1617, 779, 32, 1617, 1648, 524, 1574, 1585, 524, 1574, 1586, 524, 1574, - 1605, 524, 1574, 1606, 524, 1574, 1609, 524, 1574, 1610, 524, 1576, 1585, - 524, 1576, 1586, 524, 1576, 1605, 524, 1576, 1606, 524, 1576, 1609, 524, - 1576, 1610, 524, 1578, 1585, 524, 1578, 1586, 524, 1578, 1605, 524, 1578, - 1606, 524, 1578, 1609, 524, 1578, 1610, 524, 1579, 1585, 524, 1579, 1586, - 524, 1579, 1605, 524, 1579, 1606, 524, 1579, 1609, 524, 1579, 1610, 524, - 1601, 1609, 524, 1601, 1610, 524, 1602, 1609, 524, 1602, 1610, 524, 1603, - 1575, 524, 1603, 1604, 524, 1603, 1605, 524, 1603, 1609, 524, 1603, 1610, - 524, 1604, 1605, 524, 1604, 1609, 524, 1604, 1610, 524, 1605, 1575, 524, - 1605, 1605, 524, 1606, 1585, 524, 1606, 1586, 524, 1606, 1605, 524, 1606, - 1606, 524, 1606, 1609, 524, 1606, 1610, 524, 1609, 1648, 524, 1610, 1585, - 524, 1610, 1586, 524, 1610, 1605, 524, 1610, 1606, 524, 1610, 1609, 524, - 1610, 1610, 525, 1574, 1580, 525, 1574, 1581, 525, 1574, 1582, 525, 1574, - 1605, 525, 1574, 1607, 525, 1576, 1580, 525, 1576, 1581, 525, 1576, 1582, - 525, 1576, 1605, 525, 1576, 1607, 525, 1578, 1580, 525, 1578, 1581, 525, - 1578, 1582, 525, 1578, 1605, 525, 1578, 1607, 525, 1579, 1605, 525, 1580, - 1581, 525, 1580, 1605, 525, 1581, 1580, 525, 1581, 1605, 525, 1582, 1580, - 525, 1582, 1605, 525, 1587, 1580, 525, 1587, 1581, 525, 1587, 1582, 525, - 1587, 1605, 525, 1589, 1581, 525, 1589, 1582, 525, 1589, 1605, 525, 1590, - 1580, 525, 1590, 1581, 525, 1590, 1582, 525, 1590, 1605, 525, 1591, 1581, - 525, 1592, 1605, 525, 1593, 1580, 525, 1593, 1605, 525, 1594, 1580, 525, - 1594, 1605, 525, 1601, 1580, 525, 1601, 1581, 525, 1601, 1582, 525, 1601, - 1605, 525, 1602, 1581, 525, 1602, 1605, 525, 1603, 1580, 525, 1603, 1581, - 525, 1603, 1582, 525, 1603, 1604, 525, 1603, 1605, 525, 1604, 1580, 525, - 1604, 1581, 525, 1604, 1582, 525, 1604, 1605, 525, 1604, 1607, 525, 1605, - 1580, 525, 1605, 1581, 525, 1605, 1582, 525, 1605, 1605, 525, 1606, 1580, - 525, 1606, 1581, 525, 1606, 1582, 525, 1606, 1605, 525, 1606, 1607, 525, - 1607, 1580, 525, 1607, 1605, 525, 1607, 1648, 525, 1610, 1580, 525, 1610, - 1581, 525, 1610, 1582, 525, 1610, 1605, 525, 1610, 1607, 526, 1574, 1605, - 526, 1574, 1607, 526, 1576, 1605, 526, 1576, 1607, 526, 1578, 1605, 526, - 1578, 1607, 526, 1579, 1605, 526, 1579, 1607, 526, 1587, 1605, 526, 1587, - 1607, 526, 1588, 1605, 526, 1588, 1607, 526, 1603, 1604, 526, 1603, 1605, - 526, 1604, 1605, 526, 1606, 1605, 526, 1606, 1607, 526, 1610, 1605, 526, - 1610, 1607, 782, 1600, 1614, 1617, 782, 1600, 1615, 1617, 782, 1600, - 1616, 1617, 523, 1591, 1609, 523, 1591, 1610, 523, 1593, 1609, 523, 1593, - 1610, 523, 1594, 1609, 523, 1594, 1610, 523, 1587, 1609, 523, 1587, 1610, - 523, 1588, 1609, 523, 1588, 1610, 523, 1581, 1609, 523, 1581, 1610, 523, - 1580, 1609, 523, 1580, 1610, 523, 1582, 1609, 523, 1582, 1610, 523, 1589, - 1609, 523, 1589, 1610, 523, 1590, 1609, 523, 1590, 1610, 523, 1588, 1580, - 523, 1588, 1581, 523, 1588, 1582, 523, 1588, 1605, 523, 1588, 1585, 523, - 1587, 1585, 523, 1589, 1585, 523, 1590, 1585, 524, 1591, 1609, 524, 1591, - 1610, 524, 1593, 1609, 524, 1593, 1610, 524, 1594, 1609, 524, 1594, 1610, - 524, 1587, 1609, 524, 1587, 1610, 524, 1588, 1609, 524, 1588, 1610, 524, - 1581, 1609, 524, 1581, 1610, 524, 1580, 1609, 524, 1580, 1610, 524, 1582, - 1609, 524, 1582, 1610, 524, 1589, 1609, 524, 1589, 1610, 524, 1590, 1609, - 524, 1590, 1610, 524, 1588, 1580, 524, 1588, 1581, 524, 1588, 1582, 524, - 1588, 1605, 524, 1588, 1585, 524, 1587, 1585, 524, 1589, 1585, 524, 1590, - 1585, 525, 1588, 1580, 525, 1588, 1581, 525, 1588, 1582, 525, 1588, 1605, - 525, 1587, 1607, 525, 1588, 1607, 525, 1591, 1605, 526, 1587, 1580, 526, - 1587, 1581, 526, 1587, 1582, 526, 1588, 1580, 526, 1588, 1581, 526, 1588, - 1582, 526, 1591, 1605, 526, 1592, 1605, 524, 1575, 1611, 523, 1575, 1611, - 781, 1578, 1580, 1605, 780, 1578, 1581, 1580, 781, 1578, 1581, 1580, 781, - 1578, 1581, 1605, 781, 1578, 1582, 1605, 781, 1578, 1605, 1580, 781, - 1578, 1605, 1581, 781, 1578, 1605, 1582, 780, 1580, 1605, 1581, 781, - 1580, 1605, 1581, 780, 1581, 1605, 1610, 780, 1581, 1605, 1609, 781, - 1587, 1581, 1580, 781, 1587, 1580, 1581, 780, 1587, 1580, 1609, 780, - 1587, 1605, 1581, 781, 1587, 1605, 1581, 781, 1587, 1605, 1580, 780, - 1587, 1605, 1605, 781, 1587, 1605, 1605, 780, 1589, 1581, 1581, 781, - 1589, 1581, 1581, 780, 1589, 1605, 1605, 780, 1588, 1581, 1605, 781, - 1588, 1581, 1605, 780, 1588, 1580, 1610, 780, 1588, 1605, 1582, 781, - 1588, 1605, 1582, 780, 1588, 1605, 1605, 781, 1588, 1605, 1605, 780, - 1590, 1581, 1609, 780, 1590, 1582, 1605, 781, 1590, 1582, 1605, 780, - 1591, 1605, 1581, 781, 1591, 1605, 1581, 781, 1591, 1605, 1605, 780, - 1591, 1605, 1610, 780, 1593, 1580, 1605, 780, 1593, 1605, 1605, 781, - 1593, 1605, 1605, 780, 1593, 1605, 1609, 780, 1594, 1605, 1605, 780, - 1594, 1605, 1610, 780, 1594, 1605, 1609, 780, 1601, 1582, 1605, 781, - 1601, 1582, 1605, 780, 1602, 1605, 1581, 780, 1602, 1605, 1605, 780, - 1604, 1581, 1605, 780, 1604, 1581, 1610, 780, 1604, 1581, 1609, 781, - 1604, 1580, 1580, 780, 1604, 1580, 1580, 780, 1604, 1582, 1605, 781, - 1604, 1582, 1605, 780, 1604, 1605, 1581, 781, 1604, 1605, 1581, 781, - 1605, 1581, 1580, 781, 1605, 1581, 1605, 780, 1605, 1581, 1610, 781, - 1605, 1580, 1581, 781, 1605, 1580, 1605, 781, 1605, 1582, 1580, 781, - 1605, 1582, 1605, 781, 1605, 1580, 1582, 781, 1607, 1605, 1580, 781, - 1607, 1605, 1605, 781, 1606, 1581, 1605, 780, 1606, 1581, 1609, 780, - 1606, 1580, 1605, 781, 1606, 1580, 1605, 780, 1606, 1580, 1609, 780, - 1606, 1605, 1610, 780, 1606, 1605, 1609, 780, 1610, 1605, 1605, 781, - 1610, 1605, 1605, 780, 1576, 1582, 1610, 780, 1578, 1580, 1610, 780, - 1578, 1580, 1609, 780, 1578, 1582, 1610, 780, 1578, 1582, 1609, 780, - 1578, 1605, 1610, 780, 1578, 1605, 1609, 780, 1580, 1605, 1610, 780, - 1580, 1581, 1609, 780, 1580, 1605, 1609, 780, 1587, 1582, 1609, 780, - 1589, 1581, 1610, 780, 1588, 1581, 1610, 780, 1590, 1581, 1610, 780, - 1604, 1580, 1610, 780, 1604, 1605, 1610, 780, 1610, 1581, 1610, 780, - 1610, 1580, 1610, 780, 1610, 1605, 1610, 780, 1605, 1605, 1610, 780, - 1602, 1605, 1610, 780, 1606, 1581, 1610, 781, 1602, 1605, 1581, 781, - 1604, 1581, 1605, 780, 1593, 1605, 1610, 780, 1603, 1605, 1610, 781, - 1606, 1580, 1581, 780, 1605, 1582, 1610, 781, 1604, 1580, 1605, 780, - 1603, 1605, 1605, 780, 1604, 1580, 1605, 780, 1606, 1580, 1581, 780, - 1580, 1581, 1610, 780, 1581, 1580, 1610, 780, 1605, 1580, 1610, 780, - 1601, 1605, 1610, 780, 1576, 1581, 1610, 781, 1603, 1605, 1605, 781, - 1593, 1580, 1605, 781, 1589, 1605, 1605, 780, 1587, 1582, 1610, 780, - 1606, 1580, 1610, 779, 1589, 1604, 1746, 779, 1602, 1604, 1746, 1035, - 1575, 1604, 1604, 1607, 1035, 1575, 1603, 1576, 1585, 1035, 1605, 1581, - 1605, 1583, 1035, 1589, 1604, 1593, 1605, 1035, 1585, 1587, 1608, 1604, - 1035, 1593, 1604, 1610, 1607, 1035, 1608, 1587, 1604, 1605, 779, 1589, - 1604, 1609, 4619, 1589, 1604, 1609, 32, 1575, 1604, 1604, 1607, 32, 1593, - 1604, 1610, 1607, 32, 1608, 1587, 1604, 1605, 2059, 1580, 1604, 32, 1580, - 1604, 1575, 1604, 1607, 1035, 1585, 1740, 1575, 1604, 265, 44, 265, - 12289, 265, 12290, 265, 58, 265, 59, 265, 33, 265, 63, 265, 12310, 265, - 12311, 265, 8230, 265, 8229, 265, 8212, 265, 8211, 265, 95, 265, 95, 265, - 40, 265, 41, 265, 123, 265, 125, 265, 12308, 265, 12309, 265, 12304, 265, - 12305, 265, 12298, 265, 12299, 265, 12296, 265, 12297, 265, 12300, 265, - 12301, 265, 12302, 265, 12303, 265, 91, 265, 93, 258, 8254, 258, 8254, - 258, 8254, 258, 8254, 258, 95, 258, 95, 258, 95, 271, 44, 271, 12289, - 271, 46, 271, 59, 271, 58, 271, 63, 271, 33, 271, 8212, 271, 40, 271, 41, - 271, 123, 271, 125, 271, 12308, 271, 12309, 271, 35, 271, 38, 271, 42, - 271, 43, 271, 45, 271, 60, 271, 62, 271, 61, 271, 92, 271, 36, 271, 37, - 271, 64, 523, 32, 1611, 526, 1600, 1611, 523, 32, 1612, 523, 32, 1613, - 523, 32, 1614, 526, 1600, 1614, 523, 32, 1615, 526, 1600, 1615, 523, 32, - 1616, 526, 1600, 1616, 523, 32, 1617, 526, 1600, 1617, 523, 32, 1618, - 526, 1600, 1618, 267, 1569, 267, 1570, 268, 1570, 267, 1571, 268, 1571, - 267, 1572, 268, 1572, 267, 1573, 268, 1573, 267, 1574, 268, 1574, 269, - 1574, 270, 1574, 267, 1575, 268, 1575, 267, 1576, 268, 1576, 269, 1576, - 270, 1576, 267, 1577, 268, 1577, 267, 1578, 268, 1578, 269, 1578, 270, - 1578, 267, 1579, 268, 1579, 269, 1579, 270, 1579, 267, 1580, 268, 1580, - 269, 1580, 270, 1580, 267, 1581, 268, 1581, 269, 1581, 270, 1581, 267, - 1582, 268, 1582, 269, 1582, 270, 1582, 267, 1583, 268, 1583, 267, 1584, - 268, 1584, 267, 1585, 268, 1585, 267, 1586, 268, 1586, 267, 1587, 268, - 1587, 269, 1587, 270, 1587, 267, 1588, 268, 1588, 269, 1588, 270, 1588, - 267, 1589, 268, 1589, 269, 1589, 270, 1589, 267, 1590, 268, 1590, 269, - 1590, 270, 1590, 267, 1591, 268, 1591, 269, 1591, 270, 1591, 267, 1592, - 268, 1592, 269, 1592, 270, 1592, 267, 1593, 268, 1593, 269, 1593, 270, - 1593, 267, 1594, 268, 1594, 269, 1594, 270, 1594, 267, 1601, 268, 1601, - 269, 1601, 270, 1601, 267, 1602, 268, 1602, 269, 1602, 270, 1602, 267, - 1603, 268, 1603, 269, 1603, 270, 1603, 267, 1604, 268, 1604, 269, 1604, - 270, 1604, 267, 1605, 268, 1605, 269, 1605, 270, 1605, 267, 1606, 268, - 1606, 269, 1606, 270, 1606, 267, 1607, 268, 1607, 269, 1607, 270, 1607, - 267, 1608, 268, 1608, 267, 1609, 268, 1609, 267, 1610, 268, 1610, 269, - 1610, 270, 1610, 523, 1604, 1570, 524, 1604, 1570, 523, 1604, 1571, 524, - 1604, 1571, 523, 1604, 1573, 524, 1604, 1573, 523, 1604, 1575, 524, 1604, - 1575, 264, 33, 264, 34, 264, 35, 264, 36, 264, 37, 264, 38, 264, 39, 264, - 40, 264, 41, 264, 42, 264, 43, 264, 44, 264, 45, 264, 46, 264, 47, 264, - 48, 264, 49, 264, 50, 264, 51, 264, 52, 264, 53, 264, 54, 264, 55, 264, - 56, 264, 57, 264, 58, 264, 59, 264, 60, 264, 61, 264, 62, 264, 63, 264, - 64, 264, 65, 264, 66, 264, 67, 264, 68, 264, 69, 264, 70, 264, 71, 264, - 72, 264, 73, 264, 74, 264, 75, 264, 76, 264, 77, 264, 78, 264, 79, 264, - 80, 264, 81, 264, 82, 264, 83, 264, 84, 264, 85, 264, 86, 264, 87, 264, - 88, 264, 89, 264, 90, 264, 91, 264, 92, 264, 93, 264, 94, 264, 95, 264, - 96, 264, 97, 264, 98, 264, 99, 264, 100, 264, 101, 264, 102, 264, 103, - 264, 104, 264, 105, 264, 106, 264, 107, 264, 108, 264, 109, 264, 110, - 264, 111, 264, 112, 264, 113, 264, 114, 264, 115, 264, 116, 264, 117, - 264, 118, 264, 119, 264, 120, 264, 121, 264, 122, 264, 123, 264, 124, - 264, 125, 264, 126, 264, 10629, 264, 10630, 272, 12290, 272, 12300, 272, - 12301, 272, 12289, 272, 12539, 272, 12530, 272, 12449, 272, 12451, 272, - 12453, 272, 12455, 272, 12457, 272, 12515, 272, 12517, 272, 12519, 272, - 12483, 272, 12540, 272, 12450, 272, 12452, 272, 12454, 272, 12456, 272, - 12458, 272, 12459, 272, 12461, 272, 12463, 272, 12465, 272, 12467, 272, - 12469, 272, 12471, 272, 12473, 272, 12475, 272, 12477, 272, 12479, 272, - 12481, 272, 12484, 272, 12486, 272, 12488, 272, 12490, 272, 12491, 272, - 12492, 272, 12493, 272, 12494, 272, 12495, 272, 12498, 272, 12501, 272, - 12504, 272, 12507, 272, 12510, 272, 12511, 272, 12512, 272, 12513, 272, - 12514, 272, 12516, 272, 12518, 272, 12520, 272, 12521, 272, 12522, 272, - 12523, 272, 12524, 272, 12525, 272, 12527, 272, 12531, 272, 12441, 272, - 12442, 272, 12644, 272, 12593, 272, 12594, 272, 12595, 272, 12596, 272, - 12597, 272, 12598, 272, 12599, 272, 12600, 272, 12601, 272, 12602, 272, - 12603, 272, 12604, 272, 12605, 272, 12606, 272, 12607, 272, 12608, 272, - 12609, 272, 12610, 272, 12611, 272, 12612, 272, 12613, 272, 12614, 272, - 12615, 272, 12616, 272, 12617, 272, 12618, 272, 12619, 272, 12620, 272, - 12621, 272, 12622, 272, 12623, 272, 12624, 272, 12625, 272, 12626, 272, - 12627, 272, 12628, 272, 12629, 272, 12630, 272, 12631, 272, 12632, 272, - 12633, 272, 12634, 272, 12635, 272, 12636, 272, 12637, 272, 12638, 272, - 12639, 272, 12640, 272, 12641, 272, 12642, 272, 12643, 264, 162, 264, - 163, 264, 172, 264, 175, 264, 166, 264, 165, 264, 8361, 272, 9474, 272, - 8592, 272, 8593, 272, 8594, 272, 8595, 272, 9632, 272, 9675, 512, 55300, - 56473, 55300, 56506, 512, 55300, 56475, 55300, 56506, 512, 55300, 56485, - 55300, 56506, 512, 55300, 56625, 55300, 56615, 512, 55300, 56626, 55300, - 56615, 512, 55300, 57159, 55300, 57150, 512, 55300, 57159, 55300, 57175, - 512, 55301, 56505, 55301, 56506, 512, 55301, 56505, 55301, 56496, 512, - 55301, 56505, 55301, 56509, 512, 55301, 56760, 55301, 56751, 512, 55301, - 56761, 55301, 56751, 512, 55348, 56663, 55348, 56677, 512, 55348, 56664, - 55348, 56677, 512, 55348, 56671, 55348, 56686, 512, 55348, 56671, 55348, - 56687, 512, 55348, 56671, 55348, 56688, 512, 55348, 56671, 55348, 56689, - 512, 55348, 56671, 55348, 56690, 512, 55348, 56761, 55348, 56677, 512, - 55348, 56762, 55348, 56677, 512, 55348, 56763, 55348, 56686, 512, 55348, - 56764, 55348, 56686, 512, 55348, 56763, 55348, 56687, 512, 55348, 56764, - 55348, 56687, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, - 71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, - 79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, - 87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, - 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, - 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, - 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, - 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, - 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, - 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, - 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, - 102, 262, 103, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, - 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, - 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, - 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, - 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, - 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, - 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, - 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, - 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, - 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 67, 262, 68, - 262, 71, 262, 74, 262, 75, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, - 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, - 262, 98, 262, 99, 262, 100, 262, 102, 262, 104, 262, 105, 262, 106, 262, - 107, 262, 108, 262, 109, 262, 110, 262, 112, 262, 113, 262, 114, 262, - 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, - 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, - 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, - 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, - 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, - 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, - 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, - 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, - 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 74, 262, 75, 262, 76, - 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 83, 262, 84, 262, 85, - 262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100, - 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, - 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, - 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, - 262, 122, 262, 65, 262, 66, 262, 68, 262, 69, 262, 70, 262, 71, 262, 73, - 262, 74, 262, 75, 262, 76, 262, 77, 262, 79, 262, 83, 262, 84, 262, 85, - 262, 86, 262, 87, 262, 88, 262, 89, 262, 97, 262, 98, 262, 99, 262, 100, - 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, - 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, - 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, - 262, 122, 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, - 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, - 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, - 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, - 262, 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, - 262, 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, - 262, 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, - 262, 65, 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, - 262, 73, 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, - 262, 81, 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, - 262, 89, 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, - 102, 262, 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, - 109, 262, 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, - 116, 262, 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, - 262, 66, 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, - 262, 74, 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, - 262, 82, 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, - 262, 90, 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, - 103, 262, 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, - 110, 262, 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, - 117, 262, 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, - 262, 67, 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, - 262, 75, 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, - 262, 83, 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, - 262, 97, 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, - 104, 262, 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, - 111, 262, 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, - 118, 262, 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, - 262, 68, 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, - 262, 76, 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, - 262, 84, 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, - 262, 98, 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, - 105, 262, 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, - 112, 262, 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, - 119, 262, 120, 262, 121, 262, 122, 262, 65, 262, 66, 262, 67, 262, 68, - 262, 69, 262, 70, 262, 71, 262, 72, 262, 73, 262, 74, 262, 75, 262, 76, - 262, 77, 262, 78, 262, 79, 262, 80, 262, 81, 262, 82, 262, 83, 262, 84, - 262, 85, 262, 86, 262, 87, 262, 88, 262, 89, 262, 90, 262, 97, 262, 98, - 262, 99, 262, 100, 262, 101, 262, 102, 262, 103, 262, 104, 262, 105, 262, - 106, 262, 107, 262, 108, 262, 109, 262, 110, 262, 111, 262, 112, 262, - 113, 262, 114, 262, 115, 262, 116, 262, 117, 262, 118, 262, 119, 262, - 120, 262, 121, 262, 122, 262, 305, 262, 567, 262, 913, 262, 914, 262, - 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, - 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, - 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, - 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, - 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, - 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, - 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, - 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, - 913, 262, 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, - 920, 262, 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, - 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, - 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, - 947, 262, 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, - 954, 262, 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, - 961, 262, 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, - 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, - 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, 916, 262, 917, 262, - 918, 262, 919, 262, 920, 262, 921, 262, 922, 262, 923, 262, 924, 262, - 925, 262, 926, 262, 927, 262, 928, 262, 929, 262, 1012, 262, 931, 262, - 932, 262, 933, 262, 934, 262, 935, 262, 936, 262, 937, 262, 8711, 262, - 945, 262, 946, 262, 947, 262, 948, 262, 949, 262, 950, 262, 951, 262, - 952, 262, 953, 262, 954, 262, 955, 262, 956, 262, 957, 262, 958, 262, - 959, 262, 960, 262, 961, 262, 962, 262, 963, 262, 964, 262, 965, 262, - 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, 1013, 262, 977, 262, - 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, 914, 262, 915, 262, - 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, 921, 262, 922, 262, - 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, 928, 262, 929, 262, - 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, 935, 262, 936, 262, - 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, 948, 262, 949, 262, - 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, 955, 262, 956, 262, - 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, 962, 262, 963, 262, - 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, 969, 262, 8706, 262, - 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, 982, 262, 913, 262, - 914, 262, 915, 262, 916, 262, 917, 262, 918, 262, 919, 262, 920, 262, - 921, 262, 922, 262, 923, 262, 924, 262, 925, 262, 926, 262, 927, 262, - 928, 262, 929, 262, 1012, 262, 931, 262, 932, 262, 933, 262, 934, 262, - 935, 262, 936, 262, 937, 262, 8711, 262, 945, 262, 946, 262, 947, 262, - 948, 262, 949, 262, 950, 262, 951, 262, 952, 262, 953, 262, 954, 262, - 955, 262, 956, 262, 957, 262, 958, 262, 959, 262, 960, 262, 961, 262, - 962, 262, 963, 262, 964, 262, 965, 262, 966, 262, 967, 262, 968, 262, - 969, 262, 8706, 262, 1013, 262, 977, 262, 1008, 262, 981, 262, 1009, 262, - 982, 262, 988, 262, 989, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, - 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, - 262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 48, - 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, 262, 55, 262, 56, - 262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, 262, 53, 262, 54, - 262, 55, 262, 56, 262, 57, 262, 48, 262, 49, 262, 50, 262, 51, 262, 52, - 262, 53, 262, 54, 262, 55, 262, 56, 262, 57, 262, 1575, 262, 1576, 262, - 1580, 262, 1583, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, - 262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262, 1593, 262, - 1601, 262, 1589, 262, 1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579, - 262, 1582, 262, 1584, 262, 1590, 262, 1592, 262, 1594, 262, 1646, 262, - 1722, 262, 1697, 262, 1647, 262, 1576, 262, 1580, 262, 1607, 262, 1581, - 262, 1610, 262, 1603, 262, 1604, 262, 1605, 262, 1606, 262, 1587, 262, - 1593, 262, 1601, 262, 1589, 262, 1602, 262, 1588, 262, 1578, 262, 1579, - 262, 1582, 262, 1590, 262, 1594, 262, 1580, 262, 1581, 262, 1610, 262, - 1604, 262, 1606, 262, 1587, 262, 1593, 262, 1589, 262, 1602, 262, 1588, - 262, 1582, 262, 1590, 262, 1594, 262, 1722, 262, 1647, 262, 1576, 262, - 1580, 262, 1607, 262, 1581, 262, 1591, 262, 1610, 262, 1603, 262, 1605, - 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262, - 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1590, 262, 1592, 262, 1594, - 262, 1646, 262, 1697, 262, 1575, 262, 1576, 262, 1580, 262, 1583, 262, - 1607, 262, 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604, - 262, 1605, 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, - 1602, 262, 1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584, - 262, 1590, 262, 1592, 262, 1594, 262, 1576, 262, 1580, 262, 1583, 262, - 1608, 262, 1586, 262, 1581, 262, 1591, 262, 1610, 262, 1604, 262, 1605, - 262, 1606, 262, 1587, 262, 1593, 262, 1601, 262, 1589, 262, 1602, 262, - 1585, 262, 1588, 262, 1578, 262, 1579, 262, 1582, 262, 1584, 262, 1590, - 262, 1592, 262, 1594, 514, 48, 46, 514, 48, 44, 514, 49, 44, 514, 50, 44, - 514, 51, 44, 514, 52, 44, 514, 53, 44, 514, 54, 44, 514, 55, 44, 514, 56, - 44, 514, 57, 44, 770, 40, 65, 41, 770, 40, 66, 41, 770, 40, 67, 41, 770, - 40, 68, 41, 770, 40, 69, 41, 770, 40, 70, 41, 770, 40, 71, 41, 770, 40, - 72, 41, 770, 40, 73, 41, 770, 40, 74, 41, 770, 40, 75, 41, 770, 40, 76, - 41, 770, 40, 77, 41, 770, 40, 78, 41, 770, 40, 79, 41, 770, 40, 80, 41, - 770, 40, 81, 41, 770, 40, 82, 41, 770, 40, 83, 41, 770, 40, 84, 41, 770, - 40, 85, 41, 770, 40, 86, 41, 770, 40, 87, 41, 770, 40, 88, 41, 770, 40, - 89, 41, 770, 40, 90, 41, 770, 12308, 83, 12309, 263, 67, 263, 82, 519, - 67, 68, 519, 87, 90, 266, 65, 266, 66, 266, 67, 266, 68, 266, 69, 266, - 70, 266, 71, 266, 72, 266, 73, 266, 74, 266, 75, 266, 76, 266, 77, 266, - 78, 266, 79, 266, 80, 266, 81, 266, 82, 266, 83, 266, 84, 266, 85, 266, - 86, 266, 87, 266, 88, 266, 89, 266, 90, 522, 72, 86, 522, 77, 86, 522, - 83, 68, 522, 83, 83, 778, 80, 80, 86, 522, 87, 67, 515, 77, 67, 515, 77, - 68, 522, 68, 74, 522, 12411, 12363, 522, 12467, 12467, 266, 12469, 266, - 25163, 266, 23383, 266, 21452, 266, 12487, 266, 20108, 266, 22810, 266, - 35299, 266, 22825, 266, 20132, 266, 26144, 266, 28961, 266, 26009, 266, - 21069, 266, 24460, 266, 20877, 266, 26032, 266, 21021, 266, 32066, 266, - 29983, 266, 36009, 266, 22768, 266, 21561, 266, 28436, 266, 25237, 266, - 25429, 266, 19968, 266, 19977, 266, 36938, 266, 24038, 266, 20013, 266, - 21491, 266, 25351, 266, 36208, 266, 25171, 266, 31105, 266, 31354, 266, - 21512, 266, 28288, 266, 26377, 266, 26376, 266, 30003, 266, 21106, 266, - 21942, 266, 37197, 770, 12308, 26412, 12309, 770, 12308, 19977, 12309, - 770, 12308, 20108, 12309, 770, 12308, 23433, 12309, 770, 12308, 28857, - 12309, 770, 12308, 25171, 12309, 770, 12308, 30423, 12309, 770, 12308, - 21213, 12309, 770, 12308, 25943, 12309, 263, 24471, 263, 21487, 256, - 20029, 256, 20024, 256, 20033, 256, 55360, 56610, 256, 20320, 256, 20398, - 256, 20411, 256, 20482, 256, 20602, 256, 20633, 256, 20711, 256, 20687, - 256, 13470, 256, 55361, 56890, 256, 20813, 256, 20820, 256, 20836, 256, - 20855, 256, 55361, 56604, 256, 13497, 256, 20839, 256, 20877, 256, 55361, - 56651, 256, 20887, 256, 20900, 256, 20172, 256, 20908, 256, 20917, 256, - 55396, 56799, 256, 20981, 256, 20995, 256, 13535, 256, 21051, 256, 21062, - 256, 21106, 256, 21111, 256, 13589, 256, 21191, 256, 21193, 256, 21220, - 256, 21242, 256, 21253, 256, 21254, 256, 21271, 256, 21321, 256, 21329, - 256, 21338, 256, 21363, 256, 21373, 256, 21375, 256, 21375, 256, 21375, - 256, 55362, 56876, 256, 28784, 256, 21450, 256, 21471, 256, 55362, 57187, - 256, 21483, 256, 21489, 256, 21510, 256, 21662, 256, 21560, 256, 21576, - 256, 21608, 256, 21666, 256, 21750, 256, 21776, 256, 21843, 256, 21859, - 256, 21892, 256, 21892, 256, 21913, 256, 21931, 256, 21939, 256, 21954, - 256, 22294, 256, 22022, 256, 22295, 256, 22097, 256, 22132, 256, 20999, - 256, 22766, 256, 22478, 256, 22516, 256, 22541, 256, 22411, 256, 22578, - 256, 22577, 256, 22700, 256, 55365, 56548, 256, 22770, 256, 22775, 256, - 22790, 256, 22810, 256, 22818, 256, 22882, 256, 55365, 57000, 256, 55365, - 57066, 256, 23020, 256, 23067, 256, 23079, 256, 23000, 256, 23142, 256, - 14062, 256, 14076, 256, 23304, 256, 23358, 256, 23358, 256, 55366, 56776, - 256, 23491, 256, 23512, 256, 23527, 256, 23539, 256, 55366, 57112, 256, - 23551, 256, 23558, 256, 24403, 256, 23586, 256, 14209, 256, 23648, 256, - 23662, 256, 23744, 256, 23693, 256, 55367, 56804, 256, 23875, 256, 55367, - 56806, 256, 23918, 256, 23915, 256, 23932, 256, 24033, 256, 24034, 256, - 14383, 256, 24061, 256, 24104, 256, 24125, 256, 24169, 256, 14434, 256, - 55368, 56707, 256, 14460, 256, 24240, 256, 24243, 256, 24246, 256, 24266, - 256, 55400, 57234, 256, 24318, 256, 55368, 57137, 256, 55368, 57137, 256, - 33281, 256, 24354, 256, 24354, 256, 14535, 256, 55372, 57016, 256, 55384, - 56794, 256, 24418, 256, 24427, 256, 14563, 256, 24474, 256, 24525, 256, - 24535, 256, 24569, 256, 24705, 256, 14650, 256, 14620, 256, 24724, 256, - 55369, 57044, 256, 24775, 256, 24904, 256, 24908, 256, 24910, 256, 24908, - 256, 24954, 256, 24974, 256, 25010, 256, 24996, 256, 25007, 256, 25054, - 256, 25074, 256, 25078, 256, 25104, 256, 25115, 256, 25181, 256, 25265, - 256, 25300, 256, 25424, 256, 55370, 57100, 256, 25405, 256, 25340, 256, - 25448, 256, 25475, 256, 25572, 256, 55370, 57329, 256, 25634, 256, 25541, - 256, 25513, 256, 14894, 256, 25705, 256, 25726, 256, 25757, 256, 25719, - 256, 14956, 256, 25935, 256, 25964, 256, 55372, 56330, 256, 26083, 256, - 26360, 256, 26185, 256, 15129, 256, 26257, 256, 15112, 256, 15076, 256, - 20882, 256, 20885, 256, 26368, 256, 26268, 256, 32941, 256, 17369, 256, - 26391, 256, 26395, 256, 26401, 256, 26462, 256, 26451, 256, 55372, 57283, - 256, 15177, 256, 26618, 256, 26501, 256, 26706, 256, 26757, 256, 55373, - 56429, 256, 26766, 256, 26655, 256, 26900, 256, 15261, 256, 26946, 256, - 27043, 256, 27114, 256, 27304, 256, 55373, 56995, 256, 27355, 256, 15384, - 256, 27425, 256, 55374, 56487, 256, 27476, 256, 15438, 256, 27506, 256, - 27551, 256, 27578, 256, 27579, 256, 55374, 56973, 256, 55367, 56587, 256, - 55374, 57082, 256, 27726, 256, 55375, 56508, 256, 27839, 256, 27853, 256, - 27751, 256, 27926, 256, 27966, 256, 28023, 256, 27969, 256, 28009, 256, - 28024, 256, 28037, 256, 55375, 56606, 256, 27956, 256, 28207, 256, 28270, - 256, 15667, 256, 28363, 256, 28359, 256, 55375, 57041, 256, 28153, 256, - 28526, 256, 55375, 57182, 256, 55375, 57230, 256, 28614, 256, 28729, 256, - 28702, 256, 28699, 256, 15766, 256, 28746, 256, 28797, 256, 28791, 256, - 28845, 256, 55361, 56613, 256, 28997, 256, 55376, 56931, 256, 29084, 256, - 55376, 57259, 256, 29224, 256, 29237, 256, 29264, 256, 55377, 56840, 256, - 29312, 256, 29333, 256, 55377, 57141, 256, 55378, 56340, 256, 29562, 256, - 29579, 256, 16044, 256, 29605, 256, 16056, 256, 16056, 256, 29767, 256, - 29788, 256, 29809, 256, 29829, 256, 29898, 256, 16155, 256, 29988, 256, - 55379, 56374, 256, 30014, 256, 55379, 56466, 256, 30064, 256, 55368, - 56735, 256, 30224, 256, 55379, 57249, 256, 55379, 57272, 256, 55380, - 56388, 256, 16380, 256, 16392, 256, 30452, 256, 55380, 56563, 256, 55380, - 56562, 256, 55380, 56601, 256, 55380, 56627, 256, 30494, 256, 30495, 256, - 30495, 256, 30538, 256, 16441, 256, 30603, 256, 16454, 256, 16534, 256, - 55381, 56349, 256, 30798, 256, 30860, 256, 30924, 256, 16611, 256, 55381, - 56870, 256, 31062, 256, 55381, 56986, 256, 55381, 57029, 256, 31119, 256, - 31211, 256, 16687, 256, 31296, 256, 31306, 256, 31311, 256, 55382, 56700, - 256, 55382, 56999, 256, 55382, 56999, 256, 31470, 256, 16898, 256, 55382, - 57259, 256, 31686, 256, 31689, 256, 16935, 256, 55383, 56448, 256, 31954, - 256, 17056, 256, 31976, 256, 31971, 256, 32000, 256, 55383, 57222, 256, - 32099, 256, 17153, 256, 32199, 256, 32258, 256, 32325, 256, 17204, 256, - 55384, 56872, 256, 55384, 56903, 256, 17241, 256, 55384, 57049, 256, - 32634, 256, 55384, 57150, 256, 32661, 256, 32762, 256, 32773, 256, 55385, - 56538, 256, 55385, 56611, 256, 32864, 256, 55385, 56744, 256, 32880, 256, - 55372, 57183, 256, 17365, 256, 32946, 256, 33027, 256, 17419, 256, 33086, - 256, 23221, 256, 55385, 57255, 256, 55385, 57269, 256, 55372, 57235, 256, - 55372, 57244, 256, 33281, 256, 33284, 256, 36766, 256, 17515, 256, 33425, - 256, 33419, 256, 33437, 256, 21171, 256, 33457, 256, 33459, 256, 33469, - 256, 33510, 256, 55386, 57148, 256, 33509, 256, 33565, 256, 33635, 256, - 33709, 256, 33571, 256, 33725, 256, 33767, 256, 33879, 256, 33619, 256, - 33738, 256, 33740, 256, 33756, 256, 55387, 56374, 256, 55387, 56683, 256, - 55387, 56533, 256, 17707, 256, 34033, 256, 34035, 256, 34070, 256, 55388, - 57290, 256, 34148, 256, 55387, 57132, 256, 17757, 256, 17761, 256, 55387, - 57265, 256, 55388, 56530, 256, 17771, 256, 34384, 256, 34396, 256, 34407, - 256, 34409, 256, 34473, 256, 34440, 256, 34574, 256, 34530, 256, 34681, - 256, 34600, 256, 34667, 256, 34694, 256, 17879, 256, 34785, 256, 34817, - 256, 17913, 256, 34912, 256, 34915, 256, 55389, 56935, 256, 35031, 256, - 35038, 256, 17973, 256, 35066, 256, 13499, 256, 55390, 56494, 256, 55390, - 56678, 256, 18110, 256, 18119, 256, 35488, 256, 35565, 256, 35722, 256, - 35925, 256, 55391, 56488, 256, 36011, 256, 36033, 256, 36123, 256, 36215, - 256, 55391, 57135, 256, 55362, 56324, 256, 36299, 256, 36284, 256, 36336, - 256, 55362, 56542, 256, 36564, 256, 36664, 256, 55393, 56786, 256, 55393, - 56813, 256, 37012, 256, 37105, 256, 37137, 256, 55393, 57134, 256, 37147, - 256, 37432, 256, 37591, 256, 37592, 256, 37500, 256, 37881, 256, 37909, - 256, 55394, 57338, 256, 38283, 256, 18837, 256, 38327, 256, 55395, 56695, - 256, 18918, 256, 38595, 256, 23986, 256, 38691, 256, 55396, 56645, 256, - 55396, 56858, 256, 19054, 256, 19062, 256, 38880, 256, 55397, 56330, 256, - 19122, 256, 55397, 56470, 256, 38923, 256, 38923, 256, 38953, 256, 55397, - 56758, 256, 39138, 256, 19251, 256, 39209, 256, 39335, 256, 39362, 256, - 39422, 256, 19406, 256, 55398, 57136, 256, 39698, 256, 40000, 256, 40189, - 256, 19662, 256, 19693, 256, 40295, 256, 55400, 56526, 256, 19704, 256, - 55400, 56581, 256, 55400, 56846, 256, 55400, 56977, 256, 40635, 256, - 19798, 256, 40697, 256, 40702, 256, 40709, 256, 40719, 256, 40726, 256, - 40763, 256, 55401, 56832, -}; - -/* index tables for the decomposition data */ -#define DECOMP_SHIFT1 6 -#define DECOMP_SHIFT2 4 -static const unsigned char decomp_index0[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 13, 14, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 15, 16, 5, 5, 5, 5, 17, 18, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 19, 20, - 5, 5, 5, 5, 5, 21, 22, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 23, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, -}; - -static const unsigned short decomp_index1[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 0, 0, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 0, 0, 0, 0, 0, 0, 0, - 25, 0, 26, 27, 0, 0, 0, 0, 0, 28, 0, 0, 29, 30, 31, 32, 33, 34, 35, 0, - 36, 37, 38, 0, 39, 0, 40, 0, 41, 0, 0, 0, 0, 42, 43, 44, 45, 0, 0, 0, 0, - 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 48, 0, 0, 0, - 0, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 52, 0, 53, 0, 0, 0, 0, - 0, 0, 54, 55, 0, 0, 0, 0, 0, 56, 0, 57, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 58, 59, 0, 0, 0, 60, 0, 0, 61, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, - 0, 0, 0, 0, 63, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, - 0, 0, 0, 0, 66, 0, 0, 0, 0, 0, 0, 0, 67, 0, 68, 0, 0, 69, 0, 0, 0, 70, - 71, 72, 73, 74, 75, 76, 77, 0, 0, 0, 0, 0, 0, 78, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 81, 0, - 82, 83, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 84, 85, 86, 87, 88, 89, 0, 90, 91, 92, 0, 0, 0, 0, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 0, 131, 132, 133, 134, 0, 0, 0, - 0, 0, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 0, 146, 0, - 0, 0, 147, 0, 148, 149, 150, 0, 151, 152, 153, 0, 154, 0, 0, 0, 155, 0, - 0, 0, 156, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 166, 0, - 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 169, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 171, 0, 0, 0, 0, 0, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 0, 0, 187, 0, 0, 188, 189, 190, 191, 192, 0, - 193, 194, 195, 196, 197, 0, 198, 0, 0, 0, 199, 200, 201, 202, 203, 204, - 205, 0, 0, 0, 0, 0, 0, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 0, 0, - 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 0, 0, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 0, 284, 285, 286, 287, 288, - 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, - 303, 304, 305, 306, 0, 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, 315, - 0, 316, 0, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, - 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, - 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 0, - 347, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 350, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 351, 352, 0, 0, 0, 0, 353, 354, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378, - 379, 380, 381, 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, 392, - 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, - 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 431, 432, 433, 434, 435, 0, 436, 0, - 0, 437, 0, 0, 0, 0, 0, 0, 438, 439, 440, 441, 442, 443, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 444, 445, - 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, - 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, - 474, 475, 476, 477, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -}; - -static const unsigned short decomp_index2[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, - 3, 0, 6, 0, 0, 0, 0, 8, 0, 0, 11, 13, 15, 18, 0, 0, 20, 23, 25, 0, 27, - 31, 35, 0, 39, 42, 45, 48, 51, 54, 0, 57, 60, 63, 66, 69, 72, 75, 78, 81, - 0, 84, 87, 90, 93, 96, 99, 0, 0, 102, 105, 108, 111, 114, 0, 0, 117, 120, - 123, 126, 129, 132, 0, 135, 138, 141, 144, 147, 150, 153, 156, 159, 0, - 162, 165, 168, 171, 174, 177, 0, 0, 180, 183, 186, 189, 192, 0, 195, 198, - 201, 204, 207, 210, 213, 216, 219, 222, 225, 228, 231, 234, 237, 240, - 243, 0, 0, 246, 249, 252, 255, 258, 261, 264, 267, 270, 273, 276, 279, - 282, 285, 288, 291, 294, 297, 300, 303, 0, 0, 306, 309, 312, 315, 318, - 321, 324, 327, 330, 0, 333, 336, 339, 342, 345, 348, 0, 351, 354, 357, - 360, 363, 366, 369, 372, 0, 0, 375, 378, 381, 384, 387, 390, 393, 0, 0, - 396, 399, 402, 405, 408, 411, 0, 0, 414, 417, 420, 423, 426, 429, 432, - 435, 438, 441, 444, 447, 450, 453, 456, 459, 462, 465, 0, 0, 468, 471, - 474, 477, 480, 483, 486, 489, 492, 495, 498, 501, 504, 507, 510, 513, - 516, 519, 522, 525, 528, 531, 534, 537, 539, 542, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 545, 548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 551, 554, 557, 560, 563, 566, 569, 572, 575, 578, 581, 584, 587, - 590, 593, 596, 599, 602, 605, 608, 611, 614, 617, 620, 623, 0, 626, 629, - 632, 635, 638, 641, 0, 0, 644, 647, 650, 653, 656, 659, 662, 665, 668, - 671, 674, 677, 680, 683, 686, 689, 0, 0, 692, 695, 698, 701, 704, 707, - 710, 713, 716, 719, 722, 725, 728, 731, 734, 737, 740, 743, 746, 749, - 752, 755, 758, 761, 764, 767, 770, 773, 776, 779, 782, 785, 788, 791, - 794, 797, 0, 0, 800, 803, 0, 0, 0, 0, 0, 0, 806, 809, 812, 815, 818, 821, - 824, 827, 830, 833, 836, 839, 842, 845, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 848, 850, 852, 854, 856, 858, 860, 862, 864, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 866, 869, 872, 875, 878, 881, 0, 0, 884, 886, 888, - 890, 892, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 894, 896, 0, 898, 900, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 903, 0, 0, 0, 0, 0, 905, 0, 0, 0, - 908, 0, 0, 0, 0, 0, 910, 913, 916, 919, 921, 924, 927, 0, 930, 0, 933, - 936, 939, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 942, 945, 948, 951, 954, 957, 960, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 963, 966, 969, 972, 975, - 0, 978, 980, 982, 984, 987, 990, 992, 0, 0, 0, 0, 0, 0, 0, 0, 0, 994, - 996, 998, 0, 1000, 1002, 0, 0, 0, 1004, 0, 0, 0, 0, 0, 0, 1006, 1009, 0, - 1012, 0, 0, 0, 1015, 0, 0, 0, 0, 1018, 1021, 1024, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1027, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1030, 0, 0, - 0, 0, 0, 0, 1033, 1036, 0, 1039, 0, 0, 0, 1042, 0, 0, 0, 0, 1045, 1048, - 1051, 0, 0, 0, 0, 0, 0, 0, 1054, 1057, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1060, - 1063, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1066, 1069, 1072, 1075, 0, - 0, 1078, 1081, 0, 0, 1084, 1087, 1090, 1093, 1096, 1099, 0, 0, 1102, - 1105, 1108, 1111, 1114, 1117, 0, 0, 1120, 1123, 1126, 1129, 1132, 1135, - 1138, 1141, 1144, 1147, 1150, 1153, 0, 0, 1156, 1159, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1162, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1165, 1168, - 1171, 1174, 1177, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1180, 1183, - 1186, 1189, 0, 0, 0, 0, 0, 0, 0, 1192, 0, 1195, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1198, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1201, 0, 0, 0, 0, 0, 0, 0, 1204, 0, 0, 1207, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1210, 1213, 1216, - 1219, 1222, 1225, 1228, 1231, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1234, - 1237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1240, 1243, 0, 1246, - 0, 0, 0, 1249, 0, 0, 1252, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1255, 1258, 1261, 0, 0, 1264, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1267, - 0, 0, 1270, 1273, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1276, - 1279, 0, 0, 0, 0, 0, 0, 1282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1285, 1288, 1291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1294, 0, 0, 0, 0, 0, 0, 0, 1297, 0, 0, 0, 0, 0, 0, 1300, 1303, 0, 1306, - 1309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1312, 1315, 1318, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1321, 0, 1324, 1327, 1330, 0, 0, 0, 0, - 1333, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1336, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1339, 1342, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1345, 0, 0, 0, 0, 0, 0, 1347, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1350, 0, 0, 0, 0, 1353, 0, 0, 0, 0, 1356, 0, 0, - 0, 0, 1359, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1362, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1365, 0, 1368, 1371, 1374, 1377, 1380, 0, 0, 0, 0, 0, 0, 0, - 1383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1386, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1389, 0, 0, 0, 0, 1392, 0, 0, 0, 0, 1395, 0, 0, 0, 0, - 1398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1401, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1409, 0, 1412, 0, 1415, 0, - 1418, 0, 1421, 0, 0, 0, 1424, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1427, 0, 1430, 0, 0, 1433, 1436, 0, 1439, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1442, 1444, 1446, 0, 1448, 1450, 1452, 1454, 1456, 1458, 1460, 1462, - 1464, 1466, 1468, 0, 1470, 1472, 1474, 1476, 1478, 1480, 1482, 1484, - 1486, 1488, 1490, 1492, 1494, 1496, 1498, 1500, 1502, 1504, 0, 1506, - 1508, 1510, 1512, 1514, 1516, 1518, 1520, 1522, 1524, 1526, 1528, 1530, - 1532, 1534, 1536, 1538, 1540, 1542, 1544, 1546, 1548, 1550, 1552, 1554, - 1556, 1558, 1560, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1562, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1564, 1566, 1568, 1570, - 1572, 1574, 1576, 1578, 1580, 1582, 1584, 1586, 1588, 1590, 1592, 1594, - 1596, 1598, 1600, 1602, 1604, 1606, 1608, 1610, 1612, 1614, 1616, 1618, - 1620, 1622, 1624, 1626, 1628, 1630, 1632, 1634, 1636, 1638, 1641, 1644, - 1647, 1650, 1653, 1656, 1659, 1662, 1665, 1668, 1671, 1674, 1677, 1680, - 1683, 1686, 1689, 1692, 1695, 1698, 1701, 1704, 1707, 1710, 1713, 1716, - 1719, 1722, 1725, 1728, 1731, 1734, 1737, 1740, 1743, 1746, 1749, 1752, - 1755, 1758, 1761, 1764, 1767, 1770, 1773, 1776, 1779, 1782, 1785, 1788, - 1791, 1794, 1797, 1800, 1803, 1806, 1809, 1812, 1815, 1818, 1821, 1824, - 1827, 1830, 1833, 1836, 1839, 1842, 1845, 1848, 1851, 1854, 1857, 1860, - 1863, 1866, 1869, 1872, 1875, 1878, 1881, 1884, 1887, 1890, 1893, 1896, - 1899, 1902, 1905, 1908, 1911, 1914, 1917, 1920, 1923, 1926, 1929, 1932, - 1935, 1938, 1941, 1944, 1947, 1950, 1953, 1956, 1959, 1962, 1965, 1968, - 1971, 1974, 1977, 1980, 1983, 1986, 1989, 1992, 1995, 1998, 2001, 2004, - 2007, 2010, 2013, 2016, 2019, 2022, 2025, 2028, 2031, 2034, 2037, 2040, - 2043, 2046, 2049, 2052, 2055, 2058, 2061, 2064, 2067, 2070, 2073, 2076, - 2079, 2082, 2085, 2088, 2091, 2094, 2097, 2100, 2103, 0, 0, 0, 0, 2106, - 2109, 2112, 2115, 2118, 2121, 2124, 2127, 2130, 2133, 2136, 2139, 2142, - 2145, 2148, 2151, 2154, 2157, 2160, 2163, 2166, 2169, 2172, 2175, 2178, - 2181, 2184, 2187, 2190, 2193, 2196, 2199, 2202, 2205, 2208, 2211, 2214, - 2217, 2220, 2223, 2226, 2229, 2232, 2235, 2238, 2241, 2244, 2247, 2250, - 2253, 2256, 2259, 2262, 2265, 2268, 2271, 2274, 2277, 2280, 2283, 2286, - 2289, 2292, 2295, 2298, 2301, 2304, 2307, 2310, 2313, 2316, 2319, 2322, - 2325, 2328, 2331, 2334, 2337, 2340, 2343, 2346, 2349, 2352, 2355, 2358, - 2361, 2364, 2367, 2370, 2373, 0, 0, 0, 0, 0, 0, 2376, 2379, 2382, 2385, - 2388, 2391, 2394, 2397, 2400, 2403, 2406, 2409, 2412, 2415, 2418, 2421, - 2424, 2427, 2430, 2433, 2436, 2439, 0, 0, 2442, 2445, 2448, 2451, 2454, - 2457, 0, 0, 2460, 2463, 2466, 2469, 2472, 2475, 2478, 2481, 2484, 2487, - 2490, 2493, 2496, 2499, 2502, 2505, 2508, 2511, 2514, 2517, 2520, 2523, - 2526, 2529, 2532, 2535, 2538, 2541, 2544, 2547, 2550, 2553, 2556, 2559, - 2562, 2565, 2568, 2571, 0, 0, 2574, 2577, 2580, 2583, 2586, 2589, 0, 0, - 2592, 2595, 2598, 2601, 2604, 2607, 2610, 2613, 0, 2616, 0, 2619, 0, - 2622, 0, 2625, 2628, 2631, 2634, 2637, 2640, 2643, 2646, 2649, 2652, - 2655, 2658, 2661, 2664, 2667, 2670, 2673, 2676, 2679, 2681, 2684, 2686, - 2689, 2691, 2694, 2696, 2699, 2701, 2704, 2706, 2709, 0, 0, 2711, 2714, - 2717, 2720, 2723, 2726, 2729, 2732, 2735, 2738, 2741, 2744, 2747, 2750, - 2753, 2756, 2759, 2762, 2765, 2768, 2771, 2774, 2777, 2780, 2783, 2786, - 2789, 2792, 2795, 2798, 2801, 2804, 2807, 2810, 2813, 2816, 2819, 2822, - 2825, 2828, 2831, 2834, 2837, 2840, 2843, 2846, 2849, 2852, 2855, 2858, - 2861, 2864, 2867, 0, 2870, 2873, 2876, 2879, 2882, 2885, 2887, 2890, - 2893, 2895, 2898, 2901, 2904, 2907, 2910, 0, 2913, 2916, 2919, 2922, - 2924, 2927, 2929, 2932, 2935, 2938, 2941, 2944, 2947, 2950, 0, 0, 2952, - 2955, 2958, 2961, 2964, 2967, 0, 2969, 2972, 2975, 2978, 2981, 2984, - 2987, 2989, 2992, 2995, 2998, 3001, 3004, 3007, 3010, 3012, 3015, 3018, - 3020, 0, 0, 3022, 3025, 3028, 0, 3031, 3034, 3037, 3040, 3042, 3045, - 3047, 3050, 3052, 0, 3055, 3057, 3059, 3061, 3063, 3065, 3067, 3069, - 3071, 3073, 3075, 0, 0, 0, 0, 0, 0, 3077, 0, 0, 0, 0, 0, 3079, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 3082, 3084, 3087, 0, 0, 0, 0, 0, 0, 0, 0, - 3091, 0, 0, 0, 3093, 3096, 0, 3100, 3103, 0, 0, 0, 0, 3107, 0, 3110, 0, - 0, 0, 0, 0, 0, 0, 0, 3113, 3116, 3119, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 3122, 0, 0, 0, 0, 0, 0, 0, 3127, 3129, 3131, 0, 0, 3133, 3135, - 3137, 3139, 3141, 3143, 3145, 3147, 3149, 3151, 3153, 3155, 3157, 3159, - 3161, 3163, 3165, 3167, 3169, 3171, 3173, 3175, 3177, 3179, 3181, 3183, - 3185, 0, 3187, 3189, 3191, 3193, 3195, 3197, 3199, 3201, 3203, 3205, - 3207, 3209, 3211, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3213, 0, 0, 0, 0, 0, - 0, 0, 3216, 3220, 3224, 3226, 0, 3229, 3233, 3237, 0, 3239, 3242, 3244, - 3246, 3248, 3250, 3252, 3254, 3256, 3258, 3260, 0, 3262, 3264, 0, 0, - 3267, 3269, 3271, 3273, 3275, 0, 0, 3277, 3280, 3284, 0, 3287, 0, 3289, - 0, 3291, 0, 3293, 3295, 3297, 3299, 0, 3301, 3303, 3305, 0, 3307, 3309, - 3311, 3313, 3315, 3317, 3319, 0, 3321, 3325, 3327, 3329, 3331, 3333, 0, - 0, 0, 0, 3335, 3337, 3339, 3341, 3343, 0, 0, 0, 0, 0, 0, 3345, 3349, - 3353, 3358, 3362, 3366, 3370, 3374, 3378, 3382, 3386, 3390, 3394, 3398, - 3402, 3406, 3409, 3411, 3414, 3418, 3421, 3423, 3426, 3430, 3435, 3438, - 3440, 3443, 3447, 3449, 3451, 3453, 3455, 3457, 3460, 3464, 3467, 3469, - 3472, 3476, 3481, 3484, 3486, 3489, 3493, 3495, 3497, 3499, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 3501, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3505, 3508, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3511, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3514, 3517, 3520, 0, 0, 0, 0, - 3523, 0, 0, 0, 0, 3526, 0, 0, 3529, 0, 0, 0, 0, 0, 0, 0, 3532, 0, 3535, - 0, 0, 0, 0, 0, 3538, 3541, 0, 3545, 3548, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3552, 0, 0, 3555, 0, 0, 3558, 0, 3561, 0, 0, 0, 0, 0, - 0, 3564, 0, 3567, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3570, 3573, 3576, 3579, - 3582, 0, 0, 3585, 3588, 0, 0, 3591, 3594, 0, 0, 0, 0, 0, 0, 3597, 3600, - 0, 0, 3603, 3606, 0, 0, 3609, 3612, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 3615, 3618, 3621, 3624, 3627, 3630, 3633, 3636, 0, 0, - 0, 0, 0, 0, 3639, 3642, 3645, 3648, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 3651, 3653, 0, 0, 0, 0, 0, 3655, 3657, 3659, 3661, 3663, 3665, 3667, - 3669, 3671, 3673, 3676, 3679, 3682, 3685, 3688, 3691, 3694, 3697, 3700, - 3703, 3706, 3710, 3714, 3718, 3722, 3726, 3730, 3734, 3738, 3742, 3747, - 3752, 3757, 3762, 3767, 3772, 3777, 3782, 3787, 3792, 3797, 3800, 3803, - 3806, 3809, 3812, 3815, 3818, 3821, 3824, 3828, 3832, 3836, 3840, 3844, - 3848, 3852, 3856, 3860, 3864, 3868, 3872, 3876, 3880, 3884, 3888, 3892, - 3896, 3900, 3904, 3908, 3912, 3916, 3920, 3924, 3928, 3932, 3936, 3940, - 3944, 3948, 3952, 3956, 3960, 3964, 3968, 3972, 3974, 3976, 3978, 3980, - 3982, 3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004, - 4006, 4008, 4010, 4012, 4014, 4016, 4018, 4020, 4022, 4024, 4026, 4028, - 4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046, 4048, 4050, 4052, - 4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4078, 0, 0, 0, 0, 0, - 0, 0, 4083, 4087, 4090, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 4094, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4097, - 4099, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4101, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4103, 0, 0, 0, 4105, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 4107, 4109, 4111, 4113, 4115, 4117, 4119, 4121, - 4123, 4125, 4127, 4129, 4131, 4133, 4135, 4137, 4139, 4141, 4143, 4145, - 4147, 4149, 4151, 4153, 4155, 4157, 4159, 4161, 4163, 4165, 4167, 4169, - 4171, 4173, 4175, 4177, 4179, 4181, 4183, 4185, 4187, 4189, 4191, 4193, - 4195, 4197, 4199, 4201, 4203, 4205, 4207, 4209, 4211, 4213, 4215, 4217, - 4219, 4221, 4223, 4225, 4227, 4229, 4231, 4233, 4235, 4237, 4239, 4241, - 4243, 4245, 4247, 4249, 4251, 4253, 4255, 4257, 4259, 4261, 4263, 4265, - 4267, 4269, 4271, 4273, 4275, 4277, 4279, 4281, 4283, 4285, 4287, 4289, - 4291, 4293, 4295, 4297, 4299, 4301, 4303, 4305, 4307, 4309, 4311, 4313, - 4315, 4317, 4319, 4321, 4323, 4325, 4327, 4329, 4331, 4333, 4335, 4337, - 4339, 4341, 4343, 4345, 4347, 4349, 4351, 4353, 4355, 4357, 4359, 4361, - 4363, 4365, 4367, 4369, 4371, 4373, 4375, 4377, 4379, 4381, 4383, 4385, - 4387, 4389, 4391, 4393, 4395, 4397, 4399, 4401, 4403, 4405, 4407, 4409, - 4411, 4413, 4415, 4417, 4419, 4421, 4423, 4425, 4427, 4429, 4431, 4433, - 4435, 4437, 4439, 4441, 4443, 4445, 4447, 4449, 4451, 4453, 4455, 4457, - 4459, 4461, 4463, 4465, 4467, 4469, 4471, 4473, 4475, 4477, 4479, 4481, - 4483, 4485, 4487, 4489, 4491, 4493, 4495, 4497, 4499, 4501, 4503, 4505, - 4507, 4509, 4511, 4513, 4515, 4517, 4519, 4521, 4523, 4525, 4527, 4529, - 4531, 4533, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4535, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4537, 0, 4539, 4541, 4543, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4545, 0, 4548, 0, 4551, 0, - 4554, 0, 4557, 0, 4560, 0, 4563, 0, 4566, 0, 4569, 0, 4572, 0, 4575, 0, - 4578, 0, 0, 4581, 0, 4584, 0, 4587, 0, 0, 0, 0, 0, 0, 4590, 4593, 0, - 4596, 4599, 0, 4602, 4605, 0, 4608, 4611, 0, 4614, 4617, 0, 0, 0, 0, 0, - 0, 4620, 0, 0, 0, 0, 0, 0, 4623, 4626, 0, 4629, 4632, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 4635, 0, 4638, 0, 4641, 0, 4644, 0, 4647, 0, 4650, 0, - 4653, 0, 4656, 0, 4659, 0, 4662, 0, 4665, 0, 4668, 0, 0, 4671, 0, 4674, - 0, 4677, 0, 0, 0, 0, 0, 0, 4680, 4683, 0, 4686, 4689, 0, 4692, 4695, 0, - 4698, 4701, 0, 4704, 4707, 0, 0, 0, 0, 0, 0, 4710, 0, 0, 4713, 4716, - 4719, 4722, 0, 0, 0, 4725, 4728, 0, 4731, 4733, 4735, 4737, 4739, 4741, - 4743, 4745, 4747, 4749, 4751, 4753, 4755, 4757, 4759, 4761, 4763, 4765, - 4767, 4769, 4771, 4773, 4775, 4777, 4779, 4781, 4783, 4785, 4787, 4789, - 4791, 4793, 4795, 4797, 4799, 4801, 4803, 4805, 4807, 4809, 4811, 4813, - 4815, 4817, 4819, 4821, 4823, 4825, 4827, 4829, 4831, 4833, 4835, 4837, - 4839, 4841, 4843, 4845, 4847, 4849, 4851, 4853, 4855, 4857, 4859, 4861, - 4863, 4865, 4867, 4869, 4871, 4873, 4875, 4877, 4879, 4881, 4883, 4885, - 4887, 4889, 4891, 4893, 4895, 4897, 4899, 4901, 4903, 4905, 4907, 4909, - 4911, 4913, 4915, 4917, 0, 0, 0, 4919, 4921, 4923, 4925, 4927, 4929, - 4931, 4933, 4935, 4937, 4939, 4941, 4943, 4945, 4947, 4951, 4955, 4959, - 4963, 4967, 4971, 4975, 4979, 4983, 4987, 4991, 4995, 4999, 5003, 5008, - 5013, 5018, 5023, 5028, 5033, 5038, 5043, 5048, 5053, 5058, 5063, 5068, - 5073, 5078, 5086, 0, 5093, 5097, 5101, 5105, 5109, 5113, 5117, 5121, - 5125, 5129, 5133, 5137, 5141, 5145, 5149, 5153, 5157, 5161, 5165, 5169, - 5173, 5177, 5181, 5185, 5189, 5193, 5197, 5201, 5205, 5209, 5213, 5217, - 5221, 5225, 5229, 5233, 5237, 5239, 5241, 5243, 0, 0, 0, 0, 0, 0, 0, 0, - 5245, 5249, 5252, 5255, 5258, 5261, 5264, 5267, 5270, 5273, 5276, 5279, - 5282, 5285, 5288, 5291, 5294, 5296, 5298, 5300, 5302, 5304, 5306, 5308, - 5310, 5312, 5314, 5316, 5318, 5320, 5322, 5325, 5328, 5331, 5334, 5337, - 5340, 5343, 5346, 5349, 5352, 5355, 5358, 5361, 5364, 5370, 5375, 0, - 5378, 5380, 5382, 5384, 5386, 5388, 5390, 5392, 5394, 5396, 5398, 5400, - 5402, 5404, 5406, 5408, 5410, 5412, 5414, 5416, 5418, 5420, 5422, 5424, - 5426, 5428, 5430, 5432, 5434, 5436, 5438, 5440, 5442, 5444, 5446, 5448, - 5450, 5452, 5454, 5456, 5458, 5460, 5462, 5464, 5466, 5468, 5470, 5472, - 5474, 5476, 5479, 5482, 5485, 5488, 5491, 5494, 5497, 5500, 5503, 5506, - 5509, 5512, 5515, 5518, 5521, 5524, 5527, 5530, 5533, 5536, 5539, 5542, - 5545, 5548, 5552, 5556, 5560, 5563, 5567, 5570, 5574, 5576, 5578, 5580, - 5582, 5584, 5586, 5588, 5590, 5592, 5594, 5596, 5598, 5600, 5602, 5604, - 5606, 5608, 5610, 5612, 5614, 5616, 5618, 5620, 5622, 5624, 5626, 5628, - 5630, 5632, 5634, 5636, 5638, 5640, 5642, 5644, 5646, 5648, 5650, 5652, - 5654, 5656, 5658, 5660, 5662, 5664, 5666, 0, 5668, 5673, 5678, 5683, - 5687, 5692, 5696, 5700, 5706, 5711, 5715, 5719, 5723, 5728, 5733, 5737, - 5741, 5744, 5748, 5753, 5758, 5761, 5767, 5774, 5780, 5784, 5790, 5796, - 5801, 5805, 5809, 5813, 5818, 5824, 5829, 5833, 5837, 5841, 5844, 5847, - 5850, 5853, 5857, 5861, 5867, 5871, 5876, 5882, 5886, 5889, 5892, 5898, - 5903, 5909, 5913, 5919, 5922, 5926, 5930, 5934, 5938, 5942, 5947, 5951, - 5954, 5958, 5962, 5966, 5971, 5975, 5979, 5983, 5989, 5994, 5997, 6003, - 6006, 6011, 6016, 6020, 6024, 6028, 6033, 6036, 6040, 6045, 6048, 6054, - 6058, 6061, 6064, 6067, 6070, 6073, 6076, 6079, 6082, 6085, 6088, 6092, - 6096, 6100, 6104, 6108, 6112, 6116, 6120, 6124, 6128, 6132, 6136, 6140, - 6144, 6148, 6152, 6155, 6158, 6162, 6165, 6168, 6171, 6175, 6179, 6182, - 6185, 6188, 6191, 6194, 6199, 6202, 6205, 6208, 6211, 6214, 6217, 6220, - 6223, 6227, 6232, 6235, 6238, 6241, 6244, 6247, 6250, 6253, 6257, 6261, - 6265, 6269, 6272, 6275, 6278, 6281, 6284, 6287, 6290, 6293, 6296, 6299, - 6303, 6307, 6310, 6314, 6318, 6322, 6325, 6329, 6333, 6338, 6341, 6345, - 6349, 6353, 6357, 6363, 6370, 6373, 6376, 6379, 6382, 6385, 6388, 6391, - 6394, 6397, 6400, 6403, 6406, 6409, 6412, 6415, 6418, 6421, 6424, 6429, - 6432, 6435, 6438, 6443, 6447, 6450, 6453, 6456, 6459, 6462, 6465, 6468, - 6471, 6474, 6477, 6481, 6484, 6487, 6491, 6495, 6498, 6503, 6507, 6510, - 6513, 6516, 6519, 6523, 6527, 6530, 6533, 6536, 6539, 6542, 6545, 6548, - 6551, 6554, 6558, 6562, 6566, 6570, 6574, 6578, 6582, 6586, 6590, 6594, - 6598, 6602, 6606, 6610, 6614, 6618, 6622, 6626, 6630, 6634, 6638, 6642, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6646, 6648, 0, 0, 6650, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6652, 6654, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6656, 6658, 6660, - 6662, 6664, 6666, 6668, 6670, 6672, 6674, 6676, 6678, 6680, 6682, 6684, - 6686, 6688, 6690, 6692, 6694, 6696, 6698, 6700, 6702, 6704, 6706, 6708, - 6710, 6712, 6714, 6716, 6718, 6720, 6722, 6724, 6726, 6728, 6730, 6732, - 6734, 6736, 6738, 6740, 6742, 6744, 6746, 6748, 6750, 6752, 6754, 6756, - 6758, 6760, 6762, 6764, 6766, 6768, 6770, 6772, 6774, 6776, 6778, 6780, - 6782, 6784, 6786, 6788, 6790, 6792, 6794, 6796, 6798, 6800, 6802, 6804, - 6806, 6808, 6810, 6812, 6814, 6816, 6818, 6820, 6822, 6824, 6826, 6828, - 6830, 6832, 6834, 6836, 6838, 6840, 6842, 6844, 6846, 6848, 6850, 6852, - 6854, 6856, 6858, 6860, 6862, 6864, 6866, 6868, 6870, 6872, 6874, 6876, - 6878, 6880, 6882, 6884, 6886, 6888, 6890, 6892, 6894, 6896, 6898, 6900, - 6902, 6904, 6906, 6908, 6910, 6912, 6914, 6916, 6918, 6920, 6922, 6924, - 6926, 6928, 6930, 6932, 6934, 6936, 6938, 6940, 6942, 6944, 6946, 6948, - 6950, 6952, 6954, 6956, 6958, 6960, 6962, 6964, 6966, 6968, 6970, 6972, - 6974, 6976, 6978, 6980, 6982, 6984, 6986, 6988, 6990, 6992, 6994, 6996, - 6998, 7000, 7002, 7004, 7006, 7008, 7010, 7012, 7014, 7016, 7018, 7020, - 7022, 7024, 7026, 7028, 7030, 7032, 7034, 7036, 7038, 7040, 7042, 7044, - 7046, 7048, 7050, 7052, 7054, 7056, 7058, 7060, 7062, 7064, 7066, 7068, - 7070, 7072, 7074, 7076, 7078, 7080, 7082, 7084, 7086, 7088, 7090, 7092, - 7094, 7096, 7098, 7100, 7102, 7104, 7106, 7108, 7110, 7112, 7114, 7116, - 7118, 7120, 7122, 7124, 7126, 7128, 7130, 7132, 7134, 7136, 7138, 7140, - 7142, 7144, 7146, 7148, 7150, 7152, 7154, 7156, 7158, 7160, 7162, 7164, - 7166, 7168, 7170, 7172, 7174, 7176, 7178, 7180, 7182, 7184, 7186, 7188, - 7190, 7192, 7194, 7196, 7198, 7200, 7202, 0, 0, 7204, 0, 7206, 0, 0, - 7208, 7210, 7212, 7214, 7216, 7218, 7220, 7222, 7224, 7226, 0, 7228, 0, - 7230, 0, 0, 7232, 7234, 0, 0, 0, 7236, 7238, 7240, 7242, 7244, 7246, - 7248, 7250, 7252, 7254, 7256, 7258, 7260, 7262, 7264, 7266, 7268, 7270, - 7272, 7274, 7276, 7278, 7280, 7282, 7284, 7286, 7288, 7290, 7292, 7294, - 7296, 7298, 7300, 7302, 7304, 7306, 7308, 7310, 7312, 7314, 7316, 7318, - 7320, 7322, 7324, 7326, 7328, 7330, 7332, 7334, 7336, 7338, 7340, 7342, - 7344, 7346, 7348, 7350, 7352, 7354, 7356, 7358, 7360, 7362, 7364, 7366, - 7368, 7371, 0, 0, 7373, 7375, 7377, 7379, 7381, 7383, 7385, 7387, 7389, - 7391, 7393, 7395, 7397, 7399, 7401, 7403, 7405, 7407, 7409, 7411, 7413, - 7415, 7417, 7419, 7421, 7423, 7425, 7427, 7429, 7431, 7433, 7435, 7437, - 7439, 7441, 7443, 7445, 7447, 7449, 7451, 7453, 7455, 7457, 7459, 7461, - 7463, 7465, 7467, 7469, 7471, 7473, 7475, 7477, 7479, 7481, 7483, 7485, - 7487, 7489, 7491, 7493, 7495, 7497, 7499, 7501, 7503, 7505, 7507, 7509, - 7511, 7513, 7515, 7517, 7519, 7521, 7523, 7525, 7527, 7529, 7531, 7533, - 7535, 7537, 7539, 7541, 7543, 7545, 7547, 7549, 7551, 7553, 7555, 7557, - 7559, 7561, 7563, 7566, 7569, 7572, 7574, 7576, 7578, 7581, 7584, 7587, - 7589, 0, 0, 0, 0, 0, 0, 7591, 7594, 7597, 7600, 7604, 7608, 7611, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7614, 7617, 7620, 7623, 7626, 0, 0, 0, 0, - 0, 7629, 0, 7632, 7635, 7637, 7639, 7641, 7643, 7645, 7647, 7649, 7651, - 7653, 7655, 7658, 7661, 7664, 7667, 7670, 7673, 7676, 7679, 7682, 7685, - 7688, 7691, 0, 7694, 7697, 7700, 7703, 7706, 0, 7709, 0, 7712, 7715, 0, - 7718, 7721, 0, 7724, 7727, 7730, 7733, 7736, 7739, 7742, 7745, 7748, - 7751, 7754, 7756, 7758, 7760, 7762, 7764, 7766, 7768, 7770, 7772, 7774, - 7776, 7778, 7780, 7782, 7784, 7786, 7788, 7790, 7792, 7794, 7796, 7798, - 7800, 7802, 7804, 7806, 7808, 7810, 7812, 7814, 7816, 7818, 7820, 7822, - 7824, 7826, 7828, 7830, 7832, 7834, 7836, 7838, 7840, 7842, 7844, 7846, - 7848, 7850, 7852, 7854, 7856, 7858, 7860, 7862, 7864, 7866, 7868, 7870, - 7872, 7874, 7876, 7878, 7880, 7882, 7884, 7886, 7888, 7890, 7892, 7894, - 7896, 7898, 7900, 7902, 7904, 7906, 7908, 7910, 7912, 7914, 7916, 7918, - 7920, 7922, 7924, 7926, 7928, 7930, 7932, 7934, 7936, 7938, 7940, 7942, - 7944, 7946, 7948, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 7950, 7952, 7954, 7956, 7958, 7960, 7962, 7964, 7966, 7968, 7970, 7972, - 7974, 7976, 7978, 7980, 7982, 7984, 7986, 7988, 7990, 7992, 7994, 7996, - 7999, 8002, 8005, 8008, 8011, 8014, 8017, 8020, 8023, 8026, 8029, 8032, - 8035, 8038, 8041, 8044, 8047, 8050, 8052, 8054, 8056, 8058, 8061, 8064, - 8067, 8070, 8073, 8076, 8079, 8082, 8085, 8088, 8091, 8094, 8097, 8100, - 8103, 8106, 8109, 8112, 8115, 8118, 8121, 8124, 8127, 8130, 8133, 8136, - 8139, 8142, 8145, 8148, 8151, 8154, 8157, 8160, 8163, 8166, 8169, 8172, - 8175, 8178, 8181, 8184, 8187, 8190, 8193, 8196, 8199, 8202, 8205, 8208, - 8211, 8214, 8217, 8220, 8223, 8226, 8229, 8232, 8235, 8238, 8241, 8244, - 8247, 8250, 8253, 8256, 8259, 8262, 8265, 8268, 8271, 8274, 8277, 8280, - 8283, 8286, 8289, 8292, 8295, 8298, 8301, 8304, 8307, 8310, 8313, 8316, - 8319, 8322, 8325, 8328, 8331, 8334, 8337, 8340, 8344, 8348, 8352, 8356, - 8360, 8364, 8367, 8370, 8373, 8376, 8379, 8382, 8385, 8388, 8391, 8394, - 8397, 8400, 8403, 8406, 8409, 8412, 8415, 8418, 8421, 8424, 8427, 8430, - 8433, 8436, 8439, 8442, 8445, 8448, 8451, 8454, 8457, 8460, 8463, 8466, - 8469, 8472, 8475, 8478, 8481, 8484, 8487, 8490, 8493, 8496, 8499, 8502, - 8505, 8508, 8511, 8514, 8517, 8520, 8523, 8526, 8529, 8532, 8535, 8538, - 8541, 8544, 8547, 8550, 8553, 8556, 8559, 8562, 8565, 8568, 8571, 8574, - 8577, 8580, 8583, 8586, 8589, 8592, 8595, 8598, 8601, 8604, 8607, 8610, - 8613, 8616, 8619, 8622, 8625, 8628, 8631, 8634, 8637, 8640, 8643, 8646, - 8649, 8652, 8655, 8658, 8661, 8664, 8667, 8670, 8673, 8676, 8679, 8682, - 8685, 8688, 8691, 8694, 8697, 8700, 8703, 8706, 8709, 8712, 8715, 8718, - 8721, 8724, 8727, 8730, 8733, 8736, 8739, 8742, 8745, 8748, 8751, 8754, - 8757, 8760, 8763, 8766, 8769, 8772, 8775, 8778, 8781, 8784, 8787, 8790, - 8794, 8798, 8802, 8805, 8808, 8811, 8814, 8817, 8820, 8823, 8826, 8829, - 8832, 8835, 8838, 8841, 8844, 8847, 8850, 8853, 8856, 8859, 8862, 8865, - 8868, 8871, 8874, 8877, 8880, 8883, 8886, 8889, 8892, 8895, 8898, 8901, - 8904, 8907, 8910, 8913, 8916, 8919, 8922, 8925, 8928, 8931, 8934, 8937, - 8940, 8943, 8946, 8949, 8952, 8955, 8958, 8961, 8964, 8967, 8970, 8973, - 8976, 8979, 8982, 8985, 8988, 8991, 8994, 8997, 9000, 9003, 9006, 9009, - 9012, 9015, 9018, 0, 0, 9021, 9025, 9029, 9033, 9037, 9041, 9045, 9049, - 9053, 9057, 9061, 9065, 9069, 9073, 9077, 9081, 9085, 9089, 9093, 9097, - 9101, 9105, 9109, 9113, 9117, 9121, 9125, 9129, 9133, 9137, 9141, 9145, - 9149, 9153, 9157, 9161, 9165, 9169, 9173, 9177, 9181, 9185, 9189, 9193, - 9197, 9201, 9205, 9209, 9213, 9217, 9221, 9225, 9229, 9233, 9237, 9241, - 9245, 9249, 9253, 9257, 9261, 9265, 9269, 9273, 0, 0, 9277, 9281, 9285, - 9289, 9293, 9297, 9301, 9305, 9309, 9313, 9317, 9321, 9325, 9329, 9333, - 9337, 9341, 9345, 9349, 9353, 9357, 9361, 9365, 9369, 9373, 9377, 9381, - 9385, 9389, 9393, 9397, 9401, 9405, 9409, 9413, 9417, 9421, 9425, 9429, - 9433, 9437, 9441, 9445, 9449, 9453, 9457, 9461, 9465, 9469, 9473, 9477, - 9481, 9485, 9489, 0, 0, 0, 0, 0, 0, 0, 0, 9493, 9497, 9501, 9506, 9511, - 9516, 9521, 9526, 9531, 9536, 9540, 9559, 9568, 0, 0, 0, 9573, 9575, - 9577, 9579, 9581, 9583, 9585, 9587, 9589, 9591, 0, 0, 0, 0, 0, 0, 9593, - 9595, 9597, 9599, 9601, 9603, 9605, 9607, 9609, 9611, 9613, 9615, 9617, - 9619, 9621, 9623, 9625, 9627, 9629, 9631, 9633, 0, 0, 9635, 9637, 9639, - 9641, 9643, 9645, 9647, 9649, 9651, 9653, 9655, 9657, 0, 9659, 9661, - 9663, 9665, 9667, 9669, 9671, 9673, 9675, 9677, 9679, 9681, 9683, 9685, - 9687, 9689, 9691, 9693, 9695, 0, 9697, 9699, 9701, 9703, 0, 0, 0, 0, - 9705, 9708, 9711, 0, 9714, 0, 9717, 9720, 9723, 9726, 9729, 9732, 9735, - 9738, 9741, 9744, 9747, 9749, 9751, 9753, 9755, 9757, 9759, 9761, 9763, - 9765, 9767, 9769, 9771, 9773, 9775, 9777, 9779, 9781, 9783, 9785, 9787, - 9789, 9791, 9793, 9795, 9797, 9799, 9801, 9803, 9805, 9807, 9809, 9811, - 9813, 9815, 9817, 9819, 9821, 9823, 9825, 9827, 9829, 9831, 9833, 9835, - 9837, 9839, 9841, 9843, 9845, 9847, 9849, 9851, 9853, 9855, 9857, 9859, - 9861, 9863, 9865, 9867, 9869, 9871, 9873, 9875, 9877, 9879, 9881, 9883, - 9885, 9887, 9889, 9891, 9893, 9895, 9897, 9899, 9901, 9903, 9905, 9907, - 9909, 9911, 9913, 9915, 9917, 9919, 9921, 9923, 9925, 9927, 9929, 9931, - 9933, 9935, 9937, 9939, 9941, 9943, 9945, 9947, 9949, 9951, 9953, 9955, - 9957, 9959, 9961, 9963, 9965, 9967, 9969, 9971, 9973, 9975, 9977, 9979, - 9981, 9984, 9987, 9990, 9993, 9996, 9999, 10002, 0, 0, 0, 0, 10005, - 10007, 10009, 10011, 10013, 10015, 10017, 10019, 10021, 10023, 10025, - 10027, 10029, 10031, 10033, 10035, 10037, 10039, 10041, 10043, 10045, - 10047, 10049, 10051, 10053, 10055, 10057, 10059, 10061, 10063, 10065, - 10067, 10069, 10071, 10073, 10075, 10077, 10079, 10081, 10083, 10085, - 10087, 10089, 10091, 10093, 10095, 10097, 10099, 10101, 10103, 10105, - 10107, 10109, 10111, 10113, 10115, 10117, 10119, 10121, 10123, 10125, - 10127, 10129, 10131, 10133, 10135, 10137, 10139, 10141, 10143, 10145, - 10147, 10149, 10151, 10153, 10155, 10157, 10159, 10161, 10163, 10165, - 10167, 10169, 10171, 10173, 10175, 10177, 10179, 10181, 10183, 10185, - 10187, 10189, 10191, 10193, 10195, 10197, 10199, 10201, 10203, 10205, - 10207, 10209, 10211, 10213, 10215, 10217, 10219, 10221, 10223, 10225, - 10227, 10229, 10231, 10233, 10235, 10237, 10239, 10241, 10243, 10245, - 10247, 10249, 10251, 10253, 10255, 10257, 10259, 10261, 10263, 10265, - 10267, 10269, 10271, 10273, 10275, 10277, 10279, 10281, 10283, 10285, - 10287, 10289, 10291, 10293, 10295, 10297, 10299, 10301, 10303, 10305, - 10307, 10309, 10311, 10313, 10315, 10317, 10319, 10321, 10323, 10325, - 10327, 10329, 10331, 10333, 10335, 10337, 10339, 10341, 10343, 10345, - 10347, 10349, 10351, 10353, 10355, 10357, 10359, 10361, 10363, 10365, - 10367, 10369, 10371, 10373, 10375, 10377, 10379, 10381, 10383, 0, 0, 0, - 10385, 10387, 10389, 10391, 10393, 10395, 0, 0, 10397, 10399, 10401, - 10403, 10405, 10407, 0, 0, 10409, 10411, 10413, 10415, 10417, 10419, 0, - 0, 10421, 10423, 10425, 0, 0, 0, 10427, 10429, 10431, 10433, 10435, - 10437, 10439, 0, 10441, 10443, 10445, 10447, 10449, 10451, 10453, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 10455, 0, 10460, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 10465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 10470, 10475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10480, 10485, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10490, 10495, 0, 10500, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 10505, 10510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 10515, 10520, 10525, 10530, 10535, 10540, 10545, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10550, 10555, 10560, - 10565, 10570, 10575, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10580, - 10582, 10584, 10586, 10588, 10590, 10592, 10594, 10596, 10598, 10600, - 10602, 10604, 10606, 10608, 10610, 10612, 10614, 10616, 10618, 10620, - 10622, 10624, 10626, 10628, 10630, 10632, 10634, 10636, 10638, 10640, - 10642, 10644, 10646, 10648, 10650, 10652, 10654, 10656, 10658, 10660, - 10662, 10664, 10666, 10668, 10670, 10672, 10674, 10676, 10678, 10680, - 10682, 10684, 10686, 10688, 10690, 10692, 10694, 10696, 10698, 10700, - 10702, 10704, 10706, 10708, 10710, 10712, 10714, 10716, 10718, 10720, - 10722, 10724, 10726, 10728, 10730, 10732, 10734, 10736, 10738, 10740, - 10742, 10744, 10746, 10748, 0, 10750, 10752, 10754, 10756, 10758, 10760, - 10762, 10764, 10766, 10768, 10770, 10772, 10774, 10776, 10778, 10780, - 10782, 10784, 10786, 10788, 10790, 10792, 10794, 10796, 10798, 10800, - 10802, 10804, 10806, 10808, 10810, 10812, 10814, 10816, 10818, 10820, - 10822, 10824, 10826, 10828, 10830, 10832, 10834, 10836, 10838, 10840, - 10842, 10844, 10846, 10848, 10850, 10852, 10854, 10856, 10858, 10860, - 10862, 10864, 10866, 10868, 10870, 10872, 10874, 10876, 10878, 10880, - 10882, 10884, 10886, 10888, 10890, 0, 10892, 10894, 0, 0, 10896, 0, 0, - 10898, 10900, 0, 0, 10902, 10904, 10906, 10908, 0, 10910, 10912, 10914, - 10916, 10918, 10920, 10922, 10924, 10926, 10928, 10930, 10932, 0, 10934, - 0, 10936, 10938, 10940, 10942, 10944, 10946, 10948, 0, 10950, 10952, - 10954, 10956, 10958, 10960, 10962, 10964, 10966, 10968, 10970, 10972, - 10974, 10976, 10978, 10980, 10982, 10984, 10986, 10988, 10990, 10992, - 10994, 10996, 10998, 11000, 11002, 11004, 11006, 11008, 11010, 11012, - 11014, 11016, 11018, 11020, 11022, 11024, 11026, 11028, 11030, 11032, - 11034, 11036, 11038, 11040, 11042, 11044, 11046, 11048, 11050, 11052, - 11054, 11056, 11058, 11060, 11062, 11064, 11066, 11068, 11070, 11072, - 11074, 11076, 11078, 0, 11080, 11082, 11084, 11086, 0, 0, 11088, 11090, - 11092, 11094, 11096, 11098, 11100, 11102, 0, 11104, 11106, 11108, 11110, - 11112, 11114, 11116, 0, 11118, 11120, 11122, 11124, 11126, 11128, 11130, - 11132, 11134, 11136, 11138, 11140, 11142, 11144, 11146, 11148, 11150, - 11152, 11154, 11156, 11158, 11160, 11162, 11164, 11166, 11168, 11170, - 11172, 0, 11174, 11176, 11178, 11180, 0, 11182, 11184, 11186, 11188, - 11190, 0, 11192, 0, 0, 0, 11194, 11196, 11198, 11200, 11202, 11204, - 11206, 0, 11208, 11210, 11212, 11214, 11216, 11218, 11220, 11222, 11224, - 11226, 11228, 11230, 11232, 11234, 11236, 11238, 11240, 11242, 11244, - 11246, 11248, 11250, 11252, 11254, 11256, 11258, 11260, 11262, 11264, - 11266, 11268, 11270, 11272, 11274, 11276, 11278, 11280, 11282, 11284, - 11286, 11288, 11290, 11292, 11294, 11296, 11298, 11300, 11302, 11304, - 11306, 11308, 11310, 11312, 11314, 11316, 11318, 11320, 11322, 11324, - 11326, 11328, 11330, 11332, 11334, 11336, 11338, 11340, 11342, 11344, - 11346, 11348, 11350, 11352, 11354, 11356, 11358, 11360, 11362, 11364, - 11366, 11368, 11370, 11372, 11374, 11376, 11378, 11380, 11382, 11384, - 11386, 11388, 11390, 11392, 11394, 11396, 11398, 11400, 11402, 11404, - 11406, 11408, 11410, 11412, 11414, 11416, 11418, 11420, 11422, 11424, - 11426, 11428, 11430, 11432, 11434, 11436, 11438, 11440, 11442, 11444, - 11446, 11448, 11450, 11452, 11454, 11456, 11458, 11460, 11462, 11464, - 11466, 11468, 11470, 11472, 11474, 11476, 11478, 11480, 11482, 11484, - 11486, 11488, 11490, 11492, 11494, 11496, 11498, 11500, 11502, 11504, - 11506, 11508, 11510, 11512, 11514, 11516, 11518, 11520, 11522, 11524, - 11526, 11528, 11530, 11532, 11534, 11536, 11538, 11540, 11542, 11544, - 11546, 11548, 11550, 11552, 11554, 11556, 11558, 11560, 11562, 11564, - 11566, 11568, 11570, 11572, 11574, 11576, 11578, 11580, 11582, 11584, - 11586, 11588, 11590, 11592, 11594, 11596, 11598, 11600, 11602, 11604, - 11606, 11608, 11610, 11612, 11614, 11616, 11618, 11620, 11622, 11624, - 11626, 11628, 11630, 11632, 11634, 11636, 11638, 11640, 11642, 11644, - 11646, 11648, 11650, 11652, 11654, 11656, 11658, 11660, 11662, 11664, - 11666, 11668, 11670, 11672, 11674, 11676, 11678, 11680, 11682, 11684, - 11686, 11688, 11690, 11692, 11694, 11696, 11698, 11700, 11702, 11704, - 11706, 11708, 11710, 11712, 11714, 11716, 11718, 11720, 11722, 11724, - 11726, 11728, 11730, 11732, 11734, 11736, 11738, 11740, 11742, 11744, - 11746, 11748, 11750, 11752, 11754, 11756, 11758, 11760, 11762, 11764, - 11766, 11768, 11770, 11772, 11774, 11776, 11778, 11780, 11782, 11784, - 11786, 11788, 11790, 11792, 11794, 11796, 11798, 11800, 11802, 11804, - 11806, 11808, 11810, 11812, 11814, 11816, 11818, 11820, 11822, 11824, - 11826, 11828, 11830, 11832, 11834, 11836, 11838, 11840, 11842, 11844, - 11846, 11848, 11850, 11852, 11854, 11856, 11858, 11860, 11862, 11864, - 11866, 11868, 11870, 11872, 11874, 11876, 11878, 11880, 11882, 11884, - 11886, 0, 0, 11888, 11890, 11892, 11894, 11896, 11898, 11900, 11902, - 11904, 11906, 11908, 11910, 11912, 11914, 11916, 11918, 11920, 11922, - 11924, 11926, 11928, 11930, 11932, 11934, 11936, 11938, 11940, 11942, - 11944, 11946, 11948, 11950, 11952, 11954, 11956, 11958, 11960, 11962, - 11964, 11966, 11968, 11970, 11972, 11974, 11976, 11978, 11980, 11982, - 11984, 11986, 11988, 11990, 11992, 11994, 11996, 11998, 12000, 12002, - 12004, 12006, 12008, 12010, 12012, 12014, 12016, 12018, 12020, 12022, - 12024, 12026, 12028, 12030, 12032, 12034, 12036, 12038, 12040, 12042, - 12044, 12046, 12048, 12050, 12052, 12054, 12056, 12058, 12060, 12062, - 12064, 12066, 12068, 12070, 12072, 12074, 12076, 12078, 12080, 12082, - 12084, 12086, 12088, 12090, 12092, 12094, 12096, 12098, 12100, 12102, - 12104, 12106, 12108, 12110, 12112, 12114, 12116, 12118, 12120, 12122, - 12124, 12126, 12128, 12130, 12132, 12134, 12136, 12138, 12140, 12142, - 12144, 12146, 12148, 12150, 12152, 12154, 12156, 12158, 12160, 12162, - 12164, 12166, 12168, 12170, 12172, 12174, 12176, 12178, 12180, 12182, - 12184, 12186, 12188, 12190, 12192, 12194, 12196, 12198, 12200, 12202, - 12204, 12206, 12208, 12210, 12212, 12214, 12216, 12218, 12220, 12222, - 12224, 12226, 12228, 12230, 12232, 12234, 12236, 12238, 12240, 12242, - 12244, 12246, 12248, 12250, 12252, 12254, 12256, 12258, 12260, 12262, - 12264, 12266, 12268, 12270, 12272, 12274, 12276, 12278, 12280, 12282, - 12284, 12286, 12288, 12290, 12292, 12294, 12296, 12298, 12300, 12302, - 12304, 12306, 12308, 12310, 12312, 12314, 12316, 12318, 12320, 12322, - 12324, 12326, 12328, 12330, 12332, 12334, 12336, 12338, 12340, 12342, - 12344, 12346, 12348, 12350, 12352, 12354, 12356, 12358, 12360, 12362, - 12364, 12366, 12368, 12370, 12372, 12374, 12376, 12378, 12380, 12382, - 12384, 12386, 12388, 12390, 12392, 12394, 12396, 12398, 12400, 12402, - 12404, 12406, 12408, 12410, 12412, 12414, 12416, 12418, 12420, 12422, - 12424, 12426, 12428, 12430, 12432, 12434, 12436, 12438, 12440, 12442, - 12444, 12446, 12448, 12450, 12452, 12454, 12456, 12458, 12460, 12462, - 12464, 12466, 12468, 12470, 0, 0, 12472, 12474, 12476, 12478, 12480, - 12482, 12484, 12486, 12488, 12490, 12492, 12494, 12496, 12498, 12500, - 12502, 12504, 12506, 12508, 12510, 12512, 12514, 12516, 12518, 12520, - 12522, 12524, 12526, 12528, 12530, 12532, 12534, 12536, 12538, 12540, - 12542, 12544, 12546, 12548, 12550, 12552, 12554, 12556, 12558, 12560, - 12562, 12564, 12566, 12568, 12570, 12572, 12574, 12576, 12578, 0, 12580, - 12582, 12584, 12586, 12588, 12590, 12592, 12594, 12596, 12598, 12600, - 12602, 12604, 12606, 12608, 12610, 12612, 12614, 12616, 12618, 12620, - 12622, 12624, 12626, 12628, 12630, 12632, 0, 12634, 12636, 0, 12638, 0, - 0, 12640, 0, 12642, 12644, 12646, 12648, 12650, 12652, 12654, 12656, - 12658, 12660, 0, 12662, 12664, 12666, 12668, 0, 12670, 0, 12672, 0, 0, 0, - 0, 0, 0, 12674, 0, 0, 0, 0, 12676, 0, 12678, 0, 12680, 0, 12682, 12684, - 12686, 0, 12688, 12690, 0, 12692, 0, 0, 12694, 0, 12696, 0, 12698, 0, - 12700, 0, 12702, 0, 12704, 12706, 0, 12708, 0, 0, 12710, 12712, 12714, - 12716, 0, 12718, 12720, 12722, 12724, 12726, 12728, 12730, 0, 12732, - 12734, 12736, 12738, 0, 12740, 12742, 12744, 12746, 0, 12748, 0, 12750, - 12752, 12754, 12756, 12758, 12760, 12762, 12764, 12766, 12768, 0, 12770, - 12772, 12774, 12776, 12778, 12780, 12782, 12784, 12786, 12788, 12790, - 12792, 12794, 12796, 12798, 12800, 12802, 0, 0, 0, 0, 0, 12804, 12806, - 12808, 0, 12810, 12812, 12814, 12816, 12818, 0, 12820, 12822, 12824, - 12826, 12828, 12830, 12832, 12834, 12836, 12838, 12840, 12842, 12844, - 12846, 12848, 12850, 12852, 0, 0, 0, 0, 12854, 12857, 12860, 12863, - 12866, 12869, 12872, 12875, 12878, 12881, 12884, 0, 0, 0, 0, 0, 12887, - 12891, 12895, 12899, 12903, 12907, 12911, 12915, 12919, 12923, 12927, - 12931, 12935, 12939, 12943, 12947, 12951, 12955, 12959, 12963, 12967, - 12971, 12975, 12979, 12983, 12987, 12991, 12995, 12997, 12999, 13002, 0, - 13005, 13007, 13009, 13011, 13013, 13015, 13017, 13019, 13021, 13023, - 13025, 13027, 13029, 13031, 13033, 13035, 13037, 13039, 13041, 13043, - 13045, 13047, 13049, 13051, 13053, 13055, 13057, 13060, 13063, 13066, - 13069, 13073, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13076, 13079, 0, 0, 0, 0, - 13082, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13085, 13088, 13091, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13093, 13095, 13097, 13099, 13101, - 13103, 13105, 13107, 13109, 13111, 13113, 13115, 13117, 13119, 13121, - 13123, 13125, 13127, 13129, 13131, 13133, 13135, 13137, 13139, 13141, - 13143, 13145, 13147, 13149, 13151, 13153, 13155, 13157, 13159, 13161, - 13163, 13165, 13167, 13169, 13171, 13173, 13175, 13177, 13179, 0, 0, 0, - 0, 13181, 13185, 13189, 13193, 13197, 13201, 13205, 13209, 13213, 0, 0, - 0, 0, 0, 0, 0, 13217, 13219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 13221, 13223, 13225, 13227, 13230, 13232, 13234, 13236, 13238, 13240, - 13242, 13244, 13246, 13248, 13251, 13253, 13255, 13257, 13259, 13262, - 13264, 13266, 13268, 13271, 13273, 13275, 13277, 13279, 13281, 13284, - 13286, 13288, 13290, 13292, 13294, 13296, 13298, 13300, 13302, 13304, - 13306, 13308, 13310, 13312, 13314, 13316, 13318, 13320, 13322, 13324, - 13326, 13328, 13330, 13333, 13335, 13337, 13339, 13342, 13344, 13346, - 13348, 13350, 13352, 13354, 13356, 13358, 13360, 13362, 13364, 13366, - 13368, 13370, 13372, 13374, 13376, 13378, 13380, 13382, 13384, 13386, - 13388, 13390, 13392, 13394, 13396, 13398, 13400, 13402, 13404, 13406, - 13409, 13411, 13413, 13415, 13417, 13419, 13421, 13424, 13427, 13429, - 13431, 13433, 13435, 13437, 13439, 13441, 13443, 13445, 13447, 13450, - 13452, 13454, 13456, 13458, 13461, 13463, 13465, 13467, 13469, 13471, - 13473, 13475, 13477, 13479, 13482, 13484, 13487, 13489, 13491, 13493, - 13495, 13497, 13499, 13501, 13503, 13505, 13507, 13509, 13512, 13514, - 13516, 13518, 13520, 13522, 13525, 13527, 13530, 13533, 13535, 13537, - 13539, 13541, 13544, 13547, 13549, 13551, 13553, 13555, 13557, 13559, - 13561, 13563, 13565, 13567, 13569, 13572, 13574, 13576, 13578, 13580, - 13582, 13584, 13586, 13588, 13590, 13592, 13594, 13596, 13598, 13600, - 13602, 13604, 13606, 13608, 13610, 13613, 13615, 13617, 13619, 13621, - 13623, 13626, 13628, 13630, 13632, 13634, 13636, 13638, 13640, 13642, - 13644, 13646, 13648, 13651, 13653, 13655, 13657, 13659, 13661, 13663, - 13665, 13667, 13669, 13671, 13673, 13675, 13677, 13679, 13681, 13683, - 13685, 13687, 13690, 13692, 13694, 13696, 13698, 13700, 13703, 13705, - 13707, 13709, 13711, 13713, 13715, 13717, 13719, 13722, 13724, 13726, - 13728, 13731, 13733, 13735, 13737, 13739, 13741, 13743, 13746, 13749, - 13752, 13754, 13757, 13759, 13761, 13763, 13765, 13767, 13769, 13771, - 13773, 13775, 13777, 13780, 13782, 13784, 13786, 13788, 13790, 13792, - 13795, 13797, 13799, 13802, 13805, 13807, 13809, 13811, 13813, 13815, - 13817, 13819, 13821, 13823, 13826, 13828, 13831, 13833, 13836, 13838, - 13840, 13842, 13845, 13847, 13849, 13852, 13855, 13857, 13859, 13861, - 13863, 13865, 13867, 13869, 13871, 13873, 13875, 13877, 13879, 13881, - 13884, 13886, 13889, 13891, 13894, 13896, 13899, 13902, 13905, 13907, - 13909, 13911, 13914, 13917, 13920, 13923, 13925, 13927, 13929, 13931, - 13933, 13935, 13937, 13939, 13942, 13944, 13946, 13948, 13950, 13953, - 13955, 13958, 13961, 13963, 13965, 13967, 13969, 13971, 13973, 13976, - 13979, 13982, 13984, 13986, 13989, 13991, 13993, 13995, 13998, 14000, - 14002, 14004, 14006, 14008, 14011, 14013, 14015, 14017, 14019, 14021, - 14023, 14026, 14029, 14031, 14034, 14036, 14039, 14041, 14043, 14045, - 14048, 14051, 14053, 14056, 14058, 14061, 14063, 14065, 14067, 14069, - 14071, 14073, 14076, 14079, 14082, 14085, 14087, 14089, 14091, 14093, - 14095, 14097, 14099, 14101, 14103, 14105, 14107, 14109, 14112, 14114, - 14116, 14118, 14120, 14122, 14124, 14126, 14128, 14130, 14132, 14134, - 14136, 14139, 14142, 14145, 14147, 14149, 14151, 14153, 14156, 14158, - 14161, 14163, 14165, 14168, 14171, 14173, 14175, 14177, 14179, 14181, - 14183, 14185, 14187, 14189, 14191, 14193, 14195, 14197, 14199, 14201, - 14203, 14205, 14207, 14209, 14212, 14214, 14216, 14218, 14220, 14222, - 14225, 14228, 14230, 14232, 14234, 14236, 14238, 14240, 14243, 14245, - 14247, 14249, 14251, 14254, 14257, 14259, 14261, 14263, 14266, 14268, - 14270, 14273, 14276, 14278, 14280, 14282, 14285, 14287, 14289, 14291, - 14293, 14295, 14297, 14299, 14302, 14304, 14306, 14308, 14311, 14313, - 14315, 14317, 14319, 14322, 14325, 14327, 14329, 14331, 14334, 14336, - 14339, 14341, 14343, 14345, 14348, 14350, 14352, 14354, 14356, 14358, - 14360, 14362, 14365, 14367, 14369, 14371, 14373, 14375, 14377, 14380, - 14382, 14385, 14388, 14391, 14393, 14395, 14397, 14399, 14401, 14403, - 14405, 14407, 0, 0, -}; - -/* NFC pairs */ -#define COMP_SHIFT1 2 -#define COMP_SHIFT2 1 -static const unsigned short comp_index0[] = { - 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, - 5, 6, 7, 0, 0, 0, 0, 8, 0, 9, 10, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0, - 15, 16, 17, 0, 0, 0, 0, 18, 19, 20, 21, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, - 23, 24, 25, 26, 0, 0, 0, 0, 27, 28, 29, 30, 0, 0, 0, 0, 31, 32, 33, 34, - 0, 0, 0, 0, 35, 0, 0, 0, 0, 0, 0, 36, 0, 37, 38, 39, 0, 0, 0, 40, 41, 42, - 43, 0, 0, 0, 0, 44, 45, 46, 0, 0, 0, 0, 0, 47, 48, 49, 50, 0, 0, 0, 51, - 52, 53, 54, 0, 0, 0, 0, 55, 56, 0, 0, 0, 0, 0, 0, 57, 58, 59, 60, 0, 0, - 0, 0, 61, 62, 63, 0, 0, 0, 0, 0, 64, 65, 66, 67, 0, 0, 0, 68, 69, 70, 71, - 0, 0, 0, 0, 72, 0, 73, 0, 0, 0, 0, 0, 74, 0, 75, 0, 0, 0, 0, 0, 76, 0, 0, - 0, 0, 0, 0, 77, 78, 79, 0, 0, 0, 0, 0, 80, 81, 82, 83, 0, 0, 0, 0, 84, - 85, 86, 0, 0, 0, 0, 0, 87, 88, 0, 89, 0, 0, 0, 90, 91, 0, 92, 0, 0, 0, 0, - 0, 93, 94, 95, 0, 0, 0, 0, 96, 97, 98, 99, 0, 0, 0, 0, 100, 0, 0, 0, 0, - 0, 0, 101, 102, 0, 103, 0, 0, 0, 0, 104, 105, 106, 107, 0, 0, 0, 0, 108, - 109, 110, 111, 0, 0, 0, 0, 112, 113, 0, 0, 0, 0, 0, 114, 115, 116, 117, - 0, 0, 0, 0, 118, 119, 120, 121, 0, 0, 0, 0, 122, 0, 123, 0, 0, 0, 0, 124, - 125, 126, 127, 128, 0, 0, 0, 129, 130, 131, 132, 0, 0, 0, 0, 133, 134, 0, - 0, 0, 0, 0, 0, 135, 136, 137, 138, 0, 0, 0, 139, 140, 141, 142, 0, 0, 0, - 0, 0, 143, 144, 145, 0, 0, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0, 150, 0, - 151, 0, 0, 0, 0, 152, 153, 154, 0, 0, 0, 0, 0, 0, 155, 0, 0, 0, 0, 0, 0, - 156, 157, 158, 0, 0, 0, 0, 0, 159, 160, 161, 162, 0, 0, 0, 163, 0, 0, 0, - 164, 0, 0, 0, 165, 166, 0, 0, 0, 0, 0, 0, 167, 0, 0, 0, 0, 0, 0, 0, 168, - 0, 0, 0, 0, 0, 0, 169, 170, 0, 0, 0, 0, 0, 0, 171, 0, 0, 0, 0, 0, 0, 0, - 172, 173, 0, 0, 0, 0, 0, 0, 174, 0, 0, 0, 0, 0, 0, 175, 176, 0, 0, 0, 0, - 0, 0, 177, 178, 0, 0, 0, 0, 0, 0, 179, 0, 0, 0, 0, 0, 0, 0, 180, 0, 0, 0, - 0, 0, 0, 181, 182, 183, 0, 0, 0, 0, 0, 184, 185, 0, 0, 0, 0, 0, 0, 186, - 0, 0, 0, 0, 0, 0, 0, 187, 0, 0, 0, 0, 0, 0, 188, 189, 0, 0, 0, 0, 0, 0, - 190, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 0, 193, 0, 0, 0, 0, 0, - 0, 194, 195, 0, 0, 0, 0, 0, 0, 196, 197, 0, 0, 0, 0, 0, 0, 198, 0, 0, 0, - 0, 0, 0, 0, 199, 0, 0, 0, 0, 0, 0, 200, 201, 202, 0, 0, 0, 0, 0, 203, - 204, 0, 0, 0, 0, 0, 0, 205, 206, 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, 0, - 208, 0, 0, 0, 0, 0, 0, 0, 209, 0, 0, 0, 0, 0, 0, 0, 210, 0, 0, 0, 0, 0, - 0, 0, 211, 0, 0, 0, 0, 0, 0, 0, 212, 0, 0, 0, 0, 0, 0, 0, 213, 0, 0, 0, - 0, 0, 0, 0, 214, 0, 0, 0, 0, 0, 0, 215, 0, 0, 0, 0, 0, 0, 216, 0, 0, 0, - 0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 0, 0, 0, 0, 219, 0, - 0, 0, 0, 0, 0, 220, 221, 222, 0, 0, 0, 0, 0, 223, 224, 225, 0, 0, 0, 0, - 0, 226, 227, 228, 0, 0, 0, 0, 0, 229, 230, 231, 0, 0, 0, 0, 0, 0, 232, 0, - 0, 0, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 234, 0, 0, 0, 0, 0, 0, 0, 235, 0, - 0, 0, 0, 0, 0, 0, 236, 0, 0, 0, 0, 0, 0, 0, 237, 0, 0, 0, 0, 0, 0, 238, - 0, 0, 0, 0, 0, 0, 0, 239, 0, 0, 0, 0, 0, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, - 241, 0, 0, 0, 0, 0, 0, 242, 0, 243, 244, 0, 0, 0, 0, 245, 246, 0, 0, 0, - 0, 0, 247, 0, 248, 0, 249, 0, 0, 0, 250, 251, 252, 0, 0, 0, 0, 0, 253, 0, - 254, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 256, 257, 258, 0, 0, 0, 0, 0, - 259, 0, 260, 0, 261, 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 263, 0, - 0, 0, 264, 265, 266, 0, 267, 0, 0, 0, 268, 0, 269, 0, 0, 0, 0, 0, 270, 0, - 271, 272, 0, 0, 0, 0, 273, 274, 0, 275, 0, 0, 0, 276, 0, 277, 0, 0, 0, 0, - 0, 0, 0, 278, 0, 0, 0, 0, 0, 279, 280, 281, 282, 0, 0, 0, 0, 283, 284, 0, - 285, 0, 0, 0, 286, 0, 0, 0, 287, 0, 0, 0, 288, 0, 0, 0, 289, 0, 0, 0, 0, - 0, 0, 290, 0, 0, 0, 0, 291, 0, 0, 0, 0, 0, 0, 0, 292, 0, 0, 0, 0, 0, 0, - 0, 293, 0, 0, 0, 0, 0, 0, 294, 0, 0, 0, 0, 0, 0, 0, 295, 0, 0, 0, 0, 0, - 0, 0, 296, 0, 0, 0, 0, 0, 0, 0, 297, 0, 0, 0, 0, 0, 0, 298, 299, 0, 0, 0, - 0, 0, 0, 300, 0, 0, 0, 0, 0, 0, 0, 301, 0, 0, 0, 0, 0, 0, 0, 302, 0, 0, - 0, 0, 0, 0, 0, 303, 0, 0, 0, 0, 0, 0, 304, 0, 0, 0, 0, 0, 0, 0, 305, 0, - 0, 0, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 307, 0, 0, 0, 0, 0, 0, 0, 308, - 0, 0, 0, 0, 0, 0, 0, 309, 0, 0, 0, 0, 0, 0, 0, 310, 0, 0, 0, 0, 0, 0, - 311, 312, 0, 0, 0, 0, 0, 0, 313, 0, 0, 0, 0, 0, 0, 0, 314, 0, 0, 0, 0, 0, - 0, 0, 315, 0, 0, 0, 0, 0, 0, 0, 316, 0, 0, 0, 0, 0, 0, 317, 0, 0, 0, 0, - 0, 0, 0, 318, 0, 0, 0, 0, 0, 0, 0, 319, 0, 0, 0, 0, 0, 0, 0, 320, 0, 0, - 0, 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, 322, 0, 0, 0, 0, 0, 0, 0, 323, 0, - 0, 0, 0, 0, 0, 0, 324, 0, 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 326, 0, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 0, 328, 0, 0, 0, 0, - 0, 0, 329, 0, 0, 0, 0, 0, 0, 0, 330, 0, 0, 0, 0, 0, 0, 0, 331, 0, 0, 0, - 0, 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, 333, 0, 0, 0, 0, 0, 0, 334, 0, 0, - 0, 0, 0, 0, 0, 335, 0, 0, 0, 0, 0, 0, 0, 336, 337, 0, 0, 0, 0, 0, 0, 0, - 338, 0, 0, 0, 0, 0, 0, 339, 0, 0, 0, 0, 0, 0, 0, 340, 0, 0, 0, 0, 0, 0, - 0, 341, 0, 0, 0, 0, 0, 0, 0, 342, 0, 0, 0, 0, 0, 0, 0, 343, 0, 0, 0, 0, - 0, 0, 344, 0, 0, 0, 0, 0, 0, 0, 345, 346, 0, 0, 0, 0, 0, 0, 347, 0, 0, 0, - 0, 0, 0, 0, 348, 0, 0, 0, 0, 0, 0, 0, 349, 0, 0, 0, 0, 0, 0, 0, 350, 0, - 0, 0, 0, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, 0, 352, 0, 0, 0, 0, 0, 0, 353, - 0, 0, 0, 0, 0, 0, 0, 354, 0, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 0, 0, 0, 0, - 356, 0, 0, 0, 0, 0, 0, 357, 0, 0, 0, 0, 0, 0, 0, 358, 0, 0, 0, 0, 0, 0, - 0, 359, 0, 0, 0, 0, 0, 0, 0, 360, 0, 0, 0, 0, 0, 0, 361, 0, 362, 0, 0, 0, - 0, 0, 0, 0, 363, 0, 0, 0, 0, 0, 0, 0, 364, 0, 0, 0, 0, 0, 0, 0, 365, 0, - 0, 0, 0, 0, 0, 0, 366, 0, 0, 0, 0, 0, 0, 367, 0, 0, 0, 0, 0, 0, 0, 368, - 0, 0, 0, 0, 0, 0, 369, 370, 0, 0, 0, 0, 0, 0, 371, 0, 0, 0, 0, 0, 0, 0, - 372, 0, 0, 0, 0, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 0, 0, 0, 0, - 0, 375, 0, 0, 376, 0, 0, 0, 0, 377, 0, 0, 378, 0, 0, 0, 0, 0, 0, 0, 379, - 0, 0, 0, 0, 0, 0, 0, 380, 0, 0, 0, 0, 0, 0, 381, 0, 0, 0, 0, 0, 0, 0, - 382, 0, 0, 0, 0, 0, 0, 0, 383, 0, 0, 0, 0, 0, 0, 0, 384, 0, 0, 0, 385, 0, - 0, 386, 0, 0, 0, 0, 387, 0, 0, 388, 0, 0, 0, 0, 0, 0, 0, 389, 0, 0, 0, 0, - 0, 0, 0, 390, 0, 0, 0, 0, 0, 0, 391, 0, 0, 0, 0, 0, 0, 0, 392, 0, 0, 0, - 0, 0, 0, 0, 393, 0, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 395, 0, 0, 0, 0, 0, - 0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 0, 0, 0, 0, 398, 0, 0, 0, 0, - 0, 0, 0, 399, 0, 0, 400, 0, 0, 0, 0, 401, 0, 0, 402, 0, 0, 0, 0, 0, 0, 0, - 403, 0, 0, 0, 0, 0, 0, 0, 404, 0, 0, 0, 0, 0, 0, 405, 0, 0, 0, 0, 0, 0, - 0, 406, 0, 0, 0, 0, 0, 0, 0, 407, 0, 0, 0, 0, 0, 0, 0, 408, 0, 0, 0, 409, - 0, 0, 410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 0, 0, 0, 0, 413, 0, 0, 0, - 0, 0, 0, 0, 414, 0, 0, 0, 0, 0, 0, 415, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0, - 0, 0, 0, 0, 0, 417, 0, 0, 0, 0, 0, 0, 0, 418, 0, 0, 0, 419, 0, 0, 420, 0, - 0, 0, 0, 421, 0, 0, 422, 0, 0, 0, 423, 0, 0, 0, 424, 0, 0, 0, 425, 0, 0, - 0, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, 0, 429, 0, - 0, 0, 0, 0, 0, 0, 430, 0, 0, 0, 0, 0, 0, 0, 431, 0, 0, 432, 0, 0, 0, 0, - 433, 0, 0, 434, 0, 0, 0, 435, 0, 0, 0, 436, 0, 0, 0, 437, 0, 0, 0, 438, - 0, 0, 0, 439, 0, 0, 440, 0, 0, 0, 0, 0, 0, 0, 441, 0, 0, 0, 0, 0, 0, 0, - 442, 0, 0, 0, 0, 0, 0, 0, 443, 0, 0, 0, 0, 0, 0, 444, 0, 0, 0, 0, 0, 0, - 0, 445, 0, 0, 0, 0, 0, 0, 0, 446, 0, 0, 0, 447, 0, 0, 0, 448, 0, 0, 0, - 449, 0, 0, 450, 0, 0, 0, 0, 0, 0, 0, 451, 0, 0, 0, 0, 0, 0, 0, 452, 0, 0, - 0, 0, 0, 0, 0, 453, 0, 0, 0, 0, 0, 0, 454, 0, 0, 0, 0, 0, 0, 0, 455, 0, - 0, 0, 0, 0, 0, 0, 456, 0, 0, 0, 0, 0, 0, 0, 457, 0, 0, 0, 0, 0, 0, 458, - 0, 0, 0, 0, 0, 0, 0, 459, 0, 0, 0, 0, 0, 0, 0, 460, 0, 0, 0, 461, 0, 0, - 0, 462, 0, 0, 0, 0, 0, 0, 463, 0, 0, 0, 0, 0, 0, 0, 464, 0, 0, 0, 465, 0, - 0, 0, 466, 0, 0, 0, 0, 0, 0, 467, 0, 0, 0, 0, 0, 0, 0, 468, 0, 0, 0, 0, - 0, 0, 0, 469, 0, 0, 0, 0, 0, 0, 0, 470, 0, 0, 0, 0, 0, 0, 471, 0, 0, 0, - 0, 0, 0, 0, 472, 0, 0, 0, 0, 0, 0, 0, 473, 0, 0, 0, 0, 0, 0, 0, 474, 0, - 0, 0, 0, 0, 0, 475, 0, 0, 0, 0, 0, 0, 0, 476, 0, 0, 0, 0, 0, 0, 0, 477, - 0, 0, 0, 0, 0, 0, 0, 478, 0, 0, 0, 0, 0, 0, 479, 0, 0, 0, 0, 0, 0, 0, - 480, 0, 0, 0, 0, 0, 0, 0, 481, 0, 0, 0, 0, 0, 0, 0, 482, 0, 0, 0, 0, 0, - 0, 483, 0, 0, 0, 0, 0, 0, 0, 484, 0, 0, 0, 0, 0, 0, 0, 485, 0, 0, 0, 0, - 0, 0, 0, 486, 0, 0, 0, 0, 0, 0, 487, 0, 0, 0, 0, 0, 0, 0, 488, 0, 0, 0, - 0, 0, 0, 0, 489, 0, 0, 0, 0, 0, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0, - 0, 0, 0, 0, 0, 492, 0, 0, 0, 0, 0, 0, 0, 493, 0, 0, 0, 0, 0, 0, 0, 494, - 0, 0, 0, 0, 0, 0, 495, 0, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0, - 497, 0, 0, 0, 0, 0, 0, 0, 498, 0, 0, 0, 0, 0, 0, 499, 0, 0, 0, 0, 0, 0, - 0, 500, 0, 0, 0, 0, 0, 0, 0, 501, 0, 0, 0, 0, 0, 0, 0, 502, 0, 0, 0, 0, - 0, 0, 503, 0, 0, 0, 0, 0, 0, 0, 504, 0, 0, 0, 0, 0, 0, 0, 505, 0, 0, 0, - 0, 0, 0, 0, 506, 0, 0, 0, 0, 0, 0, 507, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 508, 0, 0, 0, 0, 0, 0, 0, 509, 0, 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0, - 0, 0, 511, 0, 0, 0, 0, 0, 0, 512, 0, 0, 0, 0, 0, 0, 0, 513, 0, 0, 0, 0, - 0, 0, 0, 514, 0, 0, 0, 0, 0, 0, 0, 515, 0, 0, 0, 0, 0, 0, 516, 0, 0, 0, - 0, 0, 0, 0, 517, 0, 0, 0, 0, 0, 0, 0, 518, 0, 0, 0, 0, 0, 0, 0, 519, 0, - 0, 0, 0, 0, 0, 520, 0, 0, 0, 0, 0, 0, 0, 521, 0, 0, 0, 0, 0, 0, 0, 522, - 0, 0, 0, 0, 0, 0, 0, 523, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, 0, 0, 0, - 525, 0, 0, 0, 0, 0, 0, 0, 526, 0, 0, 0, 0, 0, 0, 0, 527, 0, 0, 0, 0, 0, - 0, 528, 0, 0, 0, 0, 0, 0, 0, 529, 0, 0, 0, 0, 0, 0, 0, 530, 0, 0, 0, 0, - 0, 0, 0, 531, 0, 0, 0, 0, 0, 0, 532, 0, 0, 0, 0, 0, 0, 0, 533, 0, 0, 0, - 0, 0, 0, 0, 534, 0, 0, 0, 0, 0, 0, 0, 535, 0, 0, 0, 0, 0, 0, 536, 0, 0, - 0, 0, 0, 0, 0, 537, 0, 0, 0, 0, 0, 0, 0, 538, 0, 0, 0, 0, 0, 0, 0, 539, - 0, 0, 0, 0, 0, 0, 540, 0, 0, 0, 0, 0, 0, 0, 541, 0, 0, 0, 0, 0, 0, 0, - 542, 0, 0, 0, 0, 0, 0, 0, 543, 0, 0, 0, 0, 0, 0, 544, 0, 0, 0, 0, 0, 0, - 0, 545, 0, 0, 0, 0, 0, 0, 0, 546, 0, 0, 0, 0, 0, 0, 0, 547, 0, 0, 0, 0, - 0, 0, 548, 0, 0, 0, 0, 0, 0, 0, 549, 0, 0, 0, 0, 0, 0, 0, 550, 0, 0, 0, - 0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 0, 552, 0, 0, 0, 0, 0, 0, 0, 553, 0, 0, - 0, 0, 0, 0, 0, 554, 0, 0, 0, 0, 0, 0, 0, 555, 0, 0, 0, 0, 0, 0, 0, 556, - 0, 0, 0, 0, 0, 0, 557, 0, 0, 0, 0, 0, 0, 0, 558, 0, 0, 0, 0, 0, 0, 0, - 559, 0, 0, 0, 0, 0, 0, 0, 560, 0, 0, 0, 0, 0, 0, 0, 561, 0, 0, 0, 0, 0, - 0, 0, 562, 0, 0, 0, 0, 0, 0, 0, 563, 0, 0, 0, 0, 0, 0, 564, -}; - -static const unsigned short comp_index1[] = { - 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 0, 3, 0, 4, 5, 6, 7, 8, 9, 10, - 0, 11, 12, 0, 13, 0, 0, 0, 0, 0, 0, 14, 15, 0, 0, 0, 0, 16, 0, 0, 0, 0, - 0, 17, 18, 0, 19, 0, 20, 0, 0, 0, 0, 21, 0, 0, 0, 22, 0, 23, 0, 0, 24, 0, - 25, 26, 0, 27, 0, 28, 29, 30, 31, 32, 33, 34, 0, 35, 0, 36, 37, 38, 0, 0, - 0, 0, 0, 39, 0, 0, 0, 40, 41, 42, 43, 0, 44, 0, 0, 0, 0, 45, 0, 0, 0, 0, - 0, 46, 0, 47, 0, 48, 0, 0, 49, 0, 50, 0, 51, 0, 0, 52, 53, 54, 55, 56, - 57, 58, 0, 59, 0, 0, 60, 61, 0, 0, 0, 62, 0, 0, 0, 0, 0, 63, 64, 0, 0, - 65, 0, 66, 0, 0, 67, 0, 0, 0, 0, 0, 68, 0, 0, 0, 0, 69, 0, 0, 70, 0, 71, - 72, 0, 73, 0, 74, 0, 0, 75, 0, 0, 0, 0, 76, 0, 0, 77, 78, 0, 79, 0, 80, - 0, 0, 81, 0, 82, 83, 0, 84, 0, 0, 0, 0, 0, 85, 86, 87, 88, 89, 90, 91, 0, - 92, 0, 0, 93, 0, 0, 0, 94, 0, 0, 95, 0, 0, 0, 96, 0, 0, 97, 0, 98, 99, 0, - 100, 0, 101, 0, 0, 102, 0, 103, 104, 0, 105, 0, 106, 0, 0, 107, 0, 108, - 0, 0, 0, 109, 0, 110, 0, 0, 111, 0, 112, 113, 0, 114, 0, 0, 0, 0, 0, 115, - 116, 117, 118, 119, 120, 121, 0, 122, 123, 0, 124, 125, 0, 0, 0, 126, 0, - 0, 127, 0, 0, 128, 129, 0, 130, 131, 0, 0, 0, 0, 0, 132, 0, 0, 0, 133, - 134, 135, 136, 137, 0, 0, 0, 138, 0, 0, 139, 140, 0, 141, 0, 142, 0, 0, - 143, 0, 0, 0, 0, 144, 0, 145, 146, 147, 148, 149, 150, 151, 0, 152, 153, - 0, 154, 0, 0, 155, 0, 0, 0, 0, 156, 157, 0, 0, 0, 0, 0, 158, 159, 0, 160, - 0, 161, 162, 0, 0, 0, 163, 0, 164, 0, 0, 165, 0, 166, 167, 0, 168, 0, - 169, 170, 171, 172, 173, 174, 175, 0, 176, 0, 177, 178, 179, 0, 0, 0, 0, - 0, 180, 0, 0, 0, 181, 182, 183, 184, 0, 185, 186, 0, 0, 0, 0, 0, 187, 0, - 188, 0, 189, 0, 0, 190, 0, 191, 0, 192, 193, 0, 194, 195, 196, 197, 198, - 199, 200, 0, 201, 0, 0, 202, 203, 0, 0, 0, 204, 0, 0, 0, 205, 0, 0, 0, 0, - 0, 206, 0, 0, 0, 0, 207, 0, 0, 208, 0, 209, 0, 0, 210, 0, 211, 0, 0, 0, - 0, 212, 0, 0, 213, 0, 214, 215, 0, 216, 0, 217, 0, 0, 218, 219, 0, 0, 0, - 0, 0, 0, 220, 221, 0, 222, 0, 223, 0, 0, 224, 0, 225, 226, 0, 227, 0, 0, - 0, 0, 0, 228, 229, 230, 231, 232, 233, 234, 0, 235, 0, 0, 236, 0, 0, 0, - 237, 0, 0, 238, 0, 0, 0, 239, 0, 0, 240, 0, 241, 242, 0, 243, 0, 244, 0, - 0, 245, 0, 0, 0, 0, 0, 246, 247, 0, 248, 0, 249, 0, 0, 250, 0, 251, 0, 0, - 0, 252, 0, 253, 0, 0, 254, 0, 255, 256, 0, 257, 0, 258, 259, 260, 261, - 262, 263, 264, 0, 265, 266, 0, 267, 268, 0, 0, 0, 269, 0, 0, 270, 0, 0, - 0, 0, 0, 0, 271, 272, 0, 273, 274, 0, 0, 0, 275, 0, 276, 0, 0, 0, 277, - 278, 279, 280, 281, 0, 0, 0, 282, 0, 0, 283, 284, 0, 285, 0, 286, 0, 0, - 287, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 289, 0, 290, 0, 0, 0, 0, 291, 292, - 0, 0, 293, 0, 0, 0, 0, 294, 295, 0, 0, 0, 0, 0, 0, 296, 0, 297, 0, 0, 0, - 0, 298, 0, 0, 299, 300, 0, 0, 301, 0, 0, 302, 0, 0, 0, 0, 0, 0, 303, 304, - 0, 0, 305, 0, 0, 306, 0, 307, 308, 0, 0, 0, 0, 0, 309, 310, 0, 0, 0, 0, - 0, 0, 311, 0, 312, 0, 0, 313, 0, 0, 0, 0, 0, 314, 315, 0, 0, 316, 0, 0, - 0, 0, 317, 318, 0, 0, 0, 0, 0, 0, 319, 0, 320, 0, 0, 0, 0, 321, 0, 0, - 322, 323, 0, 0, 324, 0, 0, 325, 0, 0, 0, 0, 0, 0, 326, 327, 0, 0, 328, 0, - 0, 329, 0, 330, 331, 0, 0, 0, 0, 0, 332, 333, 0, 0, 0, 0, 0, 0, 334, 0, - 335, 0, 0, 336, 0, 0, 0, 0, 0, 337, 338, 0, 0, 339, 0, 0, 340, 341, 0, 0, - 342, 0, 0, 343, 0, 0, 0, 0, 0, 0, 344, 0, 0, 345, 0, 0, 346, 0, 0, 0, 0, - 0, 347, 0, 0, 348, 0, 0, 349, 0, 0, 350, 0, 0, 0, 351, 0, 0, 0, 0, 0, 0, - 352, 0, 353, 0, 0, 354, 0, 0, 0, 0, 0, 0, 355, 0, 0, 0, 356, 357, 0, 0, - 358, 0, 0, 0, 359, 0, 0, 360, 361, 0, 0, 362, 0, 0, 0, 363, 0, 0, 364, - 365, 0, 0, 366, 0, 0, 0, 367, 0, 0, 368, 369, 0, 0, 370, 0, 0, 0, 371, 0, - 0, 0, 372, 0, 0, 0, 373, 0, 0, 0, 0, 0, 0, 374, 0, 0, 375, 0, 0, 376, 0, - 0, 377, 0, 0, 0, 0, 0, 0, 378, 0, 0, 379, 0, 0, 380, 0, 0, 0, 0, 0, 381, - 0, 382, 0, 383, 384, 0, 0, 0, 0, 0, 0, 385, 386, 0, 0, 0, 0, 0, 0, 387, - 0, 0, 0, 388, 0, 0, 389, 0, 0, 390, 0, 0, 0, 0, 391, 0, 392, 393, 0, 0, - 0, 394, 0, 0, 0, 395, 0, 0, 396, 0, 0, 0, 0, 0, 0, 397, 0, 0, 0, 398, 0, - 399, 400, 0, 0, 0, 401, 0, 0, 0, 402, 0, 0, 403, 0, 0, 404, 0, 0, 0, 0, - 0, 0, 405, 0, 0, 406, 0, 0, 0, 0, 407, 0, 408, 0, 0, 0, 0, 409, 0, 0, - 410, 0, 0, 0, 0, 411, 0, 0, 412, 0, 0, 0, 413, 0, 0, 414, 0, 0, 0, 0, 0, - 0, 415, 416, 0, 417, 418, 0, 0, 0, 419, 0, 0, 420, 0, 0, 0, 0, 421, 0, 0, - 422, 0, 0, 423, 0, 0, 0, 424, 0, 425, 426, 0, 0, 0, 427, 0, 0, 0, 0, 0, - 0, 428, 429, 0, 0, 0, 0, 0, 0, 430, 0, 0, 431, 0, 0, 0, 0, 432, 0, 433, - 0, 0, 0, 0, 434, 0, 435, 0, 0, 0, 0, 0, 0, 436, 437, 0, 0, 438, 0, 0, - 439, 0, 440, 441, 0, 0, 0, 442, 0, 0, 443, 0, 444, 445, 0, 446, 447, 0, - 0, 448, 0, 0, 0, 449, 0, 450, 451, 0, 0, 0, 452, 0, 0, 0, 0, 0, 453, 0, - 454, 455, 0, 456, 457, 0, 0, 0, 0, 0, 0, 458, 0, 0, 459, 0, 460, 461, 0, - 0, 0, 462, 0, 0, 463, 0, 464, 465, 0, 466, 467, 0, 0, 468, 0, 0, 0, 469, - 0, 470, 471, 0, 0, 0, 472, 0, 0, 0, 0, 0, 473, 0, 474, 475, 0, 476, 477, - 0, 0, 0, 0, 0, 0, 478, 0, 0, 479, 0, 0, 480, 0, 0, 0, 0, 0, 481, 0, 0, - 482, 0, 0, 0, 483, 0, 0, 484, 0, 0, 485, 0, 0, 0, 0, 0, 0, 486, 0, 0, - 487, 488, 0, 489, 0, 0, 490, 0, 0, 0, 0, 0, 0, 491, 0, 0, 492, 0, 0, 493, - 0, 0, 0, 494, 0, 0, 495, 0, 0, 0, 0, 0, 0, 496, 0, 0, 0, 497, 0, 0, 0, - 498, 499, 0, 0, 0, 500, 0, 0, 0, 0, 0, 501, 502, 0, 503, 0, 0, 0, 504, 0, - 0, 0, 505, 0, 0, 506, 507, 0, 0, 0, 0, 0, 508, 0, 0, 0, 509, 510, 0, 0, - 0, 0, 0, 511, 0, 0, 0, 512, 513, 0, 514, 0, 0, 0, 0, 515, 0, 0, 516, 0, - 0, 517, 0, 0, 0, 0, 0, 0, 518, 0, 0, 519, 0, 0, 520, 0, 0, 521, 0, 0, 0, - 0, 0, 0, 522, 0, 0, 523, 0, 0, 524, 0, 0, 525, 0, 0, 0, 0, 0, 0, 526, 0, - 0, 0, 527, 0, 0, 528, 0, 0, 529, 0, 0, 530, 0, 0, 0, 531, 0, 0, 0, 0, 0, - 0, 532, 533, 534, 0, 0, 0, 0, 0, 535, 536, 0, 0, 0, 0, 0, 537, 0, 0, 538, - 0, 0, 539, 0, 0, 0, 0, 0, 0, 540, 0, 541, 0, 0, 0, 0, 0, 542, 543, 0, 0, - 0, 0, 0, 544, 0, 0, 545, 0, 0, 546, 0, 0, 0, 0, 0, 0, 547, 0, 0, 548, 0, - 0, 549, 0, 0, 550, 0, 0, 0, 0, 551, 0, 0, 0, 0, 0, 552, 553, 0, 0, 0, 0, - 0, 554, 0, 0, 555, 0, 0, 556, 0, 0, 0, 0, 0, 0, 557, 0, 0, 558, 0, 0, - 559, 0, 0, 560, 0, 0, 0, 0, 561, 0, 0, 562, 0, 0, 0, 0, 0, 0, 563, 0, 0, - 564, 0, 0, 565, 0, 0, 0, 0, 0, 566, 567, 0, 0, 0, 0, 0, 568, 0, 0, 569, - 0, 0, 570, 0, 0, 0, 0, 0, 0, 571, 0, 0, 572, 0, 0, 573, 0, 0, 574, 0, 0, - 0, 0, 575, 0, 0, 0, 0, 0, 576, 577, 0, 0, 0, 0, 0, 578, 0, 0, 579, 0, 0, - 580, 0, 0, 0, 0, 0, 0, 581, 0, 0, 582, 0, 0, 583, 0, 0, 584, 0, 0, 0, 0, - 585, 0, 0, 0, 0, 0, 586, 587, 0, 0, 0, 0, 0, 588, 0, 0, 0, 0, 589, 0, - 590, 0, 0, 0, 0, 591, 0, 592, 0, 0, 0, 0, 593, 0, 0, 594, 0, 0, 0, 0, 0, - 0, 595, 0, 0, 596, 0, 0, 597, 0, 0, 0, 0, 0, 598, 599, 0, 0, 0, 0, 0, - 600, 0, 0, 0, 0, 601, 0, 602, 0, 0, 0, 0, 603, 0, 604, 0, 0, 0, 0, 605, - 0, 0, 0, 0, 0, 606, 0, 0, 607, 0, 0, 608, 0, 0, 609, 0, 0, 0, 0, 0, 0, - 610, 0, 0, 611, 0, 0, 612, 0, 0, 0, 0, 613, 0, 614, 0, 0, 0, 0, 615, 0, - 0, 0, 0, 0, 616, 0, 0, 617, 0, 0, 618, 0, 0, 619, 0, 0, 0, 0, 0, 0, 620, - 0, 0, 621, 0, 0, 622, 0, 0, 623, 0, 0, 0, 0, 0, 0, 624, 0, 0, 625, 0, 0, - 626, 0, 0, 0, 0, 627, 0, 628, 0, 0, 0, 0, 0, 0, 629, 0, 0, 630, 0, 0, 0, - 0, 631, 0, 632, 0, 0, 0, 0, 0, 633, 0, 0, 634, 0, 0, 635, 0, 0, 636, 0, - 0, 0, 0, 0, 0, 637, 0, 0, 638, 0, 0, 639, 0, 0, 640, 0, 0, 0, 0, 0, 0, - 641, 0, 0, 642, 0, 0, 643, 0, 0, 644, 0, 0, 0, 0, 0, 0, 645, 0, 0, 646, - 0, 0, 647, 0, 0, 648, 0, 0, 0, 0, 0, 0, 649, 0, 0, 650, 0, 0, 651, 0, 0, - 652, 0, 0, 0, 0, 0, 0, 653, 0, 0, 654, 0, 0, 655, 0, 0, 656, 0, 0, 0, 0, - 0, 0, 657, 0, 0, 658, 0, 0, 659, 0, 0, 660, 0, 0, 0, 0, 0, 0, 661, 0, 0, - 662, 0, 0, 663, 0, 0, 664, 0, 0, 0, 0, 0, 0, 665, 0, 0, 666, 0, 0, 667, - 0, 0, 668, 0, 0, 0, 0, 0, 0, 669, 0, 0, 670, 0, 0, 671, 0, 0, 672, 0, 0, - 0, 0, 0, 0, 673, 0, 0, 0, 674, 0, 0, 675, 0, 0, 676, 0, 0, 677, 0, 0, 0, - 0, 0, 0, 678, 0, 0, 679, 0, 0, 680, 0, 0, 681, 0, 0, 0, 0, 0, 0, 682, 0, - 0, 683, 0, 0, 684, 0, 0, 685, 0, 0, 0, 0, 0, 0, 686, 0, 0, 687, 0, 0, - 688, 0, 0, 689, 0, 0, 0, 0, 0, 0, 690, 0, 0, 691, 0, 0, 692, 0, 0, 693, - 0, 0, 0, 0, 0, 0, 694, 0, 0, 695, 0, 0, 696, 0, 0, 697, 0, 0, 0, 0, 0, 0, - 698, 0, 0, 699, 0, 0, 700, 0, 0, 701, 0, 0, 0, 0, 0, 0, 702, 0, 0, 703, - 0, 0, 704, 0, 0, 705, 0, 0, 0, 0, 0, 0, 706, 0, 0, 707, 0, 0, 708, 0, 0, - 709, 0, 0, 0, 0, 0, 0, 710, 0, 0, 711, 0, 0, 712, 0, 0, 713, 0, 0, 0, 0, - 0, 0, 714, 0, 0, 715, 0, 0, 716, 0, 0, 717, 0, 0, 0, 0, 0, 0, 718, 0, 0, - 719, 0, 0, 720, 0, 0, 721, 0, 0, 0, 722, 0, 0, 0, 0, 0, 0, 723, 0, 0, - 724, 0, 0, 725, 0, 0, 726, 0, 0, 0, 727, 0, 0, 0, 728, 729, 0, 0, 730, 0, - 0, 0, 0, 0, 0, 731, -}; - -static const unsigned int comp_data[] = { - 0, 0, 0, 8814, 0, 8800, 0, 8815, 192, 193, 194, 195, 256, 258, 550, 196, - 7842, 197, 0, 461, 512, 514, 0, 7840, 0, 7680, 260, 0, 7682, 0, 0, 7684, - 7686, 0, 0, 262, 264, 0, 266, 0, 0, 268, 0, 199, 7690, 0, 0, 270, 0, - 7692, 0, 7696, 0, 7698, 7694, 0, 200, 201, 202, 7868, 274, 276, 278, 203, - 7866, 0, 0, 282, 516, 518, 0, 7864, 0, 552, 280, 7704, 0, 7706, 7710, 0, - 0, 500, 284, 0, 7712, 286, 288, 0, 0, 486, 0, 290, 292, 0, 7714, 7718, 0, - 542, 0, 7716, 0, 7720, 7722, 0, 204, 205, 206, 296, 298, 300, 304, 207, - 7880, 0, 0, 463, 520, 522, 0, 7882, 302, 0, 0, 7724, 308, 0, 0, 7728, 0, - 488, 0, 7730, 0, 310, 7732, 0, 0, 313, 0, 317, 0, 7734, 0, 315, 0, 7740, - 7738, 0, 0, 7742, 7744, 0, 0, 7746, 504, 323, 0, 209, 7748, 0, 0, 327, 0, - 7750, 0, 325, 0, 7754, 7752, 0, 210, 211, 212, 213, 332, 334, 558, 214, - 7886, 0, 336, 465, 524, 526, 416, 7884, 490, 0, 0, 7764, 7766, 0, 0, 340, - 7768, 0, 0, 344, 528, 530, 0, 7770, 0, 342, 7774, 0, 0, 346, 348, 0, - 7776, 0, 0, 352, 0, 7778, 536, 350, 7786, 0, 0, 356, 0, 7788, 538, 354, - 0, 7792, 7790, 0, 217, 218, 219, 360, 362, 364, 0, 220, 7910, 366, 368, - 467, 532, 534, 431, 7908, 7794, 0, 370, 7798, 0, 7796, 0, 7804, 0, 7806, - 7808, 7810, 372, 0, 7814, 7812, 0, 7816, 7818, 7820, 7922, 221, 374, - 7928, 562, 0, 7822, 376, 7926, 0, 0, 7924, 0, 377, 7824, 0, 379, 0, 0, - 381, 0, 7826, 7828, 0, 224, 225, 226, 227, 257, 259, 551, 228, 7843, 229, - 0, 462, 513, 515, 0, 7841, 0, 7681, 261, 0, 7683, 0, 0, 7685, 7687, 0, 0, - 263, 265, 0, 267, 0, 0, 269, 0, 231, 7691, 0, 0, 271, 0, 7693, 0, 7697, - 0, 7699, 7695, 0, 232, 233, 234, 7869, 275, 277, 279, 235, 7867, 0, 0, - 283, 517, 519, 0, 7865, 0, 553, 281, 7705, 0, 7707, 7711, 0, 0, 501, 285, - 0, 7713, 287, 289, 0, 0, 487, 0, 291, 293, 0, 7715, 7719, 0, 543, 0, - 7717, 0, 7721, 7723, 0, 7830, 0, 236, 237, 238, 297, 299, 301, 0, 239, - 7881, 0, 0, 464, 521, 523, 0, 7883, 303, 0, 0, 7725, 309, 0, 0, 496, 0, - 7729, 0, 489, 0, 7731, 0, 311, 7733, 0, 0, 314, 0, 318, 0, 7735, 0, 316, - 0, 7741, 7739, 0, 0, 7743, 7745, 0, 0, 7747, 505, 324, 0, 241, 7749, 0, - 0, 328, 0, 7751, 0, 326, 0, 7755, 7753, 0, 242, 243, 244, 245, 333, 335, - 559, 246, 7887, 0, 337, 466, 525, 527, 417, 7885, 491, 0, 0, 7765, 7767, - 0, 0, 341, 7769, 0, 0, 345, 529, 531, 0, 7771, 0, 343, 7775, 0, 0, 347, - 349, 0, 7777, 0, 0, 353, 0, 7779, 537, 351, 7787, 7831, 0, 357, 0, 7789, - 539, 355, 0, 7793, 7791, 0, 249, 250, 251, 361, 363, 365, 0, 252, 7911, - 367, 369, 468, 533, 535, 432, 7909, 7795, 0, 371, 7799, 0, 7797, 0, 7805, - 0, 7807, 7809, 7811, 373, 0, 7815, 7813, 0, 7832, 0, 7817, 7819, 7821, - 7923, 253, 375, 7929, 563, 0, 7823, 255, 7927, 7833, 0, 7925, 0, 378, - 7825, 0, 380, 0, 0, 382, 0, 7827, 7829, 0, 8173, 901, 8129, 0, 7846, - 7844, 0, 7850, 7848, 0, 478, 0, 0, 506, 0, 508, 482, 0, 0, 7688, 7872, - 7870, 0, 7876, 7874, 0, 0, 7726, 7890, 7888, 0, 7894, 7892, 0, 0, 7756, - 556, 0, 0, 7758, 554, 0, 0, 510, 475, 471, 469, 0, 0, 473, 7847, 7845, 0, - 7851, 7849, 0, 479, 0, 0, 507, 0, 509, 483, 0, 0, 7689, 7873, 7871, 0, - 7877, 7875, 0, 0, 7727, 7891, 7889, 0, 7895, 7893, 0, 0, 7757, 557, 0, 0, - 7759, 555, 0, 0, 511, 476, 472, 470, 0, 0, 474, 7856, 7854, 0, 7860, - 7858, 0, 7857, 7855, 0, 7861, 7859, 0, 7700, 7702, 7701, 7703, 7760, - 7762, 7761, 7763, 7780, 0, 7781, 0, 7782, 0, 7783, 0, 0, 7800, 0, 7801, - 0, 7802, 0, 7803, 7835, 0, 7900, 7898, 0, 7904, 7902, 0, 0, 7906, 7901, - 7899, 0, 7905, 7903, 0, 0, 7907, 7914, 7912, 0, 7918, 7916, 0, 0, 7920, - 7915, 7913, 0, 7919, 7917, 0, 0, 7921, 0, 494, 492, 0, 493, 0, 480, 0, - 481, 0, 0, 7708, 0, 7709, 560, 0, 561, 0, 0, 495, 8122, 902, 8121, 8120, - 7944, 7945, 0, 8124, 8136, 904, 7960, 7961, 8138, 905, 7976, 7977, 0, - 8140, 8154, 906, 8153, 8152, 0, 938, 7992, 7993, 8184, 908, 8008, 8009, - 0, 8172, 8170, 910, 8169, 8168, 0, 939, 0, 8025, 8186, 911, 8040, 8041, - 0, 8188, 0, 8116, 0, 8132, 8048, 940, 8113, 8112, 7936, 7937, 8118, 8115, - 8050, 941, 7952, 7953, 8052, 942, 7968, 7969, 8134, 8131, 8054, 943, - 8145, 8144, 0, 970, 7984, 7985, 8150, 0, 8056, 972, 8000, 8001, 8164, - 8165, 8058, 973, 8161, 8160, 0, 971, 8016, 8017, 8166, 0, 8060, 974, - 8032, 8033, 8182, 8179, 8146, 912, 8151, 0, 8162, 944, 8167, 0, 0, 8180, - 0, 979, 0, 980, 0, 1031, 0, 1232, 0, 1234, 0, 1027, 1024, 0, 0, 1238, 0, - 1025, 0, 1217, 0, 1244, 0, 1246, 1037, 0, 1250, 1049, 0, 1252, 0, 1036, - 0, 1254, 1262, 1038, 0, 1264, 1266, 0, 0, 1268, 0, 1272, 0, 1260, 0, - 1233, 0, 1235, 0, 1107, 1104, 0, 0, 1239, 0, 1105, 0, 1218, 0, 1245, 0, - 1247, 1117, 0, 1251, 1081, 0, 1253, 0, 1116, 0, 1255, 1263, 1118, 0, - 1265, 1267, 0, 0, 1269, 0, 1273, 0, 1261, 0, 1111, 1142, 0, 1143, 0, 0, - 1242, 0, 1243, 0, 1258, 0, 1259, 1570, 1571, 1573, 0, 0, 1572, 0, 1574, - 0, 1730, 0, 1747, 0, 1728, 0, 2345, 0, 2353, 0, 2356, 2507, 2508, 2891, - 2888, 2892, 0, 2964, 0, 0, 3018, 3020, 0, 0, 3019, 0, 3144, 0, 3264, - 3274, 3271, 3272, 0, 0, 3275, 0, 3402, 3404, 0, 0, 3403, 0, 3546, 3548, - 3550, 0, 3549, 4134, 0, 0, 6918, 0, 6920, 0, 6922, 0, 6924, 0, 6926, 0, - 6930, 0, 6971, 0, 6973, 0, 6976, 0, 6977, 0, 6979, 7736, 0, 7737, 0, - 7772, 0, 7773, 0, 7784, 0, 7785, 0, 7852, 0, 0, 7862, 7853, 0, 0, 7863, - 7878, 0, 7879, 0, 7896, 0, 7897, 0, 7938, 7940, 7942, 8064, 7939, 7941, - 7943, 8065, 0, 8066, 0, 8067, 0, 8068, 0, 8069, 0, 8070, 0, 8071, 7946, - 7948, 7950, 8072, 7947, 7949, 7951, 8073, 0, 8074, 0, 8075, 0, 8076, 0, - 8077, 0, 8078, 0, 8079, 7954, 7956, 7955, 7957, 7962, 7964, 7963, 7965, - 7970, 7972, 7974, 8080, 7971, 7973, 7975, 8081, 0, 8082, 0, 8083, 0, - 8084, 0, 8085, 0, 8086, 0, 8087, 7978, 7980, 7982, 8088, 7979, 7981, - 7983, 8089, 0, 8090, 0, 8091, 0, 8092, 0, 8093, 0, 8094, 0, 8095, 7986, - 7988, 7990, 0, 7987, 7989, 7991, 0, 7994, 7996, 7998, 0, 7995, 7997, - 7999, 0, 8002, 8004, 8003, 8005, 8010, 8012, 8011, 8013, 8018, 8020, - 8022, 0, 8019, 8021, 8023, 0, 8027, 8029, 8031, 0, 8034, 8036, 8038, - 8096, 8035, 8037, 8039, 8097, 0, 8098, 0, 8099, 0, 8100, 0, 8101, 0, - 8102, 0, 8103, 8042, 8044, 8046, 8104, 8043, 8045, 8047, 8105, 0, 8106, - 0, 8107, 0, 8108, 0, 8109, 0, 8110, 0, 8111, 0, 8114, 0, 8130, 0, 8178, - 0, 8119, 8141, 8142, 8143, 0, 0, 8135, 0, 8183, 8157, 8158, 8159, 0, 0, - 8602, 0, 8603, 0, 8622, 0, 8653, 0, 8655, 0, 8654, 0, 8708, 0, 8713, 0, - 8716, 0, 8740, 0, 8742, 0, 8769, 0, 8772, 0, 8775, 0, 8777, 0, 8813, 0, - 8802, 0, 8816, 0, 8817, 0, 8820, 0, 8821, 0, 8824, 0, 8825, 0, 8832, 0, - 8833, 0, 8928, 0, 8929, 0, 8836, 0, 8837, 0, 8840, 0, 8841, 0, 8930, 0, - 8931, 0, 8876, 0, 8877, 0, 8878, 0, 8879, 0, 8938, 0, 8939, 0, 8940, 0, - 8941, 12436, 0, 12364, 0, 12366, 0, 12368, 0, 12370, 0, 12372, 0, 12374, - 0, 12376, 0, 12378, 0, 12380, 0, 12382, 0, 12384, 0, 12386, 0, 12389, 0, - 12391, 0, 12393, 0, 12400, 12401, 12403, 12404, 12406, 12407, 12409, - 12410, 12412, 12413, 12446, 0, 12532, 0, 12460, 0, 12462, 0, 12464, 0, - 12466, 0, 12468, 0, 12470, 0, 12472, 0, 12474, 0, 12476, 0, 12478, 0, - 12480, 0, 12482, 0, 12485, 0, 12487, 0, 12489, 0, 12496, 12497, 12499, - 12500, 12502, 12503, 12505, 12506, 12508, 12509, 12535, 0, 12536, 0, - 12537, 0, 12538, 0, 12542, 0, 69786, 0, 69788, 0, 69803, 0, 0, 69934, 0, - 69935, 70475, 70476, 70844, 70843, 70846, 0, 0, 71098, 0, 71099, -}; - diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh index 1dd0b3211e8..eb7776eecbe 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode-emoji-table.hh @@ -7,13 +7,13 @@ * on file with this header: * * # emoji-data.txt - * # Date: 2018-02-07, 07:55:18 GMT - * # © 2018 Unicode®, Inc. + * # Date: 2020-01-28, 20:52:38 GMT + * # © 2020 Unicode®, Inc. * # Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the U.S. and other countries. * # For terms of use, see http://www.unicode.org/terms_of_use.html * # * # Emoji Data for UTS #51 - * # Version: 11.0 + * # Version: 13.0 * # * # For documentation and usage, see http://www.unicode.org/reports/tr51 */ @@ -23,88 +23,56 @@ #include "hb-unicode.hh" - -static const struct hb_unicode_range_t _hb_unicode_emoji_Extended_Pictographic_table[] = +static const uint8_t +_hb_emoji_u8[448] = { - {0x00A9, 0x00A9}, - {0x00AE, 0x00AE}, - {0x203C, 0x203C}, - {0x2049, 0x2049}, - {0x2122, 0x2122}, - {0x2139, 0x2139}, - {0x2194, 0x2199}, - {0x21A9, 0x21AA}, - {0x231A, 0x231B}, - {0x2328, 0x2328}, - {0x2388, 0x2388}, - {0x23CF, 0x23CF}, - {0x23E9, 0x23F3}, - {0x23F8, 0x23FA}, - {0x24C2, 0x24C2}, - {0x25AA, 0x25AB}, - {0x25B6, 0x25B6}, - {0x25C0, 0x25C0}, - {0x25FB, 0x25FE}, - {0x2600, 0x2605}, - {0x2607, 0x2612}, - {0x2614, 0x2685}, - {0x2690, 0x2705}, - {0x2708, 0x2712}, - {0x2714, 0x2714}, - {0x2716, 0x2716}, - {0x271D, 0x271D}, - {0x2721, 0x2721}, - {0x2728, 0x2728}, - {0x2733, 0x2734}, - {0x2744, 0x2744}, - {0x2747, 0x2747}, - {0x274C, 0x274C}, - {0x274E, 0x274E}, - {0x2753, 0x2755}, - {0x2757, 0x2757}, - {0x2763, 0x2767}, - {0x2795, 0x2797}, - {0x27A1, 0x27A1}, - {0x27B0, 0x27B0}, - {0x27BF, 0x27BF}, - {0x2934, 0x2935}, - {0x2B05, 0x2B07}, - {0x2B1B, 0x2B1C}, - {0x2B50, 0x2B50}, - {0x2B55, 0x2B55}, - {0x3030, 0x3030}, - {0x303D, 0x303D}, - {0x3297, 0x3297}, - {0x3299, 0x3299}, - {0x1F000, 0x1F0FF}, - {0x1F10D, 0x1F10F}, - {0x1F12F, 0x1F12F}, - {0x1F16C, 0x1F171}, - {0x1F17E, 0x1F17F}, - {0x1F18E, 0x1F18E}, - {0x1F191, 0x1F19A}, - {0x1F1AD, 0x1F1E5}, - {0x1F201, 0x1F20F}, - {0x1F21A, 0x1F21A}, - {0x1F22F, 0x1F22F}, - {0x1F232, 0x1F23A}, - {0x1F23C, 0x1F23F}, - {0x1F249, 0x1F3FA}, - {0x1F400, 0x1F53D}, - {0x1F546, 0x1F64F}, - {0x1F680, 0x1F6FF}, - {0x1F774, 0x1F77F}, - {0x1F7D5, 0x1F7FF}, - {0x1F80C, 0x1F80F}, - {0x1F848, 0x1F84F}, - {0x1F85A, 0x1F85F}, - {0x1F888, 0x1F88F}, - {0x1F8AE, 0x1F8FF}, - {0x1F90C, 0x1F93A}, - {0x1F93C, 0x1F945}, - {0x1F947, 0x1FFFD}, + 0, 0, 0, 0, 33, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84,118, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 4, 5, 6, 7, 8, 7, 9, 10, 11, 0, + 0, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, + 7, 7, 7, 14, 15, 16, 17, 18, 19, 20, 7, 7, 7, 7, 7, 21, + 7, 7, 7, 7, 22, 23, 7, 7, 7, 24, 7, 14, 0, 25, 0, 26, + 27, 28, 29, 14, 30, 31, 7, 7, 7, 7, 7, 14, 0, 0, 0, 0, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 22, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240, 1, 0, 2, 0, 0, + 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,254, 7, 3, + 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 56, + 159,255,243,255,255,255,255,255,255,255,255,255,255,255,255,255, + 31, 0,255,255,255,255,255,255, 31,255, 3, 0, 0, 0, 8, 0, + 0, 0, 24, 0,120, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 16, 0, 96, 0, 0, 8, 0, 0, 0, 0, + 255,255,255,255,255,255,255,127, 0, 96, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0,240, 1, 64, 0, 0,254, 3, 0,224,255,255, + 255,255,255,255, 31, 0, 0, 0,254,127, 0, 0, 0, 0,252,115, + 0,254,255,255,255,255,255,255,255,255,255,255,255,255,255, 3, + 255,255,255,255,255,255,255, 31,192,255,255,255,255,255,255,255, + 255,127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,240,127, + 0, 0,224,255,255,255,255,127, 0,112, 0, 0, 0, 0, 0, 0, + 0,127, 0,124, 0, 0, 0, 0, 0,127, 0, 0, 0,192,255,255, + 0,240,255,255,255,255,255,243,159,255,255,255,255,255,255,255, }; +static inline unsigned +_hb_emoji_b4 (const uint8_t* a, unsigned i) +{ + return (a[i>>1]>>((i&1u)<<2))&15u; +} +static inline unsigned +_hb_emoji_b1 (const uint8_t* a, unsigned i) +{ + return (a[i>>3]>>((i&7u)<<0))&1u; +} +static inline uint_fast8_t +_hb_emoji_is_Extended_Pictographic (unsigned u) +{ + return u<131069u?_hb_emoji_b1(192+_hb_emoji_u8,((_hb_emoji_u8[64+(((_hb_emoji_b4(_hb_emoji_u8,u>>6>>4))<<4)+((u>>6)&15u))])<<6)+((u)&63u)):0; +} + + #endif /* HB_UNICODE_EMOJI_TABLE_HH */ /* == End of generated table == */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc b/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc index 47e6af647e3..8530289cbad 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode.cc @@ -60,6 +60,7 @@ hb_unicode_combining_class_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, return HB_UNICODE_COMBINING_CLASS_NOT_REORDERED; } +#ifndef HB_DISABLE_DEPRECATED static unsigned int hb_unicode_eastasian_width_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t unicode HB_UNUSED, @@ -67,6 +68,7 @@ hb_unicode_eastasian_width_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, { return 1; } +#endif static hb_unicode_general_category_t hb_unicode_general_category_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, @@ -113,6 +115,7 @@ hb_unicode_decompose_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, } +#ifndef HB_DISABLE_DEPRECATED static unsigned int hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED, hb_codepoint_t u HB_UNUSED, @@ -121,20 +124,23 @@ hb_unicode_decompose_compatibility_nil (hb_unicode_funcs_t *ufuncs HB_UNUSED { return 0; } +#endif - -extern "C" hb_unicode_funcs_t *hb_glib_get_unicode_funcs (); -extern "C" hb_unicode_funcs_t *hb_icu_get_unicode_funcs (); -extern "C" hb_unicode_funcs_t *hb_ucdn_get_unicode_funcs (); +#if !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_GLIB) +#include "hb-glib.h" +#endif +#if !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN) +#include "hb-icu.h" +#endif hb_unicode_funcs_t * hb_unicode_funcs_get_default () { -#if defined(HAVE_UCDN) - return hb_ucdn_get_unicode_funcs (); -#elif defined(HAVE_GLIB) +#if !defined(HB_NO_UNICODE_FUNCS) && !defined(HB_NO_UCD) + return hb_ucd_get_unicode_funcs (); +#elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_GLIB) return hb_glib_get_unicode_funcs (); -#elif defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN) +#elif !defined(HB_NO_UNICODE_FUNCS) && defined(HAVE_ICU) && defined(HAVE_ICU_BUILTIN) return hb_icu_get_unicode_funcs (); #else #define HB_UNICODE_FUNCS_NIL 1 @@ -144,7 +150,7 @@ hb_unicode_funcs_get_default () #if !defined(HB_NO_UNICODE_FUNCS) && defined(HB_UNICODE_FUNCS_NIL) #error "Could not find any Unicode functions implementation, you have to provide your own" -#error "Consider building hb-ucdn.c. If you absolutely want to build without any, check the code." +#error "Consider building hb-ucd.cc. If you absolutely want to build without any, check the code." #endif /** @@ -206,7 +212,7 @@ DEFINE_NULL_INSTANCE (hb_unicode_funcs_t) = hb_unicode_funcs_t * hb_unicode_funcs_get_empty () { - return const_cast (&Null(hb_unicode_funcs_t)); + return const_cast (&Null (hb_unicode_funcs_t)); } /** @@ -425,6 +431,7 @@ hb_unicode_decompose (hb_unicode_funcs_t *ufuncs, return ufuncs->decompose (ab, a, b); } +#ifndef HB_DISABLE_DEPRECATED /** * hb_unicode_decompose_compatibility: * @ufuncs: Unicode functions. @@ -445,8 +452,10 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs, { return ufuncs->decompose_compatibility (u, decomposed); } +#endif +#ifndef HB_NO_OT_SHAPE /* See hb-unicode.hh for details. */ const uint8_t _hb_modified_combining_class[256] = @@ -559,19 +568,19 @@ _hb_modified_combining_class[256] = 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, /* HB_UNICODE_COMBINING_CLASS_INVALID */ }; +#endif /* * Emoji */ +#ifndef HB_NO_EMOJI_SEQUENCES #include "hb-unicode-emoji-table.hh" bool _hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp) { - return hb_bsearch (&cp, _hb_unicode_emoji_Extended_Pictographic_table, - ARRAY_LENGTH (_hb_unicode_emoji_Extended_Pictographic_table), - sizeof (hb_unicode_range_t), - hb_unicode_range_t::cmp); + return _hb_emoji_is_Extended_Pictographic (cp); } +#endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh index 24b03c20184..40f6a5a7f43 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-unicode.hh @@ -42,19 +42,19 @@ extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256]; #define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS \ HB_UNICODE_FUNC_IMPLEMENT (combining_class) \ - HB_UNICODE_FUNC_IMPLEMENT (eastasian_width) \ + HB_IF_NOT_DEPRECATED (HB_UNICODE_FUNC_IMPLEMENT (eastasian_width)) \ HB_UNICODE_FUNC_IMPLEMENT (general_category) \ HB_UNICODE_FUNC_IMPLEMENT (mirroring) \ HB_UNICODE_FUNC_IMPLEMENT (script) \ HB_UNICODE_FUNC_IMPLEMENT (compose) \ HB_UNICODE_FUNC_IMPLEMENT (decompose) \ - HB_UNICODE_FUNC_IMPLEMENT (decompose_compatibility) \ + HB_IF_NOT_DEPRECATED (HB_UNICODE_FUNC_IMPLEMENT (decompose_compatibility)) \ /* ^--- Add new callbacks here */ /* Simple callbacks are those taking a hb_codepoint_t and returning a hb_codepoint_t */ #define HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE \ HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_combining_class_t, combining_class) \ - HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width) \ + HB_IF_NOT_DEPRECATED (HB_UNICODE_FUNC_IMPLEMENT (unsigned int, eastasian_width)) \ HB_UNICODE_FUNC_IMPLEMENT (hb_unicode_general_category_t, general_category) \ HB_UNICODE_FUNC_IMPLEMENT (hb_codepoint_t, mirroring) \ HB_UNICODE_FUNC_IMPLEMENT (hb_script_t, script) \ @@ -89,7 +89,11 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE unsigned int decompose_compatibility (hb_codepoint_t u, hb_codepoint_t *decomposed) { +#ifdef HB_DISABLE_DEPRECATED + unsigned int ret = 0; +#else unsigned int ret = func.decompose_compatibility (this, u, decomposed, user_data.decompose_compatibility); +#endif if (ret == 1 && u == decomposed[0]) { decomposed[0] = 0; return 0; @@ -101,9 +105,6 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE unsigned int modified_combining_class (hb_codepoint_t u) { - /* XXX This hack belongs to the Myanmar shaper. */ - if (unlikely (u == 0x1037u)) u = 0x103Au; - /* XXX This hack belongs to the USE shaper (for Tai Tham): * Reorder SAKOT to ensure it comes after any tone marks. */ if (unlikely (u == 0x1A60u)) return 254; @@ -322,11 +323,11 @@ DECLARE_NULL_INSTANCE (hb_unicode_funcs_t); * * Modify Telugu length marks (ccc=84, ccc=91). * These are the only matras in the main Indic scripts range that have - * a non-zero ccc. That makes them reorder with the Halant that is - * ccc=9. Just zero them, we don't need them in our Indic shaper. + * a non-zero ccc. That makes them reorder with the Halant (ccc=9). + * Assign 4 and 5, which are otherwise unassigned. */ -#define HB_MODIFIED_COMBINING_CLASS_CCC84 0 /* length mark */ -#define HB_MODIFIED_COMBINING_CLASS_CCC91 0 /* ai length mark */ +#define HB_MODIFIED_COMBINING_CLASS_CCC84 4 /* length mark */ +#define HB_MODIFIED_COMBINING_CLASS_CCC91 5 /* ai length mark */ /* Thai * @@ -391,4 +392,7 @@ HB_INTERNAL bool _hb_unicode_is_emoji_Extended_Pictographic (hb_codepoint_t cp); +extern "C" HB_INTERNAL hb_unicode_funcs_t *hb_ucd_get_unicode_funcs (); + + #endif /* HB_UNICODE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh index b438675b9dc..4a7a7a734d1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-vector.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-vector.hh @@ -38,103 +38,141 @@ struct hb_vector_t typedef Type item_t; static constexpr unsigned item_size = hb_static_size (Type); - HB_NO_COPY_ASSIGN_TEMPLATE (hb_vector_t, Type); hb_vector_t () { init (); } + hb_vector_t (const hb_vector_t &o) + { + init (); + alloc (o.length); + hb_copy (o, *this); + } + hb_vector_t (hb_vector_t &&o) + { + allocated = o.allocated; + length = o.length; + arrayZ = o.arrayZ; + o.init (); + } ~hb_vector_t () { fini (); } - unsigned int length; private: int allocated; /* == -1 means allocation failed. */ - Type *arrayZ_; public: + unsigned int length; + public: + Type *arrayZ; void init () { allocated = length = 0; - arrayZ_ = nullptr; + arrayZ = nullptr; } void fini () { - if (arrayZ_) - free (arrayZ_); + free (arrayZ); init (); } void fini_deep () { - Type *array = arrayZ(); unsigned int count = length; for (unsigned int i = 0; i < count; i++) - array[i].fini (); + arrayZ[i].fini (); + fini (); + } + + void reset () { resize (0); } + + hb_vector_t& operator = (const hb_vector_t &o) + { + reset (); + alloc (o.length); + hb_copy (o, *this); + return *this; + } + hb_vector_t& operator = (hb_vector_t &&o) + { fini (); + allocated = o.allocated; + length = o.length; + arrayZ = o.arrayZ; + o.init (); + return *this; } - const Type * arrayZ () const { return arrayZ_; } - Type * arrayZ () { return arrayZ_; } + hb_bytes_t as_bytes () const + { return hb_bytes_t ((const char *) arrayZ, length * item_size); } + + bool operator == (const hb_vector_t &o) const { return as_array () == o.as_array (); } + bool operator != (const hb_vector_t &o) const { return !(*this == o); } + uint32_t hash () const { return as_array ().hash (); } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= length)) return Crap (Type); - return arrayZ()[i]; + return arrayZ[i]; } const Type& operator [] (int i_) const { unsigned int i = (unsigned int) i_; if (unlikely (i >= length)) - return Null(Type); - return arrayZ()[i]; + return Null (Type); + return arrayZ[i]; } - explicit_operator bool () const { return length; } + Type& tail () { return (*this)[length - 1]; } + const Type& tail () const { return (*this)[length - 1]; } + + explicit operator bool () const { return length; } + unsigned get_size () const { return length * item_size; } + + /* Sink interface. */ + template + hb_vector_t& operator << (T&& v) { push (hb_forward (v)); return *this; } - hb_array_t as_array () - { return hb_array (arrayZ(), length); } - hb_array_t as_array () const - { return hb_array (arrayZ(), length); } + hb_array_t< Type> as_array () { return hb_array (arrayZ, length); } + hb_array_t as_array () const { return hb_array (arrayZ, length); } + + /* Iterator. */ + typedef hb_array_t iter_t; + typedef hb_array_t< Type> writer_t; + iter_t iter () const { return as_array (); } + writer_t writer () { return as_array (); } + operator iter_t () const { return iter (); } + operator writer_t () { return writer (); } hb_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count);} + { return as_array ().sub_array (start_offset, count); } hb_sorted_array_t as_sorted_array () - { return hb_sorted_array (arrayZ(), length); } + { return hb_sorted_array (arrayZ, length); } hb_sorted_array_t as_sorted_array () const - { return hb_sorted_array (arrayZ(), length); } - - hb_array_t sorted_sub_array (unsigned int start_offset, unsigned int count) const - { return as_sorted_array ().sorted_sub_array (start_offset, count);} - hb_array_t sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_sorted_array ().sorted_sub_array (start_offset, count);} - hb_array_t sorted_sub_array (unsigned int start_offset, unsigned int count) - { return as_sorted_array ().sorted_sub_array (start_offset, count);} - hb_array_t sorted_sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_sorted_array ().sorted_sub_array (start_offset, count);} + { return hb_sorted_array (arrayZ, length); } - template explicit_operator T * () { return arrayZ(); } - template explicit_operator const T * () const { return arrayZ(); } - operator hb_array_t () { return as_array (); } - operator hb_array_t () const { return as_array (); } + template explicit operator T * () { return arrayZ; } + template explicit operator const T * () const { return arrayZ; } - Type * operator + (unsigned int i) { return arrayZ() + i; } - const Type * operator + (unsigned int i) const { return arrayZ() + i; } + Type * operator + (unsigned int i) { return arrayZ + i; } + const Type * operator + (unsigned int i) const { return arrayZ + i; } Type *push () { if (unlikely (!resize (length + 1))) - return &Crap(Type); - return &arrayZ()[length - 1]; + return &Crap (Type); + return &arrayZ[length - 1]; } - Type *push (const Type& v) + template + Type *push (T&& v) { Type *p = push (); - *p = v; + *p = hb_forward (v); return p; } @@ -161,7 +199,7 @@ struct hb_vector_t (new_allocated < (unsigned) allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type)); if (likely (!overflows)) - new_array = (Type *) realloc (arrayZ_, new_allocated * sizeof (Type)); + new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type)); if (unlikely (!new_array)) { @@ -169,7 +207,7 @@ struct hb_vector_t return false; } - arrayZ_ = new_array; + arrayZ = new_array; allocated = new_allocated; return true; @@ -182,25 +220,24 @@ struct hb_vector_t return false; if (size > length) - memset (arrayZ() + length, 0, (size - length) * sizeof (*arrayZ())); + memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); length = size; return true; } - void pop () + Type pop () { - if (!length) return; - length--; + if (!length) return Null (Type); + return hb_move (arrayZ[--length]); /* Does this move actually work? */ } void remove (unsigned int i) { if (unlikely (i >= length)) return; - Type *array = arrayZ(); - memmove (static_cast (&array[i]), - static_cast (&array[i + 1]), + memmove (static_cast (&arrayZ[i]), + static_cast (&arrayZ[i + 1]), (length - i - 1) * sizeof (Type)); length--; } @@ -215,19 +252,17 @@ struct hb_vector_t template Type *find (T v) { - Type *array = arrayZ(); for (unsigned int i = 0; i < length; i++) - if (array[i] == v) - return &array[i]; + if (arrayZ[i] == v) + return &arrayZ[i]; return nullptr; } template const Type *find (T v) const { - const Type *array = arrayZ(); for (unsigned int i = 0; i < length; i++) - if (array[i] == v) - return &array[i]; + if (arrayZ[i] == v) + return &arrayZ[i]; return nullptr; } @@ -242,19 +277,37 @@ struct hb_vector_t template const Type *lsearch (const T &x, const Type *not_found = nullptr) const { return as_array ().lsearch (x, not_found); } + template + bool lfind (const T &x, unsigned *pos = nullptr) const + { return as_array ().lfind (x, pos); } +}; + +template +struct hb_sorted_vector_t : hb_vector_t +{ + hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->length); } + hb_sorted_array_t as_array () const { return hb_sorted_array (this->arrayZ, this->length); } + + /* Iterator. */ + typedef hb_sorted_array_t const_iter_t; + typedef hb_sorted_array_t< Type> iter_t; + const_iter_t iter () const { return as_array (); } + const_iter_t citer () const { return as_array (); } + iter_t iter () { return as_array (); } + operator iter_t () { return iter (); } + operator const_iter_t () const { return iter (); } template Type *bsearch (const T &x, Type *not_found = nullptr) - { return as_sorted_array ().bsearch (x, not_found); } + { return as_array ().bsearch (x, not_found); } template const Type *bsearch (const T &x, const Type *not_found = nullptr) const - { return as_sorted_array ().bsearch (x, not_found); } + { return as_array ().bsearch (x, not_found); } template bool bfind (const T &x, unsigned int *i = nullptr, - hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, - unsigned int to_store = (unsigned int) -1) const - { return as_sorted_array ().bfind (x, i, not_found, to_store); } + hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE, + unsigned int to_store = (unsigned int) -1) const + { return as_array ().bfind (x, i, not_found, to_store); } }; - #endif /* HB_VECTOR_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-version.h b/src/java.desktop/share/native/libharfbuzz/hb-version.h index 01248794ff8..b9ab5f55f1b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-version.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-version.h @@ -37,10 +37,10 @@ HB_BEGIN_DECLS #define HB_VERSION_MAJOR 2 -#define HB_VERSION_MINOR 3 -#define HB_VERSION_MICRO 1 +#define HB_VERSION_MINOR 7 +#define HB_VERSION_MICRO 2 -#define HB_VERSION_STRING "2.3.1" +#define HB_VERSION_STRING "2.7.2" #define HB_VERSION_ATLEAST(major,minor,micro) \ ((major)*10000+(minor)*100+(micro) <= \ diff --git a/src/java.desktop/share/native/libharfbuzz/hb.h b/src/java.desktop/share/native/libharfbuzz/hb.h index c5e7072fbac..360686ca687 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb.h +++ b/src/java.desktop/share/native/libharfbuzz/hb.h @@ -32,12 +32,14 @@ #include "hb-buffer.h" #include "hb-common.h" #include "hb-deprecated.h" +#include "hb-draw.h" #include "hb-face.h" #include "hb-font.h" #include "hb-map.h" #include "hb-set.h" #include "hb-shape.h" #include "hb-shape-plan.h" +#include "hb-style.h" #include "hb-unicode.h" #include "hb-version.h" diff --git a/src/java.desktop/share/native/libharfbuzz/hb.hh b/src/java.desktop/share/native/libharfbuzz/hb.hh index f2d39068663..8f0ba2ee054 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb.hh @@ -29,8 +29,9 @@ #ifndef HB_HH #define HB_HH + #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC -#if defined(_MSC_VER) +#ifdef _MSC_VER #pragma warning( disable: 4068 ) /* Unknown pragma */ #endif #if defined(__GNUC__) || defined(__clang__) @@ -65,9 +66,12 @@ #pragma GCC diagnostic error "-Wcast-align" #pragma GCC diagnostic error "-Wcast-function-type" #pragma GCC diagnostic error "-Wdelete-non-virtual-dtor" +#pragma GCC diagnostic error "-Wembedded-directive" +#pragma GCC diagnostic error "-Wextra-semi-stmt" #pragma GCC diagnostic error "-Wformat-security" #pragma GCC diagnostic error "-Wimplicit-function-declaration" #pragma GCC diagnostic error "-Winit-self" +#pragma GCC diagnostic error "-Winjected-class-name" #pragma GCC diagnostic error "-Wmissing-braces" #pragma GCC diagnostic error "-Wmissing-declarations" #pragma GCC diagnostic error "-Wmissing-prototypes" @@ -93,13 +97,17 @@ /* Warning. To be investigated if happens. */ #ifndef HB_NO_PRAGMA_GCC_DIAGNOSTIC_WARNING #pragma GCC diagnostic warning "-Wbuiltin-macro-redefined" +#pragma GCC diagnostic warning "-Wdeprecated" +#pragma GCC diagnostic warning "-Wdeprecated-declarations" #pragma GCC diagnostic warning "-Wdisabled-optimization" +#pragma GCC diagnostic warning "-Wdouble-promotion" #pragma GCC diagnostic warning "-Wformat=2" #pragma GCC diagnostic warning "-Wignored-pragma-optimize" #pragma GCC diagnostic warning "-Wlogical-op" #pragma GCC diagnostic warning "-Wmaybe-uninitialized" #pragma GCC diagnostic warning "-Wmissing-format-attribute" #pragma GCC diagnostic warning "-Wundef" +#pragma GCC diagnostic warning "-Wunused-but-set-variable" #endif /* Ignored currently, but should be fixed at some point. */ @@ -120,14 +128,15 @@ #pragma GCC diagnostic ignored "-Wpacked" // Erratic impl in clang #pragma GCC diagnostic ignored "-Wstrict-aliasing" #pragma GCC diagnostic ignored "-Wtype-limits" +#pragma GCC diagnostic ignored "-Wc++11-compat" // only gcc raises it #endif #endif #endif -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif + +#include "hb-config.hh" + /* * Following added based on what AC_USE_SYSTEM_EXTENSIONS adds to @@ -166,20 +175,30 @@ #include "hb-aat.h" #define HB_AAT_H_IN -#include "hb-aat.h" - +#include #include +#include #include #include #include #include -#include #include #include #if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__) +#ifdef __MINGW32_VERSION +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#else #include #endif +#endif + +#ifdef _WIN32 +#include +#include +#endif #define HB_PASTE1(a,b) a##b #define HB_PASTE(a,b) HB_PASTE1(a,b) @@ -187,10 +206,15 @@ /* Compile-time custom allocator support. */ -#if defined(hb_malloc_impl) \ - && defined(hb_calloc_impl) \ - && defined(hb_realloc_impl) \ - && defined(hb_free_impl) +#if !defined(HB_CUSTOM_MALLOC) \ + && defined(hb_malloc_impl) \ + && defined(hb_calloc_impl) \ + && defined(hb_realloc_impl) \ + && defined(hb_free_impl) +#define HB_CUSTOM_MALLOC +#endif + +#ifdef HB_CUSTOM_MALLOC extern "C" void* hb_malloc_impl(size_t size); extern "C" void* hb_calloc_impl(size_t nmemb, size_t size); extern "C" void* hb_realloc_impl(void *ptr, size_t size); @@ -199,14 +223,6 @@ extern "C" void hb_free_impl(void *ptr); #define calloc hb_calloc_impl #define realloc hb_realloc_impl #define free hb_free_impl - -#if defined(hb_memalign_impl) -extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size); -#define posix_memalign hb_memalign_impl -#else -#undef HAVE_POSIX_MEMALIGN -#endif - #endif @@ -214,58 +230,6 @@ extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size); * Compiler attributes */ -#if __cplusplus < 201103L - -#ifndef nullptr -#define nullptr NULL -#endif - -#ifndef constexpr -#define constexpr const -#endif - -#ifndef static_assert -#define static_assert(e, msg) \ - HB_UNUSED typedef int HB_PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1] -#endif // static_assert - -#if defined(__GNUC__) -#if (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)) -#define thread_local __thread -#endif -#else -#define thread_local -#endif - -template -struct _hb_alignof -{ - struct s - { - char c; - T t; - }; - static constexpr size_t value = offsetof (s, t); -}; -#ifndef alignof -#define alignof(x) (_hb_alignof::value) -#endif - -/* https://github.com/harfbuzz/harfbuzz/issues/1127 */ -#ifndef explicit_operator -#define explicit_operator operator -#endif - -#else /* __cplusplus >= 201103L */ - -/* https://github.com/harfbuzz/harfbuzz/issues/1127 */ -#ifndef explicit_operator -#define explicit_operator explicit operator -#endif - -#endif /* __cplusplus < 201103L */ - - #if (defined(__GNUC__) || defined(__clang__)) && defined(__OPTIMIZE__) #define likely(expr) (__builtin_expect (!!(expr), 1)) #define unlikely(expr) (__builtin_expect (!!(expr), 0)) @@ -288,7 +252,7 @@ struct _hb_alignof #define HB_CONST_FUNC #define HB_PRINTF_FUNC(format_idx, arg_idx) #endif -#if defined(__GNUC__) && (__GNUC__ >= 4) +#if defined(__GNUC__) && (__GNUC__ >= 4) || (__clang__) #define HB_UNUSED __attribute__((unused)) #elif defined(_MSC_VER) /* https://github.com/harfbuzz/harfbuzz/issues/635 */ #define HB_UNUSED __pragma(warning(suppress: 4100 4101)) @@ -311,6 +275,13 @@ struct _hb_alignof # endif #endif +/* https://github.com/harfbuzz/harfbuzz/issues/1651 */ +#if defined(__clang__) && __clang_major__ < 10 +#define static_const static +#else +#define static_const static const +#endif + #if defined(__GNUC__) && (__GNUC__ >= 3) #define HB_FUNC __PRETTY_FUNCTION__ #elif defined(_MSC_VER) @@ -357,7 +328,20 @@ struct _hb_alignof # define HB_FALLTHROUGH /* FALLTHROUGH */ #endif -#if defined(__clang__) +/* A tag to enforce use of return value for a function */ +#if __cplusplus >= 201703L +# define HB_NODISCARD [[nodiscard]] +#elif defined(__GNUC__) || defined(__clang__) +# define HB_NODISCARD __attribute__((warn_unused_result)) +#elif defined(_MSC_VER) +# define HB_NODISCARD _Check_return_ +#else +# define HB_NODISCARD +#endif +#define hb_success_t HB_NODISCARD bool + +/* https://github.com/harfbuzz/harfbuzz/issues/1852 */ +#if defined(__clang__) && !(defined(_AIX) && (defined(__IBMCPP__) || defined(__ibmxl__))) /* Disable certain sanitizer errors. */ /* https://github.com/harfbuzz/harfbuzz/issues/1247 */ #define HB_NO_SANITIZE_SIGNED_INTEGER_OVERFLOW __attribute__((no_sanitize("signed-integer-overflow"))) @@ -374,7 +358,7 @@ struct _hb_alignof # undef _WIN32_WINNT # endif # ifndef _WIN32_WINNT -# if !defined(WINAPI_FAMILY) || !(WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) +# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) # define _WIN32_WINNT 0x0600 # endif # endif @@ -388,19 +372,35 @@ struct _hb_alignof # if defined(_WIN32_WCE) /* Some things not defined on Windows CE. */ # define vsnprintf _vsnprintf -# define getenv(Name) nullptr +# ifndef HB_NO_GETENV +# define HB_NO_GETENV +# endif # if _WIN32_WCE < 0x800 -# define setlocale(Category, Locale) "C" -static int errno = 0; /* Use something better? */ +# define HB_NO_SETLOCALE +# define HB_NO_ERRNO +# endif +# elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +# ifndef HB_NO_GETENV +# define HB_NO_GETENV # endif -# elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP) -# define getenv(Name) nullptr # endif # if defined(_MSC_VER) && _MSC_VER < 1900 # define snprintf _snprintf # endif #endif +#ifdef HB_NO_GETENV +#define getenv(Name) nullptr +#endif + +#ifndef HB_NO_ERRNO +# include +#else +static int HB_UNUSED _hb_errno = 0; +# undef errno +# define errno _hb_errno +#endif + #if defined(HAVE_ATEXIT) && !defined(HB_USE_ATEXIT) /* atexit() is only safe to be called from shared libraries on certain * platforms. Whitelist. @@ -459,87 +459,13 @@ static_assert ((sizeof (hb_position_t) == 4), ""); static_assert ((sizeof (hb_mask_t) == 4), ""); static_assert ((sizeof (hb_var_int_t) == 4), ""); - -#if __cplusplus >= 201103L - -/* We only enable these with C++11 or later, since earlier language - * does not allow structs with constructors in unions, and we need - * those. */ - -#define HB_NO_COPY_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#define HB_NO_COPY_ASSIGN_TEMPLATE(TypeName, T) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#define HB_NO_CREATE_COPY_ASSIGN(TypeName) \ - TypeName(); \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) \ - TypeName(); \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) -#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) \ - TypeName(); \ - TypeName(const TypeName&); \ - void operator=(const TypeName&) - -#else /* __cpluspplus >= 201103L */ - -#define HB_NO_COPY_ASSIGN(TypeName) static_assert (true, "") -#define HB_NO_COPY_ASSIGN_TEMPLATE(TypeName, T) static_assert (true, "") -#define HB_NO_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) static_assert (true, "") -#define HB_NO_CREATE_COPY_ASSIGN(TypeName) static_assert (true, "") -#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE(TypeName, T) static_assert (true, "") -#define HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2(TypeName, T1, T2) static_assert (true, "") - -#endif /* __cpluspplus >= 201103L */ - - -/* - * Compiler-assisted vectorization parameters. - */ - -/* - * Disable vectorization for now. To correctly use them, we should - * use posix_memalign() to allocate in hb_vector_t. Otherwise, can - * cause misaligned access. - * - * https://bugs.chromium.org/p/chromium/issues/detail?id=860184 - */ -#if !defined(HB_VECTOR_SIZE) -# define HB_VECTOR_SIZE 0 -#endif - -/* The `vector_size' attribute was introduced in gcc 3.1. */ -#if !defined(HB_VECTOR_SIZE) -# if defined( __GNUC__ ) && ( __GNUC__ >= 4 ) -# define HB_VECTOR_SIZE 128 -# else -# define HB_VECTOR_SIZE 0 -# endif -#endif -static_assert (0 == (HB_VECTOR_SIZE & (HB_VECTOR_SIZE - 1)), "HB_VECTOR_SIZE is not power of 2."); -static_assert (0 == (HB_VECTOR_SIZE % 64), "HB_VECTOR_SIZE is not multiple of 64."); -#if HB_VECTOR_SIZE -typedef uint64_t hb_vector_size_impl_t __attribute__((vector_size (HB_VECTOR_SIZE / 8))); -#else -typedef uint64_t hb_vector_size_impl_t; -#endif - - -/* HB_NDEBUG disables some sanity checks that are very safe to disable and - * should be disabled in production systems. If NDEBUG is defined, enable - * HB_NDEBUG; but if it's desirable that normal assert()s (which are very - * light-weight) to be enabled, then HB_DEBUG can be defined to disable - * the costlier checks. */ -#ifdef NDEBUG -#define HB_NDEBUG 1 -#endif +#define HB_DELETE_COPY_ASSIGN(TypeName) \ + TypeName(const TypeName&) = delete; \ + void operator=(const TypeName&) = delete +#define HB_DELETE_CREATE_COPY_ASSIGN(TypeName) \ + TypeName() = delete; \ + TypeName(const TypeName&) = delete; \ + void operator=(const TypeName&) = delete /* Flags */ @@ -579,47 +505,107 @@ typedef uint64_t hb_vector_size_impl_t; /* Size signifying variable-sized array */ -#define VAR 1 - - -/* fallback for round() */ -static inline double -_hb_round (double x) -{ - if (x >= 0) - return floor (x + 0.5); - else - return ceil (x - 0.5); -} -#if !defined (HAVE_ROUND) && !defined (HAVE_DECL_ROUND) -#define round(x) _hb_round(x) +#ifndef HB_VAR_ARRAY +#define HB_VAR_ARRAY 1 #endif +static inline float +_hb_roundf (float x) { return floorf (x + .5f); } +#define roundf(x) _hb_roundf(x) -/* fallback for posix_memalign() */ -static inline int -_hb_memalign(void **memptr, size_t alignment, size_t size) -{ - if (unlikely (0 != (alignment & (alignment - 1)) || - !alignment || - 0 != (alignment & (sizeof (void *) - 1)))) - return EINVAL; - - char *p = (char *) malloc (size + alignment - 1); - if (unlikely (!p)) - return ENOMEM; +/* Endian swap, used in Windows related backends */ +static inline uint16_t hb_uint16_swap (const uint16_t v) +{ return (v >> 8) | (v << 8); } +static inline uint32_t hb_uint32_swap (const uint32_t v) +{ return (hb_uint16_swap (v) << 16) | hb_uint16_swap (v >> 16); } - size_t off = (size_t) p & (alignment - 1); - if (off) - p += alignment - off; +/* + * Big-endian integers. Here because fundamental. + */ - *memptr = (void *) p; +template struct BEInt; - return 0; -} -#if !defined(posix_memalign) && !defined(HAVE_POSIX_MEMALIGN) -#define posix_memalign _hb_memalign -#endif +template +struct BEInt +{ + public: + BEInt& operator = (Type V) + { + v = V; + return *this; + } + operator Type () const { return v; } + private: uint8_t v; +}; +template +struct BEInt +{ + public: + BEInt& operator = (Type V) + { + v[0] = (V >> 8) & 0xFF; + v[1] = (V ) & 0xFF; + return *this; + } + operator Type () const + { +#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ + defined(__BYTE_ORDER) && \ + (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) + /* Spoon-feed the compiler a big-endian integer with alignment 1. + * https://github.com/harfbuzz/harfbuzz/pull/1398 */ + struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; +#if __BYTE_ORDER == __LITTLE_ENDIAN + return __builtin_bswap16 (((packed_uint16_t *) this)->v); +#else /* __BYTE_ORDER == __BIG_ENDIAN */ + return ((packed_uint16_t *) this)->v; +#endif +#endif + return (v[0] << 8) + + (v[1] ); + } + private: uint8_t v[2]; +}; +template +struct BEInt +{ + public: + BEInt& operator = (Type V) + { + v[0] = (V >> 16) & 0xFF; + v[1] = (V >> 8) & 0xFF; + v[2] = (V ) & 0xFF; + return *this; + } + operator Type () const + { + return (v[0] << 16) + + (v[1] << 8) + + (v[2] ); + } + private: uint8_t v[3]; +}; +template +struct BEInt +{ + public: + BEInt& operator = (Type V) + { + v[0] = (V >> 24) & 0xFF; + v[1] = (V >> 16) & 0xFF; + v[2] = (V >> 8) & 0xFF; + v[3] = (V ) & 0xFF; + return *this; + } + operator Type () const + { + return (v[0] << 24) + + (v[1] << 16) + + (v[2] << 8) + + (v[3] ); + } + private: uint8_t v[4]; +}; /* @@ -630,28 +616,18 @@ _hb_memalign(void **memptr, size_t alignment, size_t size) #define HB_SCRIPT_MYANMAR_ZAWGYI ((hb_script_t) HB_TAG ('Q','a','a','g')) -/* Some really basic things everyone wants. */ -template struct hb_remove_const { typedef T value; }; -template struct hb_remove_const { typedef T value; }; -#define hb_remove_const(T) hb_remove_const::value -template struct hb_remove_reference { typedef T value; }; -template struct hb_remove_reference { typedef T value; }; -#define hb_remove_reference(T) hb_remove_reference::value -template struct hb_remove_pointer { typedef T value; }; -template struct hb_remove_pointer { typedef T value; }; -#define hb_remove_pointer(T) hb_remove_pointer::value - - /* Headers we include for everyone. Keep topologically sorted by dependency. * They express dependency amongst themselves, but no other file should include * them directly.*/ -#include "hb-atomic.hh" +#include "hb-meta.hh" #include "hb-mutex.hh" -#include "hb-null.hh" -#include "hb-dsalgs.hh" // Requires: hb-null -#include "hb-iter.hh" // Requires: hb-null -#include "hb-debug.hh" // Requires: hb-atomic hb-dsalgs -#include "hb-array.hh" // Requires: hb-dsalgs hb-iter hb-null +#include "hb-number.hh" +#include "hb-atomic.hh" // Requires: hb-meta +#include "hb-null.hh" // Requires: hb-meta +#include "hb-algs.hh" // Requires: hb-meta hb-null hb-number +#include "hb-iter.hh" // Requires: hb-algs hb-meta +#include "hb-debug.hh" // Requires: hb-algs hb-atomic +#include "hb-array.hh" // Requires: hb-algs hb-iter hb-null #include "hb-vector.hh" // Requires: hb-array hb-null #include "hb-object.hh" // Requires: hb-atomic hb-mutex hb-vector diff --git a/src/java.desktop/share/native/libjsound/MidiOutDevice.c b/src/java.desktop/share/native/libjsound/MidiOutDevice.c index 7411564cc5f..3738eba9381 100644 --- a/src/java.desktop/share/native/libjsound/MidiOutDevice.c +++ b/src/java.desktop/share/native/libjsound/MidiOutDevice.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -133,7 +133,7 @@ Java_com_sun_media_sound_MidiOutDevice_nSendLongMessage(JNIEnv* e, jobject thisO } /* "continuation" sysex messages start with F7 (instead of F0), but are sent without the F7. */ - if (data[0] == 0xF7) { + if (data[0] == 0xF7 && size > 1) { data++; size--; } diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c index 2d92f85ec5c..39f17a985af 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c @@ -708,7 +708,7 @@ static int gtk3_unload() */ static void flush_gtk_event_loop() { - while((*fp_g_main_context_iteration)(NULL)); + while((*fp_g_main_context_iteration)(NULL, FALSE)); } /* diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h index 51fd7778484..19a1e2ddaf5 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h +++ b/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.h @@ -401,7 +401,7 @@ static void (*fp_g_object_set)(gpointer object, const gchar *first_property_name, ...); -static gboolean (*fp_g_main_context_iteration)(GMainContext *context); +static gboolean (*fp_g_main_context_iteration)(GMainContext *context, gboolean may_block); static gboolean (*fp_g_str_has_prefix)(const gchar *str, const gchar *prefix); static gchar** (*fp_g_strsplit)(const gchar *string, const gchar *delimiter, gint max_tokens); diff --git a/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c b/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c index 7bfd0d8b860..b507ae7a4c5 100644 --- a/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c +++ b/src/java.desktop/unix/native/libawt_xawt/awt/swing_GTKEngine.c @@ -350,10 +350,8 @@ Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeFinishPainting( JNIEXPORT void JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1switch_1theme( JNIEnv *env, jobject this) { - // Note that flush_gtk_event_loop takes care of locks (7053002) - gtk->gdk_threads_enter(); + // Note that gtk->flush_event_loop takes care of locks (7053002), gdk_threads_enter/gdk_threads_leave should not be used. gtk->flush_event_loop(); - gtk->gdk_threads_leave(); } /* diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonListener.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonListener.java index a78298cada2..11b0a8de24e 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonListener.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,23 +23,13 @@ * questions. */ - package com.sun.java.swing.plaf.windows; -import java.beans.PropertyChangeEvent; - -import javax.swing.*; -import javax.swing.plaf.basic.*; +import javax.swing.AbstractButton; +import javax.swing.plaf.basic.BasicButtonListener; /** - * Button Listener - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. + * Button Listener. * * @author Rich Schiavi */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java index 89a2a18e115..6b3d9b004bf 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,31 +25,38 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.plaf.basic.*; -import javax.swing.border.*; -import javax.swing.plaf.*; -import javax.swing.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; + +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JRadioButton; +import javax.swing.JToolBar; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.CompoundBorder; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicButtonUI; +import javax.swing.plaf.basic.BasicGraphicsUtils; -import java.awt.*; - -import static com.sun.java.swing.plaf.windows.TMSchema.*; -import static com.sun.java.swing.plaf.windows.TMSchema.Part.*; -import static com.sun.java.swing.plaf.windows.XPStyle.Skin; import sun.awt.AppContext; +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.State; +import static com.sun.java.swing.plaf.windows.XPStyle.Skin; /** * Windows button. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Jeff Dinkins - * */ public class WindowsButtonUI extends BasicButtonUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java index 99966cb210e..c7007bec3db 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,24 +25,21 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicCheckBoxMenuItemUI; import com.sun.java.swing.plaf.windows.TMSchema.Part; import com.sun.java.swing.plaf.windows.TMSchema.State; - /** * Windows check box menu item. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsCheckBoxMenuItemUI extends BasicCheckBoxMenuItemUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java index 91c919c8711..65b1131a351 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsCheckBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,15 @@ package com.sun.java.swing.plaf.windows; -import sun.awt.AppContext; - -import javax.swing.plaf.basic.*; -import javax.swing.*; -import javax.swing.plaf.*; +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; -import java.awt.*; +import sun.awt.AppContext; /** * Windows check box. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Jeff Dinkins */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java index 5141fa399da..6a2c9eeae31 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsClassicLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,13 +27,6 @@ /** * Implements the Windows95/98/ME/NT/2000 Look and Feel. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @since 1.5 */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java index 0de8f38d43e..13f7e6e7d47 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsComboBoxUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,38 +25,56 @@ package com.sun.java.swing.plaf.windows; -import java.beans.PropertyChangeListener; +import java.awt.Color; +import java.awt.Component; +import java.awt.ComponentOrientation; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; +import java.awt.LayoutManager; +import java.awt.Rectangle; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import java.beans.PropertyChangeEvent; -import javax.swing.plaf.basic.*; -import javax.swing.plaf.*; -import javax.swing.border.*; -import javax.swing.*; -import java.awt.event.*; -import java.awt.*; +import java.beans.PropertyChangeListener; -import static com.sun.java.swing.plaf.windows.TMSchema.Part; -import static com.sun.java.swing.plaf.windows.TMSchema.State; -import static com.sun.java.swing.plaf.windows.XPStyle.Skin; +import javax.swing.ButtonModel; +import javax.swing.ComboBoxEditor; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.ListCellRenderer; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicComboBoxEditor; +import javax.swing.plaf.basic.BasicComboBoxRenderer; +import javax.swing.plaf.basic.BasicComboBoxUI; +import javax.swing.plaf.basic.BasicComboPopup; +import javax.swing.plaf.basic.ComboPopup; +import com.sun.java.swing.plaf.windows.WindowsBorders.DashedBorder; import sun.swing.DefaultLookup; import sun.swing.StringUIClientPropertyKey; -import com.sun.java.swing.plaf.windows.WindowsBorders.DashedBorder; +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.State; +import static com.sun.java.swing.plaf.windows.XPStyle.Skin; /** * Windows combo box. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Tom Santos * @author Igor Kushnirskiy */ - public class WindowsComboBoxUI extends BasicComboBoxUI { private static final MouseListener rolloverListener = diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java index 38618a82150..564ae5b9f71 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopIconUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,16 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; -import javax.swing.*; -import javax.swing.border.*; - +import java.awt.BorderLayout; +import java.awt.Dimension; +import javax.swing.JComponent; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicDesktopIconUI; /** * Windows icon for a minimized window on the desktop. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsDesktopIconUI extends BasicDesktopIconUI { private int width; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java index f9949fce4ca..3ceea2d31dc 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsDesktopPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,12 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.*; -import javax.swing.plaf.basic.*; +import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; -import java.awt.event.*; +import javax.swing.plaf.basic.BasicDesktopPaneUI; /** * Windows desktop pane. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author David Kloba */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java index 0e2a1bcdc1b..2f5c45633d4 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsEditorPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,21 +25,13 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; -import javax.swing.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicEditorPaneUI; import javax.swing.text.Caret; - /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsEditorPaneUI extends BasicEditorPaneUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java index 3d8b523a238..86a587aabd3 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsIconFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,28 +25,39 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.*; -import javax.swing.plaf.ButtonUI; -import javax.swing.plaf.UIResource; - -import java.awt.*; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.Stroke; import java.io.Serializable; -import static com.sun.java.swing.plaf.windows.TMSchema.*; -import static com.sun.java.swing.plaf.windows.XPStyle.Skin; +import javax.swing.AbstractButton; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.JCheckBox; +import javax.swing.JCheckBoxMenuItem; +import javax.swing.JInternalFrame; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.plaf.ButtonUI; +import javax.swing.plaf.UIResource; import sun.swing.MenuItemCheckIconFactory; import sun.swing.SwingUtilities2; +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.State; +import static com.sun.java.swing.plaf.windows.XPStyle.Skin; + /** * Factory object that can vend Icons appropriate for the Windows {@literal L & F}. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author David Kloba * @author Georges Saab diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java index 66b038d2ec5..19169f6e424 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsInternalFrameUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,25 +25,25 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; -import java.beans.*; -import javax.swing.*; -import javax.swing.border.*; -import javax.swing.plaf.basic.*; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; + +import javax.swing.DesktopManager; +import javax.swing.JComponent; +import javax.swing.JInternalFrame; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.border.AbstractBorder; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicInternalFrameUI; -import static com.sun.java.swing.plaf.windows.TMSchema.*; +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsInternalFrameUI extends BasicInternalFrameUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java index 0f3c4562a55..93f69f49c63 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLabelUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,31 +25,20 @@ package com.sun.java.swing.plaf.windows; -import sun.swing.SwingUtilities2; -import sun.awt.AppContext; - import java.awt.Color; import java.awt.Graphics; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.UIManager; - import javax.swing.plaf.ComponentUI; - import javax.swing.plaf.basic.BasicLabelUI; - +import sun.awt.AppContext; +import sun.swing.SwingUtilities2; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsLabelUI extends BasicLabelUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java index d3ab14f8d00..91a5732fc9e 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsLookAndFeel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,58 +40,75 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; import java.awt.image.BufferedImage; +import java.awt.image.FilteredImageSource; import java.awt.image.ImageFilter; import java.awt.image.ImageProducer; -import java.awt.image.FilteredImageSource; import java.awt.image.RGBImageFilter; +import java.security.AccessController; -import javax.swing.plaf.*; -import javax.swing.*; -import javax.swing.plaf.basic.*; -import javax.swing.border.*; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.BorderFactory; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JComponent; +import javax.swing.JRootPane; +import javax.swing.JTextField; +import javax.swing.LayoutStyle; +import javax.swing.LookAndFeel; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingConstants; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.border.Border; +import javax.swing.border.EmptyBorder; +import javax.swing.plaf.BorderUIResource; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.FontUIResource; +import javax.swing.plaf.InsetsUIResource; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicBorders; +import javax.swing.plaf.basic.BasicLookAndFeel; import javax.swing.text.DefaultEditorKit; -import static javax.swing.UIDefaults.LazyValue; - -import java.awt.Font; -import java.awt.Color; -import java.awt.event.ActionEvent; - -import java.security.AccessController; -import sun.awt.SunToolkit; +import com.sun.java.swing.plaf.windows.WindowsIconFactory.VistaMenuItemCheckIconFactory; import sun.awt.OSInfo; +import sun.awt.SunToolkit; import sun.awt.shell.ShellFolder; import sun.font.FontUtilities; import sun.security.action.GetPropertyAction; - import sun.swing.DefaultLayoutStyle; import sun.swing.ImageIconUIResource; +import sun.swing.StringUIClientPropertyKey; import sun.swing.SwingAccessor; -import sun.swing.icon.SortArrowIcon; import sun.swing.SwingUtilities2; -import sun.swing.StringUIClientPropertyKey; +import sun.swing.icon.SortArrowIcon; import sun.swing.plaf.windows.ClassicSortArrowIcon; -import static com.sun.java.swing.plaf.windows.TMSchema.*; +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.Prop; +import static com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; - -import com.sun.java.swing.plaf.windows.WindowsIconFactory.VistaMenuItemCheckIconFactory; +import static javax.swing.UIDefaults.LazyValue; /** * Implements the Windows95/98/NT/2000 Look and Feel. * UI classes not implemented specifically for Windows will * default to those implemented in Basic. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. - * - * @author unattributed */ @SuppressWarnings("serial") // Superclass is not serializable across versions public class WindowsLookAndFeel extends BasicLookAndFeel diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java index af73b1948f0..23df6b67849 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,32 +25,35 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.plaf.basic.*; -import javax.swing.*; -import javax.swing.plaf.ActionMapUIResource; -import javax.swing.plaf.ComponentUI; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.HierarchyEvent; import java.awt.event.HierarchyListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; -import java.awt.event.WindowStateListener; -import java.awt.*; +import javax.swing.AbstractAction; +import javax.swing.ActionMap; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JRootPane; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.SwingUtilities; +import javax.swing.plaf.ActionMapUIResource; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicMenuBarUI; -import com.sun.java.swing.plaf.windows.TMSchema.*; -import com.sun.java.swing.plaf.windows.XPStyle.*; +import com.sun.java.swing.plaf.windows.TMSchema.Part; +import com.sun.java.swing.plaf.windows.TMSchema.State; +import com.sun.java.swing.plaf.windows.XPStyle.Skin; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsMenuBarUI extends BasicMenuBarUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java index 3b895ba4d4f..09fad9c98a6 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,33 +25,34 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; +import java.awt.Color; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicMenuItemUI; + +import com.sun.java.swing.plaf.windows.TMSchema.Part; +import com.sun.java.swing.plaf.windows.TMSchema.State; +import com.sun.java.swing.plaf.windows.XPStyle.Skin; import sun.swing.MenuItemCheckIconFactory; import sun.swing.MenuItemLayoutHelper; import sun.swing.SwingUtilities2; -import com.sun.java.swing.plaf.windows.TMSchema.*; -import com.sun.java.swing.plaf.windows.XPStyle.*; - /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Igor Kushnirskiy */ - public class WindowsMenuItemUI extends BasicMenuItemUI { /** * The instance of {@code PropertyChangeListener}. diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java index 803952b8011..4195b4e85ca 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,26 +25,30 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; import java.awt.event.MouseEvent; +import javax.swing.ButtonModel; +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.MenuElement; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.MouseInputListener; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicMenuUI; -import javax.swing.event.MouseInputListener; -import javax.swing.*; import com.sun.java.swing.plaf.windows.TMSchema.Part; import com.sun.java.swing.plaf.windows.TMSchema.State; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsMenuUI extends BasicMenuUI { protected Integer menuBarHeight; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java index b163d88d577..2755cc76c96 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsOptionPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,10 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; - - +import javax.swing.plaf.basic.BasicOptionPaneUI; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsOptionPaneUI extends BasicOptionPaneUI { } diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java index aef2a218323..baf0997ceff 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPasswordFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,13 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; -import javax.swing.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicPasswordFieldUI; import javax.swing.text.Caret; - - /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsPasswordFieldUI extends BasicPasswordFieldUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java index 06dde67d7a9..87e89fca3dc 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupMenuUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,31 +28,31 @@ import java.awt.Component; import java.awt.Graphics; import java.awt.Insets; -import java.awt.KeyEventPostProcessor; -import java.awt.KeyboardFocusManager; import java.awt.Window; -import java.awt.event.KeyEvent; -import javax.swing.*; -import javax.swing.event.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; -import sun.swing.StringUIClientPropertyKey; +import javax.swing.JComponent; +import javax.swing.JPopupMenu; +import javax.swing.JRootPane; +import javax.swing.MenuElement; +import javax.swing.MenuSelectionManager; +import javax.swing.Popup; +import javax.swing.PopupFactory; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicPopupMenuUI; import com.sun.java.swing.plaf.windows.TMSchema.Part; import com.sun.java.swing.plaf.windows.TMSchema.State; import com.sun.java.swing.plaf.windows.XPStyle.Skin; +import sun.swing.StringUIClientPropertyKey; + import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Igor Kushnirskiy */ @@ -108,6 +108,7 @@ public void stateChanged(ChangeEvent ev) { WindowsGraphicsUtils.repaintMnemonicsInWindow(win); } } + repaintRoot = null; } else { Component c = (Component)path[0]; if (c instanceof JPopupMenu) c = ((JPopupMenu)c).getInvoker(); diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupWindow.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupWindow.java index 89ac13b66c4..bf01850297b 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupWindow.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsPopupWindow.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,11 +22,13 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package com.sun.java.swing.plaf.windows; -import javax.swing.JWindow; -import java.awt.Window; import java.awt.Graphics; +import java.awt.Window; + +import javax.swing.JWindow; /** * A class which tags a window with a particular semantic usage, @@ -39,13 +41,6 @@ * Note that support for transition effects may be supported with a * different mechanism in the future and so this class is * package-private and targeted for Swing implementation use only. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Amy Fowler */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java index 45947fc2b7e..e53cc798e61 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsProgressBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,24 +25,28 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.plaf.basic.*; -import javax.swing.plaf.*; -import javax.swing.*; -import java.awt.*; - -import static com.sun.java.swing.plaf.windows.TMSchema.*; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Rectangle; + +import javax.swing.JComponent; +import javax.swing.JProgressBar; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicProgressBarUI; + +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.Prop; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; - /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Michael C. Albers */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java index cce34eb9a65..584a0f1622b 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonMenuItemUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,21 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; -import javax.swing.*; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Rectangle; + +import javax.swing.ButtonModel; +import javax.swing.JComponent; +import javax.swing.JMenuItem; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicRadioButtonMenuItemUI; import com.sun.java.swing.plaf.windows.TMSchema.Part; import com.sun.java.swing.plaf.windows.TMSchema.State; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsRadioButtonMenuItemUI extends BasicRadioButtonMenuItemUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java index 36b5413e9bb..dd0a93c95a1 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsRadioButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,24 +25,23 @@ package com.sun.java.swing.plaf.windows; -import sun.awt.AppContext; - -import javax.swing.plaf.basic.*; -import javax.swing.*; -import javax.swing.plaf.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; -import java.awt.*; +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicGraphicsUtils; +import javax.swing.plaf.basic.BasicRadioButtonUI; +import sun.awt.AppContext; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsRadioButtonUI extends BasicRadioButtonUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java index f6f1bcf15b9..a3dd04362b9 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollBarUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,28 +25,35 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; -import java.awt.event.*; -import java.awt.image.*; -import java.lang.ref.*; -import java.util.*; -import javax.swing.plaf.basic.*; -import javax.swing.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.MouseEvent; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; +import java.awt.image.IndexColorModel; +import java.lang.ref.WeakReference; +import java.util.HashMap; + +import javax.swing.ButtonModel; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicArrowButton; +import javax.swing.plaf.basic.BasicScrollBarUI; -import static com.sun.java.swing.plaf.windows.TMSchema.*; +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.Prop; +import static com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; - /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsScrollBarUI extends BasicScrollBarUI { private Grid thumbGrid; diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java index 86e5a0c9c86..6c89eabc894 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsScrollPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,10 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.plaf.basic.*; -import javax.swing.*; - - +import javax.swing.plaf.basic.BasicScrollPaneUI; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsScrollPaneUI extends BasicScrollPaneUI {} diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java index 1bae3f8f441..ceaf878cbca 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSliderUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,26 +25,24 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; import java.awt.event.MouseEvent; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; -import javax.swing.*; +import javax.swing.JComponent; +import javax.swing.JSlider; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSliderUI; -import static com.sun.java.swing.plaf.windows.TMSchema.*; +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.Prop; +import static com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; - /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsSliderUI extends BasicSliderUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java index 327162e62bf..04eeb726f90 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneDivider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,16 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; -import javax.swing.JSplitPane; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; + import javax.swing.UIManager; -import javax.swing.plaf.basic.BasicSplitPaneUI; import javax.swing.plaf.basic.BasicSplitPaneDivider; - +import javax.swing.plaf.basic.BasicSplitPaneUI; /** * Divider used for Windows split pane. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Jeff Dinkins */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java index 3b85bbe660c..9305e46c36f 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsSplitPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,23 +25,13 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.plaf.basic.*; -import javax.swing.*; - -import javax.swing.plaf.basic.BasicSplitPaneUI; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicSplitPaneDivider; -import javax.swing.plaf.*; - +import javax.swing.plaf.basic.BasicSplitPaneUI; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsSplitPaneUI extends BasicSplitPaneUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java index eb8080ba3c9..9b4e22102eb 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTabbedPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,28 +25,28 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; - -import javax.swing.plaf.basic.*; -import javax.swing.plaf.*; -import javax.swing.*; -import java.util.Set; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.KeyboardFocusManager; +import java.awt.Rectangle; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; import java.util.HashSet; -import java.awt.event.*; +import java.util.Set; -import static com.sun.java.swing.plaf.windows.TMSchema.*; -import static com.sun.java.swing.plaf.windows.XPStyle.Skin; +import javax.swing.JComponent; +import javax.swing.KeyStroke; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTabbedPaneUI; +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.State; +import static com.sun.java.swing.plaf.windows.XPStyle.Skin; /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsTabbedPaneUI extends BasicTabbedPaneUI { /** diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java index ed8f90d9847..6aca81225ea 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextAreaUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,22 +25,13 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; -import javax.swing.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTextAreaUI; import javax.swing.text.Caret; - - /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsTextAreaUI extends BasicTextAreaUI { /** diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java index 4e5b3d6c1ae..be3e6276161 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextFieldUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,17 +25,23 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; -import java.awt.event.*; -import java.beans.PropertyChangeEvent; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.BasicTextFieldUI; -import javax.swing.text.*; -import javax.swing.*; -import javax.swing.plaf.UIResource; -import sun.swing.DefaultLookup; - +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import javax.swing.BoundedRangeModel; +import javax.swing.JComponent; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.TextUI; +import javax.swing.plaf.UIResource; +import javax.swing.plaf.basic.BasicTextFieldUI; +import javax.swing.text.BadLocationException; +import javax.swing.text.Caret; +import javax.swing.text.DefaultCaret; +import javax.swing.text.Highlighter; +import javax.swing.text.Position; /** * Provides the Windows look and feel for a text field. This @@ -53,13 +59,6 @@ *

  • Ctrl-left-arrow and ctrl-right-arrow act like home and * end respectively. * - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Timothy Prinzing */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java index f17b2c49599..372563f74f4 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextPaneUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 1998, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,21 +25,13 @@ package com.sun.java.swing.plaf.windows; -import javax.swing.plaf.*; -import javax.swing.plaf.basic.*; -import javax.swing.*; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTextPaneUI; import javax.swing.text.Caret; - /** * Windows rendition of the component. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public class WindowsTextPaneUI extends BasicTextPaneUI { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextUI.java index 58e9dfe5dbf..b73b38385f2 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTextUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,21 +29,22 @@ import java.awt.Graphics; import java.awt.Rectangle; import java.awt.Shape; -import javax.swing.plaf.basic.*; -import javax.swing.*; + import javax.swing.plaf.TextUI; import javax.swing.plaf.UIResource; -import javax.swing.text.*; +import javax.swing.plaf.basic.BasicTextUI; +import javax.swing.text.BadLocationException; +import javax.swing.text.Caret; +import javax.swing.text.DefaultCaret; +import javax.swing.text.DefaultHighlighter; +import javax.swing.text.Highlighter; +import javax.swing.text.JTextComponent; +import javax.swing.text.LayeredHighlighter; +import javax.swing.text.Position; +import javax.swing.text.View; /** * Windows text rendering. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ public abstract class WindowsTextUI extends BasicTextUI { /** diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java index afbc825fb20..feee0c0aaef 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsToggleButtonUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,27 +25,23 @@ package com.sun.java.swing.plaf.windows; -import sun.awt.AppContext; - -import javax.swing.plaf.basic.*; -import javax.swing.border.*; -import javax.swing.plaf.*; -import javax.swing.*; - -import java.awt.*; -import java.beans.PropertyChangeEvent; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Rectangle; +import javax.swing.AbstractButton; +import javax.swing.JComponent; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicGraphicsUtils; +import javax.swing.plaf.basic.BasicToggleButtonUI; +import sun.awt.AppContext; /** * A Windows toggle button. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Jeff Dinkins */ diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java index 8849b786f6f..5bef0e075a4 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/WindowsTreeUI.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,31 +25,26 @@ package com.sun.java.swing.plaf.windows; -import java.awt.*; -import java.awt.event.*; - -import java.io.*; -import java.util.*; - -import javax.swing.plaf.basic.*; -import javax.swing.*; -import javax.swing.plaf.*; - -import javax.swing.tree.*; - -import static com.sun.java.swing.plaf.windows.TMSchema.*; +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Rectangle; +import java.io.Serializable; + +import javax.swing.Icon; +import javax.swing.JComponent; +import javax.swing.JTree; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicTreeUI; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.TreeCellRenderer; + +import static com.sun.java.swing.plaf.windows.TMSchema.Part; +import static com.sun.java.swing.plaf.windows.TMSchema.State; import static com.sun.java.swing.plaf.windows.XPStyle.Skin; - /** * A Windows tree. - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. * * @author Scott Violet */ @@ -118,14 +113,7 @@ protected TreeCellRenderer createDefaultCellRenderer() { } /** - * The minus sign button icon - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. + * The minus sign button icon. */ @SuppressWarnings("serial") // Same-version serialization only public static class ExpandedIcon implements Icon, Serializable { @@ -172,13 +160,6 @@ public int getIconHeight() { /** * The plus sign button icon - *

    - * Warning: - * Serialized objects of this class will not be compatible with - * future Swing releases. The current serialization support is appropriate - * for short term storage or RMI between applications running the same - * version of Swing. A future release of Swing will provide support for - * long term persistence. */ @SuppressWarnings("serial") // Superclass is not serializable across versions public static class CollapsedIcon extends ExpandedIcon { diff --git a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/XPStyle.java b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/XPStyle.java index 2c60209186f..71bb48a9a16 100644 --- a/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/XPStyle.java +++ b/src/java.desktop/windows/classes/com/sun/java/swing/plaf/windows/XPStyle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -593,8 +593,7 @@ void paintSkin(Graphics g, int dx, int dy, int dw, int dh, State state) { if (XPStyle.getXP() == null) { return; } - if (ThemeReader.isGetThemeTransitionDurationDefined() - && component instanceof JComponent + if (component instanceof JComponent && SwingUtilities.getAncestorOfClass(CellRendererPane.class, component) == null) { AnimationController.paintSkin((JComponent) component, this, diff --git a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java index b4962f2a5d7..52a36786064 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32GraphicsDevice.java @@ -467,7 +467,7 @@ public synchronized void setDisplayMode(DisplayMode dm) { // display mode Rectangle screenBounds = getDefaultConfiguration().getBounds(); w.setBounds(screenBounds.x, screenBounds.y, - dm.getWidth(), dm.getHeight()); + screenBounds.width, screenBounds.height); // Note: no call to replaceSurfaceData is required here since // replacement will be caused by an upcoming display change event } else { diff --git a/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java b/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java index 167d4d5b910..482a92fd885 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,13 +35,6 @@ import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; -/* !!!! WARNING !!!! - * This class has to be in sync with - * src/solaris/classes/sun/awt/windows/ThemeReader.java - * while we continue to build WinL&F on solaris - */ - - /** * Implements Theme Support for Windows XP. * @@ -299,8 +292,6 @@ public static long getThemeTransitionDuration(String widget, int part, } } - public static native boolean isGetThemeTransitionDurationDefined(); - private static native Insets getThemeBackgroundContentMargins(long theme, int part, int state, int boundingWidth, int boundingHeight); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java index d8114aed453..c07d116abfb 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WComponentPeer.java @@ -533,7 +533,11 @@ public void run() { @Override public boolean updateGraphicsData(GraphicsConfiguration gc) { + var old = getGraphicsConfiguration().getDefaultTransform(); winGraphicsConfig = (Win32GraphicsConfig)gc; + if (gc != null && !old.equals(gc.getDefaultTransform())) { + syncBounds(); // the bounds of the peer depend on the DPI + } try { replaceSurfaceData(); } catch (InvalidPipeException e) { @@ -542,6 +546,14 @@ public boolean updateGraphicsData(GraphicsConfiguration gc) { return false; } + /** + * Make sure that the native peer's coordinates are in sync with the target. + */ + void syncBounds() { + Rectangle r = ((Component) target).getBounds(); + setBounds(r.x, r.y, r.width, r.height, SET_BOUNDS); + } + //This will return null for Components not yet added to a Container @Override public ColorModel getColorModel() { diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDialogPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WDialogPeer.java index ea4fc4aaa41..930064d5981 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDialogPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDialogPeer.java @@ -36,6 +36,8 @@ import sun.awt.AWTAccessor; import sun.awt.im.InputMethodManager; +import static sun.java2d.SunGraphicsEnvironment.toUserSpace; + final class WDialogPeer extends WWindowPeer implements DialogPeer { // Toolkit & peer internals @@ -117,8 +119,8 @@ public Dimension getMinimumSize() { if (((Dialog)target).isUndecorated()) { return super.getMinimumSize(); } - return new Dimension(scaleDownX(getSysMinWidth()), - scaleDownY(getSysMinHeight())); + return toUserSpace(getGraphicsConfiguration(), + getSysMinWidth(), getSysMinHeight()); } @Override diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java index eaa830fc8af..8671f25f308 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WFramePeer.java @@ -38,7 +38,9 @@ import sun.awt.im.InputMethodManager; import sun.security.action.GetPropertyAction; -import static sun.java2d.SunGraphicsEnvironment.convertToDeviceSpace; +import static sun.java2d.SunGraphicsEnvironment.getGCDeviceBounds; +import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs; +import static sun.java2d.SunGraphicsEnvironment.toUserSpace; class WFramePeer extends WWindowPeer implements FramePeer { @@ -97,10 +99,9 @@ public final void setMaximizedBounds(Rectangle b) { */ private Rectangle adjustMaximizedBounds(Rectangle bounds) { // All calculations should be done in the device space - bounds = convertToDeviceSpace(bounds); - + bounds = toDeviceSpaceAbs(bounds); GraphicsConfiguration gc = getGraphicsConfiguration(); - Rectangle currentDevBounds = convertToDeviceSpace(gc, gc.getBounds()); + Rectangle currentDevBounds = getGCDeviceBounds(gc); // Prepare data for WM_GETMINMAXINFO message. // ptMaxPosition should be in coordinate system of the current monitor, // not the main monitor, or monitor on which we maximize the window. @@ -148,13 +149,13 @@ public void reshape(int x, int y, int width, int height) { @Override public final Dimension getMinimumSize() { + GraphicsConfiguration gc = getGraphicsConfiguration(); Dimension d = new Dimension(); if (!((Frame)target).isUndecorated()) { - d.setSize(scaleDownX(getSysMinWidth()), - scaleDownY(getSysMinHeight())); + d.setSize(toUserSpace(gc, getSysMinWidth(), getSysMinHeight())); } - if (((Frame)target).getMenuBar() != null) { - d.height += scaleDownY(getSysMenuHeight()); + if (((Frame) target).getMenuBar() != null) { + d.height += toUserSpace(gc, 0, getSysMenuHeight()).height; } return d; } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WRobotPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WRobotPeer.java index 4d17500e079..ad924dd6e1f 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WRobotPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WRobotPeer.java @@ -29,14 +29,14 @@ import java.awt.Rectangle; import java.awt.peer.RobotPeer; -import sun.java2d.SunGraphicsEnvironment; +import static sun.java2d.SunGraphicsEnvironment.toDeviceSpaceAbs; final class WRobotPeer implements RobotPeer { public native void mouseMoveImpl(int x, int y); @Override public void mouseMove(int x, int y) { - Point point = SunGraphicsEnvironment.convertToDeviceSpace(x, y); + Point point = toDeviceSpaceAbs(x, y); mouseMoveImpl(point.x, point.y); } @Override @@ -64,5 +64,10 @@ public int getRGBPixel(int x, int y) { return pixelArray; } + @Override + public boolean useAbsoluteCoordinates() { + return true; + } + private native void getRGBPixels(int x, int y, int width, int height, int[] pixelArray); } diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java index 5db663c6f7f..6c3d059457d 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java @@ -63,10 +63,11 @@ import sun.awt.Win32GraphicsConfig; import sun.awt.Win32GraphicsDevice; import sun.awt.Win32GraphicsEnvironment; -import sun.java2d.SunGraphicsEnvironment; import sun.java2d.pipe.Region; import sun.util.logging.PlatformLogger; +import static sun.java2d.SunGraphicsEnvironment.toUserSpace; + public class WWindowPeer extends WPanelPeer implements WindowPeer, DisplayChangedListener { @@ -108,8 +109,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, * WindowStateEvent is posted to the EventQueue. */ private WindowListener windowListener; - private float scaleX; - private float scaleY; /** * Initialize JNI field IDs @@ -222,8 +221,6 @@ void initialize() { GraphicsConfiguration gc = getGraphicsConfiguration(); Win32GraphicsDevice gd = (Win32GraphicsDevice) gc.getDevice(); gd.addDisplayChangedListener(this); - scaleX = gd.getDefaultScaleX(); - scaleY = gd.getDefaultScaleY(); initActiveWindowsTracking((Window)target); @@ -310,6 +307,12 @@ public void show() { } } + @Override + final void syncBounds() { + // Windows will take care of the top-level window/frame/dialog, and + // update the location/size when DPI changes. + } + // Synchronize the insets members (here & in helper) with actual window // state. native void updateInsets(Insets i); @@ -438,9 +441,10 @@ public void updateMinimumSize() { minimumSize = ((Component)target).getMinimumSize(); } if (minimumSize != null) { - int w = Math.max(minimumSize.width, scaleDownX(getSysMinWidth())); - int h = Math.max(minimumSize.height, scaleDownY(getSysMinHeight())); - setMinSize(w, h); + Dimension sysMin = toUserSpace(getGraphicsConfiguration(), + getSysMinWidth(), getSysMinHeight()); + setMinSize(Math.max(minimumSize.width, sysMin.width), + Math.max(minimumSize.height, sysMin.height)); } else { setMinSize(0, 0); } @@ -598,21 +602,6 @@ public void updateGC() { AWTAccessor.getComponentAccessor(). setGraphicsConfiguration((Component)target, winGraphicsConfig); - - checkDPIChange(oldDev, newDev); - } - - private void checkDPIChange(Win32GraphicsDevice oldDev, - Win32GraphicsDevice newDev) { - float newScaleX = newDev.getDefaultScaleX(); - float newScaleY = newDev.getDefaultScaleY(); - - if (scaleX != newScaleX || scaleY != newScaleY) { - windowDPIChange(oldDev.getScreen(), scaleX, scaleY, - newDev.getScreen(), newScaleX, newScaleY); - scaleX = newScaleX; - scaleY = newScaleY; - } } /** @@ -666,77 +655,9 @@ boolean isTargetUndecorated() { return true; } - // These are the peer bounds. They get updated at: - // 1. the WWindowPeer.setBounds() method. - // 2. the native code (on WM_SIZE/WM_MOVE) - private volatile int sysX = 0; - private volatile int sysY = 0; - private volatile int sysW = 0; - private volatile int sysH = 0; - @Override public native void repositionSecurityWarning(); - @Override - public void setBounds(int x, int y, int width, int height, int op) { - sysX = x; - sysY = y; - sysW = width; - sysH = height; - - int cx = x + width / 2; - int cy = y + height / 2; - GraphicsConfiguration current = getGraphicsConfiguration(); - GraphicsConfiguration other = SunGraphicsEnvironment - .getGraphicsConfigurationAtPoint(current, cx, cy); - if (!current.equals(other)) { - AffineTransform tx = other.getDefaultTransform(); - double otherScaleX = tx.getScaleX(); - double otherScaleY = tx.getScaleY(); - initScales(); - if (scaleX != otherScaleX || scaleY != otherScaleY) { - x = (int) Math.floor(x * otherScaleX / scaleX); - y = (int) Math.floor(y * otherScaleY / scaleY); - } - } - - super.setBounds(x, y, width, height, op); - } - - private void initScales() { - - if (scaleX >= 1 && scaleY >= 1) { - return; - } - - GraphicsConfiguration gc = getGraphicsConfiguration(); - if (gc instanceof Win32GraphicsConfig) { - Win32GraphicsDevice gd = ((Win32GraphicsConfig) gc).getDevice(); - scaleX = gd.getDefaultScaleX(); - scaleY = gd.getDefaultScaleY(); - } else { - AffineTransform tx = gc.getDefaultTransform(); - scaleX = (float) tx.getScaleX(); - scaleY = (float) tx.getScaleY(); - } - } - - final int scaleUpX(int x) { - return Region.clipRound(x * scaleX); - } - - final int scaleUpY(int y) { - return Region.clipRound(y * scaleY); - } - - final int scaleDownX(int x) { - return Region.clipRound(x / scaleX); - } - - final int scaleDownY(int y) { - return Region.clipRound(y / scaleY); - } - @Override public void print(Graphics g) { // We assume we print the whole frame, @@ -905,9 +826,6 @@ private void updateWindow(boolean repaint) { } } - native void windowDPIChange(int prevScreen, float prevScaleX, float prevScaleY, - int newScreen, float newScaleX, float newScaleY); - /* * The method maps the list of the active windows to the window's AppContext, * then the method registers ActiveWindowListener, GuiDisposedListener listeners; diff --git a/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp b/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp index bada561fe8c..804a8efb8e9 100644 --- a/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp +++ b/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -125,9 +125,14 @@ void SetupThreadGraphicsInfo(JNIEnv *env, GDIWinSDOps *wsdo) { // First, init the HDC object AwtComponent *comp = GDIWindowSurfaceData_GetComp(env, wsdo); if (comp == NULL) { + // wsdo->invalid is set by GDIWindowSurfaceData_GetComp return; } hDC = comp->GetDCFromComponent(); + if (hDC == NULL) { + wsdo->invalid = JNI_TRUE; + return; + } if (hDC != NULL && wsdo->device != NULL) { ::SelectObject(hDC, nullbrush); ::SelectObject(hDC, nullpen); diff --git a/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp b/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp index 37fbc914519..560764e8b28 100644 --- a/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp +++ b/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -106,8 +106,8 @@ Java_sun_awt_windows_WMouseInfoPeer_fillPointWithCoords(JNIEnv *env, jclass cls, yID = env->GetFieldID(pointClass, "y", "I"); CHECK_NULL_RETURN(yID, (jint)0); - int x = (device == NULL) ? pt.x : device->ScaleDownX(pt.x); - int y = (device == NULL) ? pt.y : device->ScaleDownY(pt.y); + int x = (device == NULL) ? pt.x : device->ScaleDownAbsX(pt.x); + int y = (device == NULL) ? pt.y : device->ScaleDownAbsY(pt.y); env->SetIntField(point, xID, x); env->SetIntField(point, yID, y); diff --git a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp b/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp index 8a4461be409..002b502fafb 100644 --- a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp +++ b/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,51 +24,13 @@ */ #include "sun_awt_windows_ThemeReader.h" -#include #include "awt.h" #include "awt_Toolkit.h" -#include "awt_Object.h" -#include "awt_Component.h" #include "math.h" -// Important note about VC6 and VC7 (or XP Platform SDK) ! -// -// These type definitions have been imported from UxTheme.h -// They have been imported instead of including them, because -// currently we don't require Platform SDK for building J2SE and -// VC6 includes do not have UxTheme.h. When we move to VC7 -// we should remove these imports and just include -// -// Uncomment these when we start using VC 7 (or XP Platform SDK) -// -// #include -// #incldue - - -// Remove everyting inside this ifdef when we start using VC 7 (or XP Platform SDK) -#ifndef _UXTHEME_H_ -typedef HANDLE HTHEME; // handle to a section of theme data for class - -typedef enum { - TS_MIN, - TS_TRUE, - TS_DRAW -} THEME_SIZE; - - -// Remove these when we start using VC 7 (or XP Platform SDK) -typedef struct _MARGINS -{ - int cxLeftWidth; // width of left border that retains its size - int cxRightWidth; // width of right border that retains its size - int cyTopHeight; // height of top border that retains its size - int cyBottomHeight; // height of bottom border that retains its size -} MARGINS, *PMARGINS; - -#define TMT_TRANSPARENT 2201 -#endif // _UXTHEME_H_ +#include #if defined(_MSC_VER) && _MSC_VER >= 1800 # define ROUND_TO_INT(num) ((int) round(num)) @@ -119,7 +81,7 @@ typedef HRESULT (__stdcall *PFNGETTHEMEENUMVALUE)(HTHEME hTheme, int iPartId, typedef HRESULT (__stdcall *PFNGETTHEMEINT)(HTHEME hTheme, int iPartId, int iStateId, int iPropId, int *val); typedef HRESULT (__stdcall *PFNGETTHEMEPARTSIZE)(HTHEME hTheme, HDC hdc, - int iPartId, int iStateId, RECT *prc, THEME_SIZE eSize, SIZE *size); + int iPartId, int iStateId, RECT *prc, THEMESIZE eSize, SIZE *size); typedef HRESULT (__stdcall *PFNGETTHEMEPOSITION)(HTHEME hTheme, int iPartId, int iStateId, int propID, POINT *point); @@ -134,25 +96,24 @@ typedef HRESULT (__stdcall *PFNGETTHEMETRANSITIONDURATION) (HTHEME hTheme, int iPartId, int iStateIdFrom, int iStateIdTo, int iPropId, DWORD *pdwDuration); -static PFNOPENTHEMEDATA OpenThemeData = NULL; -static PFNDRAWTHEMEBACKGROUND DrawThemeBackground = NULL; -static PFNCLOSETHEMEDATA CloseThemeData = NULL; -static PFNDRAWTHEMETEXT DrawThemeText = NULL; -static PFNGETTHEMEBACKGROUNDCONTENTRECT GetThemeBackgroundContentRect = NULL; -static PFNGETTHEMEMARGINS GetThemeMargins = NULL; -static PFNISTHEMEPARTDEFINED IsThemePartDefined = NULL; -static PFNGETTHEMEBOOL GetThemeBool=NULL; -static PFNGETTHEMESYSBOOL GetThemeSysBool=NULL; -static PFNGETTHEMECOLOR GetThemeColor=NULL; -static PFNGETTHEMEENUMVALUE GetThemeEnumValue = NULL; -static PFNGETTHEMEINT GetThemeInt = NULL; -static PFNGETTHEMEPARTSIZE GetThemePartSize = NULL; -static PFNGETTHEMEPOSITION GetThemePosition = NULL; -static PFNSETWINDOWTHEME SetWindowTheme = NULL; +static PFNOPENTHEMEDATA OpenThemeDataFunc = NULL; +static PFNDRAWTHEMEBACKGROUND DrawThemeBackgroundFunc = NULL; +static PFNCLOSETHEMEDATA CloseThemeDataFunc = NULL; +static PFNDRAWTHEMETEXT DrawThemeTextFunc = NULL; +static PFNGETTHEMEBACKGROUNDCONTENTRECT GetThemeBackgroundContentRectFunc = NULL; +static PFNGETTHEMEMARGINS GetThemeMarginsFunc = NULL; +static PFNISTHEMEPARTDEFINED IsThemePartDefinedFunc = NULL; +static PFNGETTHEMEBOOL GetThemeBoolFunc=NULL; +static PFNGETTHEMESYSBOOL GetThemeSysBoolFunc=NULL; +static PFNGETTHEMECOLOR GetThemeColorFunc=NULL; +static PFNGETTHEMEENUMVALUE GetThemeEnumValueFunc = NULL; +static PFNGETTHEMEINT GetThemeIntFunc = NULL; +static PFNGETTHEMEPARTSIZE GetThemePartSizeFunc = NULL; +static PFNGETTHEMEPOSITION GetThemePositionFunc = NULL; +static PFNSETWINDOWTHEME SetWindowThemeFunc = NULL; static PFNISTHEMEBACKGROUNDPARTIALLYTRANSPARENT - IsThemeBackgroundPartiallyTransparent = NULL; -//this function might not exist on Windows XP -static PFNGETTHEMETRANSITIONDURATION GetThemeTransitionDuration = NULL; + IsThemeBackgroundPartiallyTransparentFunc = NULL; +static PFNGETTHEMETRANSITIONDURATION GetThemeTransitionDurationFunc = NULL; BOOL InitThemes() { @@ -161,67 +122,67 @@ BOOL InitThemes() { DTRACE_PRINTLN1("InitThemes hModThemes = %x\n", hModThemes); if(hModThemes) { DTRACE_PRINTLN("Loaded UxTheme.dll\n"); - OpenThemeData = (PFNOPENTHEMEDATA)GetProcAddress(hModThemes, + OpenThemeDataFunc = (PFNOPENTHEMEDATA)GetProcAddress(hModThemes, "OpenThemeData"); - DrawThemeBackground = (PFNDRAWTHEMEBACKGROUND)GetProcAddress( + DrawThemeBackgroundFunc = (PFNDRAWTHEMEBACKGROUND)GetProcAddress( hModThemes, "DrawThemeBackground"); - CloseThemeData = (PFNCLOSETHEMEDATA)GetProcAddress( + CloseThemeDataFunc = (PFNCLOSETHEMEDATA)GetProcAddress( hModThemes, "CloseThemeData"); - DrawThemeText = (PFNDRAWTHEMETEXT)GetProcAddress( + DrawThemeTextFunc = (PFNDRAWTHEMETEXT)GetProcAddress( hModThemes, "DrawThemeText"); - GetThemeBackgroundContentRect = (PFNGETTHEMEBACKGROUNDCONTENTRECT) + GetThemeBackgroundContentRectFunc = (PFNGETTHEMEBACKGROUNDCONTENTRECT) GetProcAddress(hModThemes, "GetThemeBackgroundContentRect"); - GetThemeMargins = (PFNGETTHEMEMARGINS)GetProcAddress( + GetThemeMarginsFunc = (PFNGETTHEMEMARGINS)GetProcAddress( hModThemes, "GetThemeMargins"); - IsThemePartDefined = (PFNISTHEMEPARTDEFINED)GetProcAddress( + IsThemePartDefinedFunc = (PFNISTHEMEPARTDEFINED)GetProcAddress( hModThemes, "IsThemePartDefined"); - GetThemeBool = (PFNGETTHEMEBOOL)GetProcAddress( + GetThemeBoolFunc = (PFNGETTHEMEBOOL)GetProcAddress( hModThemes, "GetThemeBool"); - GetThemeSysBool = (PFNGETTHEMESYSBOOL)GetProcAddress(hModThemes, + GetThemeSysBoolFunc = (PFNGETTHEMESYSBOOL)GetProcAddress(hModThemes, "GetThemeSysBool"); - GetThemeColor = (PFNGETTHEMECOLOR)GetProcAddress(hModThemes, + GetThemeColorFunc = (PFNGETTHEMECOLOR)GetProcAddress(hModThemes, "GetThemeColor"); - GetThemeEnumValue = (PFNGETTHEMEENUMVALUE)GetProcAddress(hModThemes, + GetThemeEnumValueFunc = (PFNGETTHEMEENUMVALUE)GetProcAddress(hModThemes, "GetThemeEnumValue"); - GetThemeInt = (PFNGETTHEMEINT)GetProcAddress(hModThemes, "GetThemeInt"); - GetThemePosition = (PFNGETTHEMEPOSITION)GetProcAddress(hModThemes, + GetThemeIntFunc = (PFNGETTHEMEINT)GetProcAddress(hModThemes, "GetThemeInt"); + GetThemePositionFunc = (PFNGETTHEMEPOSITION)GetProcAddress(hModThemes, "GetThemePosition"); - GetThemePartSize = (PFNGETTHEMEPARTSIZE)GetProcAddress(hModThemes, + GetThemePartSizeFunc = (PFNGETTHEMEPARTSIZE)GetProcAddress(hModThemes, "GetThemePartSize"); - SetWindowTheme = (PFNSETWINDOWTHEME)GetProcAddress(hModThemes, + SetWindowThemeFunc = (PFNSETWINDOWTHEME)GetProcAddress(hModThemes, "SetWindowTheme"); - IsThemeBackgroundPartiallyTransparent = + IsThemeBackgroundPartiallyTransparentFunc = (PFNISTHEMEBACKGROUNDPARTIALLYTRANSPARENT)GetProcAddress(hModThemes, "IsThemeBackgroundPartiallyTransparent"); - //this function might not exist - GetThemeTransitionDuration = + GetThemeTransitionDurationFunc = (PFNGETTHEMETRANSITIONDURATION)GetProcAddress(hModThemes, "GetThemeTransitionDuration"); - if(OpenThemeData - && DrawThemeBackground - && CloseThemeData - && DrawThemeText - && GetThemeBackgroundContentRect - && GetThemeMargins - && IsThemePartDefined - && GetThemeBool - && GetThemeSysBool - && GetThemeColor - && GetThemeEnumValue - && GetThemeInt - && GetThemePartSize - && GetThemePosition - && SetWindowTheme - && IsThemeBackgroundPartiallyTransparent + if(OpenThemeDataFunc + && DrawThemeBackgroundFunc + && CloseThemeDataFunc + && DrawThemeTextFunc + && GetThemeBackgroundContentRectFunc + && GetThemeMarginsFunc + && IsThemePartDefinedFunc + && GetThemeBoolFunc + && GetThemeSysBoolFunc + && GetThemeColorFunc + && GetThemeEnumValueFunc + && GetThemeIntFunc + && GetThemePartSizeFunc + && GetThemePositionFunc + && SetWindowThemeFunc + && IsThemeBackgroundPartiallyTransparentFunc + && GetThemeTransitionDurationFunc ) { DTRACE_PRINTLN("Loaded function pointers.\n"); // We need to make sure we can load the Theme. This may not be // the case on a WinXP machine with classic mode enabled. - HTHEME hTheme = OpenThemeData(AwtToolkit::GetInstance().GetHWnd(), L"Button"); + HTHEME hTheme = OpenThemeDataFunc(AwtToolkit::GetInstance().GetHWnd(), L"Button"); if(hTheme) { DTRACE_PRINTLN("Loaded Theme data.\n"); - CloseThemeData(hTheme); + CloseThemeDataFunc(hTheme); return TRUE; } } else { @@ -290,7 +251,7 @@ JNIEXPORT jlong JNICALL Java_sun_awt_windows_ThemeReader_openTheme } // We need to open the Theme on a Window that will stick around. // The best one for that purpose is the Toolkit window. - HTHEME htheme = OpenThemeData(AwtToolkit::GetInstance().GetHWnd(), str); + HTHEME htheme = OpenThemeDataFunc(AwtToolkit::GetInstance().GetHWnd(), str); JNU_ReleaseStringPlatformChars(env, widget, str); return (jlong) htheme; } @@ -308,7 +269,7 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_setWindowTheme str = (LPCTSTR) JNU_GetStringPlatformChars(env, subAppName, NULL); } // We need to set the Window theme on the same theme that we opened it with. - HRESULT hres = SetWindowTheme(AwtToolkit::GetInstance().GetHWnd(), str, NULL); + HRESULT hres = SetWindowThemeFunc(AwtToolkit::GetInstance().GetHWnd(), str, NULL); assert_result(hres, env); if (subAppName != NULL) { JNU_ReleaseStringPlatformChars(env, subAppName, str); @@ -323,7 +284,7 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_setWindowTheme JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_closeTheme (JNIEnv *env, jclass klass, jlong theme) { - HRESULT hres = CloseThemeData((HTHEME)theme); + HRESULT hres = CloseThemeDataFunc((HTHEME)theme); assert_result(hres, env); } @@ -474,7 +435,7 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_paintBackground ZeroMemory(pSrcBits,(BITS_PER_PIXEL>>3)*w*h); - HRESULT hres = DrawThemeBackground(hTheme, memDC, part, state, &rect, NULL); + HRESULT hres = DrawThemeBackgroundFunc(hTheme, memDC, part, state, &rect, NULL); assert_result(hres, env); if (SUCCEEDED(hres)) { // Make sure GDI is done. @@ -482,7 +443,7 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_paintBackground // Copy the resulting pixels to our Java BufferedImage. pDstBits = (int *)env->GetPrimitiveArrayCritical(array, 0); BOOL transparent = FALSE; - transparent = IsThemeBackgroundPartiallyTransparent(hTheme,part,state); + transparent = IsThemeBackgroundPartiallyTransparentFunc(hTheme, part, state); copyDIBToBufferedImage(pDstBits, pSrcBits, transparent, w, h, stride); env->ReleasePrimitiveArrayCritical(array, pDstBits, 0); } @@ -530,7 +491,7 @@ JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getThemeMargins HTHEME hTheme = (HTHEME) theme; if (hTheme != NULL) { - HRESULT hres = GetThemeMargins(hTheme, NULL, part, state, property, NULL, &margins); + HRESULT hres = GetThemeMarginsFunc(hTheme, NULL, part, state, property, NULL, &margins); assert_result(hres, env); if (FAILED(hres)) { return NULL; @@ -551,7 +512,7 @@ JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getThemeMargins JNIEXPORT jboolean JNICALL Java_sun_awt_windows_ThemeReader_isThemePartDefined (JNIEnv *env, jclass klass, jlong theme, jint part, jint state) { HTHEME hTheme = (HTHEME) theme; - return JNI_IS_TRUE(IsThemePartDefined(hTheme, part, state)); + return JNI_IS_TRUE(IsThemePartDefinedFunc(hTheme, part, state)); } /* @@ -567,7 +528,7 @@ JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getColor if (hTheme != NULL) { COLORREF color=0; - if (GetThemeColor(hTheme, part, state, type, &color) != S_OK) { + if (GetThemeColorFunc(hTheme, part, state, type, &color) != S_OK) { return NULL; } @@ -613,7 +574,7 @@ JNIEXPORT jint JNICALL Java_sun_awt_windows_ThemeReader_getInt HTHEME hTheme = (HTHEME) theme; int retVal = -1; if (hTheme != NULL) { - HRESULT hres = GetThemeInt(hTheme, part, state, prop, &retVal); + HRESULT hres = GetThemeIntFunc(hTheme, part, state, prop, &retVal); assert_result(hres, env); } return retVal; @@ -629,7 +590,7 @@ JNIEXPORT jint JNICALL Java_sun_awt_windows_ThemeReader_getEnum HTHEME hTheme = (HTHEME) theme; int retVal = -1; if (hTheme != NULL) { - HRESULT hres = GetThemeEnumValue(hTheme, part, state, prop, &retVal); + HRESULT hres = GetThemeEnumValueFunc(hTheme, part, state, prop, &retVal); assert_result(hres, env); } return retVal; @@ -645,7 +606,7 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_windows_ThemeReader_getBoolean HTHEME hTheme = (HTHEME) theme; BOOL retVal = FALSE; if (hTheme != NULL) { - HRESULT hres = GetThemeBool(hTheme, part, state, prop, &retVal); + HRESULT hres = GetThemeBoolFunc(hTheme, part, state, prop, &retVal); assert_result(hres, env); } return JNI_IS_TRUE(retVal); @@ -660,7 +621,7 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_windows_ThemeReader_getSysBoolean (JNIEnv *env, jclass klass, jlong theme, jint prop) { HTHEME hTheme = (HTHEME)theme; if (hTheme != NULL) { - return JNI_IS_TRUE(GetThemeSysBool(hTheme, prop)); + return JNI_IS_TRUE(GetThemeSysBoolFunc(hTheme, prop)); } return JNI_FALSE; } @@ -676,7 +637,7 @@ JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getPoint POINT point; if (hTheme != NULL) { - if (GetThemePosition(hTheme, part, state, prop, &point) != S_OK) { + if (GetThemePositionFunc(hTheme, part, state, prop, &point) != S_OK) { return NULL; } @@ -723,7 +684,7 @@ JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getPosition POINT point; - HRESULT hres = GetThemePosition(hTheme, part, state, prop, &point); + HRESULT hres = GetThemePositionFunc(hTheme, part, state, prop, &point); assert_result(hres, env); if (FAILED(hres)) { return NULL; @@ -789,7 +750,7 @@ JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getPartSize if (theme != NULL) { SIZE size; - if (SUCCEEDED(GetThemePartSize((HTHEME)theme, NULL, part, state, + if (SUCCEEDED(GetThemePartSizeFunc((HTHEME)theme, NULL, part, state, NULL, TS_TRUE, &size)) && (env->EnsureLocalCapacity(2) >= 0)) { static jmethodID dimMID = NULL; @@ -833,9 +794,10 @@ jint boundingWidth, jint boundingHeight) { boundingRect.right = boundingWidth; boundingRect.bottom = boundingHeight; RECT contentRect; - if (SUCCEEDED(GetThemeBackgroundContentRect((HTHEME) hTheme, NULL, part, - state, &boundingRect, - &contentRect))) { + if (SUCCEEDED(GetThemeBackgroundContentRectFunc((HTHEME) hTheme, NULL, + part, state, + &boundingRect, + &contentRect))) { return newInsets(env, contentRect.top, contentRect.left, boundingHeight - contentRect.bottom, @@ -855,23 +817,10 @@ Java_sun_awt_windows_ThemeReader_getThemeTransitionDuration (JNIEnv *env, jclass klass, jlong theme, jint part, jint stateFrom, jint stateTo, jint propId) { jlong rv = -1; - if (GetThemeTransitionDuration != NULL) { - DWORD duration = 0; - if (SUCCEEDED(GetThemeTransitionDuration((HTHEME) theme, part, - stateFrom, stateTo, propId, &duration))) { - rv = duration; - } + DWORD duration = 0; + if (SUCCEEDED(GetThemeTransitionDurationFunc((HTHEME) theme, part, + stateFrom, stateTo, propId, &duration))) { + rv = duration; } return rv; } - -/* - * Class: sun_awt_windows_ThemeReader - * Method: isGetThemeTransitionDurationDefined - * Signature: ()Z - */ -JNIEXPORT jboolean JNICALL -Java_sun_awt_windows_ThemeReader_isGetThemeTransitionDurationDefined -(JNIEnv *env, jclass klass) { - return (GetThemeTransitionDuration != NULL) ? JNI_TRUE : JNI_FALSE; -} diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp index 9e15a77514a..1ed97ba94d2 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp @@ -603,7 +603,7 @@ AwtComponent::CreateHWnd(JNIEnv *env, LPCWSTR title, /* * Fix for 4046446. */ - SetWindowPos(GetHWnd(), 0, x, y, w, h, SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOACTIVATE); + Reshape(x, y, w, h); /* Set default colors. */ m_colorForeground = colorForeground; @@ -1087,6 +1087,7 @@ void SpyWinMessage(HWND hwnd, UINT message, LPCTSTR szComment) { WIN_MSG(WM_DESTROY) WIN_MSG(WM_MOVE) WIN_MSG(WM_SIZE) + WIN_MSG(WM_DPICHANGED) WIN_MSG(WM_ACTIVATE) WIN_MSG(WM_SETFOCUS) WIN_MSG(WM_KILLFOCUS) @@ -1505,9 +1506,9 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) case WM_SIZE: { RECT r; - // fix 4128317 : use GetClientRect for full 32-bit int precision and + // fix 4128317 : use GetWindowRect for full 32-bit int precision and // to avoid negative client area dimensions overflowing 16-bit params - robi - ::GetClientRect( GetHWnd(), &r ); + ::GetWindowRect(GetHWnd(), &r); mr = WmSize(static_cast(wParam), r.right - r.left, r.bottom - r.top); //mr = WmSize(wParam, LOWORD(lParam), HIWORD(lParam)); SetCompositionWindow(r); @@ -3888,8 +3889,8 @@ void AwtComponent::OpenCandidateWindow(int x, int y) } HWND hTop = GetTopLevelParentForWindow(hWnd); ::ClientToScreen(hTop, &p); - int sx = ScaleUpX(x) - p.x; - int sy = ScaleUpY(y) - p.y; + int sx = ScaleUpAbsX(x) - p.x; + int sy = ScaleUpAbsY(y) - p.y; if (!m_bitsCandType) { SetCandidateWindow(m_bitsCandType, sx, sy); return; @@ -4767,34 +4768,71 @@ void AwtComponent::FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha) } } +int AwtComponent::GetScreenImOn() { + HWND hWindow = GetAncestor(GetHWnd(), GA_ROOT); + AwtComponent *comp = AwtComponent::GetComponent(hWindow); + if (comp && comp->IsTopLevel()) { + return comp->GetScreenImOn(); + } + return AwtWin32GraphicsDevice::DeviceIndexForWindow(hWindow); +} + int AwtComponent::ScaleUpX(int x) { - int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()); + int screen = GetScreenImOn(); Devices::InstanceAccess devices; AwtWin32GraphicsDevice* device = devices->GetDevice(screen); return device == NULL ? x : device->ScaleUpX(x); } +int AwtComponent::ScaleUpAbsX(int x) { + int screen = GetScreenImOn(); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* device = devices->GetDevice(screen); + return device == NULL ? x : device->ScaleUpAbsX(x); +} + int AwtComponent::ScaleUpY(int y) { - int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()); + int screen = GetScreenImOn(); Devices::InstanceAccess devices; AwtWin32GraphicsDevice* device = devices->GetDevice(screen); return device == NULL ? y : device->ScaleUpY(y); } +int AwtComponent::ScaleUpAbsY(int y) { + int screen = GetScreenImOn(); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* device = devices->GetDevice(screen); + return device == NULL ? y : device->ScaleUpAbsY(y); +} + int AwtComponent::ScaleDownX(int x) { - int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()); + int screen = GetScreenImOn(); Devices::InstanceAccess devices; AwtWin32GraphicsDevice* device = devices->GetDevice(screen); return device == NULL ? x : device->ScaleDownX(x); } +int AwtComponent::ScaleDownAbsX(int x) { + int screen = GetScreenImOn(); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* device = devices->GetDevice(screen); + return device == NULL ? x : device->ScaleDownAbsX(x); +} + int AwtComponent::ScaleDownY(int y) { - int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(GetHWnd()); + int screen = GetScreenImOn(); Devices::InstanceAccess devices; AwtWin32GraphicsDevice* device = devices->GetDevice(screen); return device == NULL ? y : device->ScaleDownY(y); } +int AwtComponent::ScaleDownAbsY(int y) { + int screen = GetScreenImOn(); + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* device = devices->GetDevice(screen); + return device == NULL ? y : device->ScaleDownAbsY(y); +} + jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size, int alpha) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); @@ -5090,7 +5128,7 @@ void AwtComponent::SendMouseEvent(jint id, jlong when, jint x, jint y, id, when, modifiers, ScaleDownX(x + insets.left), ScaleDownY(y + insets.top), - ScaleDownX(xAbs), ScaleDownY(yAbs), + ScaleDownAbsX(xAbs), ScaleDownAbsY(yAbs), clickCount, popupTrigger, button); if (safe_ExceptionOccurred(env)) { @@ -5163,8 +5201,8 @@ AwtComponent::SendMouseWheelEvent(jint id, jlong when, jint x, jint y, id, when, modifiers, ScaleDownX(x + insets.left), ScaleDownY(y + insets.top), - ScaleDownX(xAbs), - ScaleDownY(yAbs), + ScaleDownAbsX(xAbs), + ScaleDownAbsY(yAbs), clickCount, popupTrigger, scrollType, scrollAmount, roundedWheelRotation, preciseWheelRotation); @@ -5674,8 +5712,8 @@ jobject AwtComponent::_GetLocationOnScreen(void *param) RECT rect; VERIFY(::GetWindowRect(p->GetHWnd(),&rect)); result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V", - p->ScaleDownX(rect.left), - p->ScaleDownY(rect.top)); + p->ScaleDownAbsX(rect.left), + p->ScaleDownAbsY(rect.top)); } ret: env->DeleteGlobalRef(self); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.h b/src/java.desktop/windows/native/libawt/windows/awt_Component.h index 1e3e0769273..d950e78abda 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Component.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.h @@ -275,6 +275,7 @@ class AwtComponent : public AwtObject { /* * methods on this component */ + virtual int GetScreenImOn(); virtual void Show(); virtual void Hide(); virtual void Reshape(int x, int y, int w, int h); @@ -755,9 +756,13 @@ class AwtComponent : public AwtObject { virtual void FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha); int ScaleUpX(int x); + int ScaleUpAbsX(int x); int ScaleUpY(int y); + int ScaleUpAbsY(int y); int ScaleDownX(int x); + int ScaleDownAbsX(int x); int ScaleDownY(int y); + int ScaleDownAbsY(int y); private: /* A bitmask keeps the button's numbers as MK_LBUTTON, MK_MBUTTON, MK_RBUTTON diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Cursor.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Cursor.cpp index 642c9e9b14c..4a1a4c08131 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Cursor.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Cursor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -475,8 +475,8 @@ Java_sun_awt_windows_WGlobalCursorManager_getCursorPos(JNIEnv *env, int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor); Devices::InstanceAccess devices; AwtWin32GraphicsDevice *device = devices->GetDevice(screen); - int x = (device == NULL) ? p.x : device->ScaleDownX(p.x); - int y = (device == NULL) ? p.y : device->ScaleDownY(p.y); + int x = (device == NULL) ? p.x : device->ScaleDownAbsX(p.x); + int y = (device == NULL) ? p.y : device->ScaleDownAbsY(p.y); env->SetIntField(point, AwtCursor::pointXID, x); env->SetIntField(point, AwtCursor::pointYID, y); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp b/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp index 390b9250aba..0f9fb662bbf 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp @@ -1174,14 +1174,14 @@ HRESULT __stdcall AwtDragSource::GetProcessId(FORMATETC __RPC_FAR *pFormatEtc, S return S_OK; } -static void ScaleDown(POINT &pt) { +static void ScaleDownAbs(POINT &pt) { HMONITOR monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY); int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor); Devices::InstanceAccess devices; AwtWin32GraphicsDevice *device = devices->GetDevice(screen); if (device) { - pt.x = device->ScaleDownX(pt.x); - pt.y = device->ScaleDownY(pt.y); + pt.x = device->ScaleDownAbsX(pt.x); + pt.y = device->ScaleDownAbsY(pt.y); } } @@ -1190,7 +1190,7 @@ DECLARE_JAVA_CLASS(dSCClazz, "sun/awt/windows/WDragSourceContextPeer") void AwtDragSource::call_dSCenter(JNIEnv* env, jobject self, jint targetActions, jint modifiers, POINT pt) { - ScaleDown(pt); + ScaleDownAbs(pt); DECLARE_VOID_JAVA_METHOD(dSCenter, dSCClazz, "dragEnter", "(IIII)V"); DASSERT(!JNU_IsNull(env, self)); env->CallVoidMethod(self, dSCenter, targetActions, modifiers, pt.x, pt.y); @@ -1203,7 +1203,7 @@ AwtDragSource::call_dSCenter(JNIEnv* env, jobject self, jint targetActions, void AwtDragSource::call_dSCmotion(JNIEnv* env, jobject self, jint targetActions, jint modifiers, POINT pt) { - ScaleDown(pt); + ScaleDownAbs(pt); DECLARE_VOID_JAVA_METHOD(dSCmotion, dSCClazz, "dragMotion", "(IIII)V"); DASSERT(!JNU_IsNull(env, self)); env->CallVoidMethod(self, dSCmotion, targetActions, modifiers, pt.x, pt.y); @@ -1216,7 +1216,7 @@ AwtDragSource::call_dSCmotion(JNIEnv* env, jobject self, jint targetActions, void AwtDragSource::call_dSCchanged(JNIEnv* env, jobject self, jint targetActions, jint modifiers, POINT pt) { - ScaleDown(pt); + ScaleDownAbs(pt); DECLARE_VOID_JAVA_METHOD(dSCchanged, dSCClazz, "operationChanged", "(IIII)V"); DASSERT(!JNU_IsNull(env, self)); @@ -1229,7 +1229,7 @@ AwtDragSource::call_dSCchanged(JNIEnv* env, jobject self, jint targetActions, void AwtDragSource::call_dSCexit(JNIEnv* env, jobject self, POINT pt) { - ScaleDown(pt); + ScaleDownAbs(pt); DECLARE_VOID_JAVA_METHOD(dSCexit, dSCClazz, "dragExit", "(II)V"); DASSERT(!JNU_IsNull(env, self)); env->CallVoidMethod(self, dSCexit, pt.x, pt.y); @@ -1242,7 +1242,7 @@ AwtDragSource::call_dSCexit(JNIEnv* env, jobject self, POINT pt) { void AwtDragSource::call_dSCddfinished(JNIEnv* env, jobject self, jboolean success, jint operations, POINT pt) { - ScaleDown(pt); + ScaleDownAbs(pt); DECLARE_VOID_JAVA_METHOD(dSCddfinished, dSCClazz, "dragDropFinished", "(ZIII)V"); DASSERT(!JNU_IsNull(env, self)); env->CallVoidMethod(self, dSCddfinished, success, operations, pt.x, pt.y); @@ -1255,7 +1255,7 @@ AwtDragSource::call_dSCddfinished(JNIEnv* env, jobject self, jboolean success, void AwtDragSource::call_dSCmouseMoved(JNIEnv* env, jobject self, jint targetActions, jint modifiers, POINT pt) { - ScaleDown(pt); + ScaleDownAbs(pt); DECLARE_VOID_JAVA_METHOD(dSCmouseMoved, dSCClazz, "dragMouseMoved", "(IIII)V"); DASSERT(!JNU_IsNull(env, self)); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_FileDialog.cpp b/src/java.desktop/windows/native/libawt/windows/awt_FileDialog.cpp index 119b2c3680c..e8128372ceb 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_FileDialog.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_FileDialog.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -631,18 +631,18 @@ Java_sun_awt_windows_WFileDialogPeer_toBack(JNIEnv *env, jobject peer) CATCH_BAD_ALLOC; } -int ScaleDownX(int x, HWND hwnd) { +int ScaleDownAbsX(int x, HWND hwnd) { int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd); Devices::InstanceAccess devices; AwtWin32GraphicsDevice* device = devices->GetDevice(screen); - return device == NULL ? x : device->ScaleDownX(x); + return device == NULL ? x : device->ScaleDownAbsX(x); } -int ScaleDownY(int y, HWND hwnd) { +int ScaleDownAbsY(int y, HWND hwnd) { int screen = AwtWin32GraphicsDevice::DeviceIndexForWindow(hwnd); Devices::InstanceAccess devices; AwtWin32GraphicsDevice* device = devices->GetDevice(screen); - return device == NULL ? y : device->ScaleDownY(y); + return device == NULL ? y : device->ScaleDownAbsY(y); } jobject AwtFileDialog::_GetLocationOnScreen(void *param) @@ -657,7 +657,8 @@ jobject AwtFileDialog::_GetLocationOnScreen(void *param) RECT rect; VERIFY(::GetWindowRect(hwnd, &rect)); result = JNU_NewObjectByName(env, "java/awt/Point", "(II)V", - ScaleDownX(rect.left, hwnd), ScaleDownY(rect.top, hwnd)); + ScaleDownAbsX(rect.left, hwnd), + ScaleDownAbsY(rect.top, hwnd)); } if (result != NULL) diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp index 8f2fcd84f6f..d8873b6bec2 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp @@ -328,17 +328,13 @@ AwtFrame* AwtFrame::Create(jobject self, jobject parent) frame->CreateHWnd(env, L"", style, exStyle, - 0, 0, 0, 0, + x, y, width, height, hwndParent, NULL, ::GetSysColor(COLOR_WINDOWTEXT), ::GetSysColor(COLOR_WINDOWFRAME), self); - /* - * Reshape here instead of during create, so that a - * WM_NCCALCSIZE is sent. - */ - frame->Reshape(x, y, width, height); + frame->RecalcNonClient(); } } } catch (...) { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_List.cpp b/src/java.desktop/windows/native/libawt/windows/awt_List.cpp index 69484f024d7..a04f6182a5b 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_List.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_List.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -288,14 +288,17 @@ void AwtList::SetMultiSelect(BOOL ms) { UnsubclassHWND(); AwtToolkit::DestroyComponentHWND(m_hwnd); - CreateHWnd(env, L"", style, exStyle, - rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + CreateHWnd(env, L"", style, exStyle, 0, 0, 0, 0, parentHWnd, NULL, ::GetSysColor(COLOR_WINDOWTEXT), ::GetSysColor(COLOR_WINDOW), peer); + SetWindowPos(GetHWnd(), 0, + rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, + SWP_NOZORDER | SWP_NOCOPYBITS | SWP_NOACTIVATE); + SendListMessage(WM_SETFONT, (WPARAM)font, (LPARAM)FALSE); SendListMessage(LB_SETITEMHEIGHT, 0, MAKELPARAM(itemHeight, 0)); SendListMessage(LB_RESETCONTENT); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp index 7d13fbe2d87..463c1fdee10 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsConfig.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -99,16 +99,12 @@ JNIEXPORT jobject JNICALL AwtWin32GraphicsDevice *device = devices->GetDevice(screen); if (TRUE == MonitorBounds(AwtWin32GraphicsDevice::GetMonitor(screen), &rRW)) { - - int x = (device == NULL) ? rRW.left : device->ScaleDownX(rRW.left); - int y = (device == NULL) ? rRW.top : device->ScaleDownY(rRW.top); int w = (device == NULL) ? rRW.right - rRW.left : device->ScaleDownX(rRW.right - rRW.left); int h = (device == NULL) ? rRW.bottom - rRW.top : device->ScaleDownY(rRW.bottom - rRW.top); - bounds = env->NewObject(clazz, mid, x, y, w, h); - + bounds = env->NewObject(clazz, mid, rRW.left, rRW.top, w, h); } else { // 4910760 - don't return a null bounds, return the bounds of the diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp index 2b6af9d8f2c..79e7b9d1050 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp @@ -77,6 +77,7 @@ AwtWin32GraphicsDevice::AwtWin32GraphicsDevice(int screen, this->devicesArray = arr; this->scaleX = 1; this->scaleY = 1; + disableScaleAutoRefresh = FALSE; javaDevice = NULL; colorData = new ImgColorData; colorData->grayscale = GS_NOTGRAY; @@ -633,21 +634,45 @@ int AwtWin32GraphicsDevice::ScaleUpX(int x) return ClipRound(x * scaleX); } +int AwtWin32GraphicsDevice::ScaleUpAbsX(int x) +{ + LONG screen = pMonitorInfo->rcMonitor.left; + return screen + ClipRound((x - screen) * scaleX); +} + int AwtWin32GraphicsDevice::ScaleUpY(int y) { return ClipRound(y * scaleY); } +int AwtWin32GraphicsDevice::ScaleUpAbsY(int y) +{ + LONG screen = pMonitorInfo->rcMonitor.top; + return screen + ClipRound((y - screen) * scaleY); +} + int AwtWin32GraphicsDevice::ScaleDownX(int x) { return ClipRound(x / scaleX); } +int AwtWin32GraphicsDevice::ScaleDownAbsX(int x) +{ + LONG screen = pMonitorInfo->rcMonitor.left; + return screen + ClipRound((x - screen) / scaleX); +} + int AwtWin32GraphicsDevice::ScaleDownY(int y) { return ClipRound(y / scaleY); } +int AwtWin32GraphicsDevice::ScaleDownAbsY(int y) +{ + LONG screen = pMonitorInfo->rcMonitor.top; + return screen + ClipRound((y - screen) / scaleY); +} + int AwtWin32GraphicsDevice::ClipRound(double value) { value -= 0.5; @@ -666,11 +691,13 @@ int AwtWin32GraphicsDevice::ClipRound(double value) void AwtWin32GraphicsDevice::InitDesktopScales() { - float dpiX = -1.0f; - float dpiY = -1.0f; - GetScreenDpi(GetMonitor(), &dpiX, &dpiY); - if (dpiX > 0 && dpiY > 0) { - SetScale(dpiX / 96, dpiY / 96); + if (!disableScaleAutoRefresh) { + float dpiX = -1.0f; + float dpiY = -1.0f; + GetScreenDpi(GetMonitor(), &dpiX, &dpiY); + if (dpiX > 0 && dpiY > 0) { + SetScale(dpiX / 96, dpiY / 96); + } } } @@ -694,6 +721,11 @@ void AwtWin32GraphicsDevice::DisableOffscreenAcceleration() // REMIND: noop for now } +void AwtWin32GraphicsDevice::DisableScaleAutoRefresh() +{ + disableScaleAutoRefresh = TRUE; +} + /** * Invalidates the GraphicsDevice object associated with this * device by disabling offscreen acceleration and calling @@ -754,6 +786,21 @@ void AwtWin32GraphicsDevice::ResetAllMonitorInfo() } } +/** + * This function updates the scale factor for all monitors on the system. + */ +void AwtWin32GraphicsDevice::ResetAllDesktopScales() +{ + if (!Devices::GetInstance()){ + return; + } + Devices::InstanceAccess devices; + int devicesNum = devices->GetNumDevices(); + for (int deviceIndex = 0; deviceIndex < devicesNum; deviceIndex++) { + devices->GetDevice(deviceIndex)->InitDesktopScales(); + } +} + void AwtWin32GraphicsDevice::DisableOffscreenAccelerationForDevice( HMONITOR hMonitor) { @@ -1393,6 +1440,7 @@ JNIEXPORT void JNICALL AwtWin32GraphicsDevice *device = devices->GetDevice(screen); if (device != NULL ) { + device->DisableScaleAutoRefresh(); device->SetScale(scaleX, scaleY); } } @@ -1441,4 +1489,3 @@ Java_sun_awt_Win32GraphicsDevice_initNativeScale device->InitDesktopScales(); } } - diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h index d5fc0d57150..f298aad68da 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,15 +65,20 @@ class AwtWin32GraphicsDevice { int GetDeviceIndex() { return screen; } void Release(); void DisableOffscreenAcceleration(); + void DisableScaleAutoRefresh(); void Invalidate(JNIEnv *env); void InitDesktopScales(); void SetScale(float scaleX, float scaleY); float GetScaleX(); float GetScaleY(); int ScaleUpX(int x); + int ScaleUpAbsX(int x); int ScaleUpY(int y); + int ScaleUpAbsY(int x); int ScaleDownX(int x); + int ScaleDownAbsX(int x); int ScaleDownY(int y); + int ScaleDownAbsY(int y); static int DeviceIndexForWindow(HWND hWnd); static jobject GetColorModel(JNIEnv *env, jboolean dynamic, @@ -88,6 +93,7 @@ class AwtWin32GraphicsDevice { static HMONITOR GetMonitor(int deviceIndex); static LPMONITORINFO GetMonitorInfo(int deviceIndex); static void ResetAllMonitorInfo(); + static void ResetAllDesktopScales(); static BOOL IsPrimaryPalettized() { return primaryPalettized; } static int GetDefaultDeviceIndex() { return primaryIndex; } static void DisableOffscreenAccelerationForDevice(HMONITOR hMonitor); @@ -117,6 +123,7 @@ class AwtWin32GraphicsDevice { Devices *devicesArray; float scaleX; float scaleY; + BOOL disableScaleAutoRefresh; static HDC MakeDCFromMonitor(HMONITOR); static int ClipRound(double value); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp index e73c2615a07..dbca3d778c8 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp @@ -153,17 +153,6 @@ struct SetFullScreenExclusiveModeStateStruct { jboolean isFSEMState; }; -// struct for _WindowDPIChange() method -struct ScaleStruct { - jobject window; - jint prevScreen; - jfloat prevScaleX; - jfloat prevScaleY; - jint screen; - jfloat scaleX; - jfloat scaleY; -}; - struct OverrideHandle { jobject frame; HWND handle; @@ -179,10 +168,6 @@ jfieldID AwtWindow::autoRequestFocusID; jfieldID AwtWindow::securityWarningWidthID; jfieldID AwtWindow::securityWarningHeightID; -jfieldID AwtWindow::sysXID; -jfieldID AwtWindow::sysYID; -jfieldID AwtWindow::sysWID; -jfieldID AwtWindow::sysHID; jfieldID AwtWindow::windowTypeID; jmethodID AwtWindow::notifyWindowStateChangedMID; @@ -1128,20 +1113,19 @@ AwtWindow* AwtWindow::Create(jobject self, jobject parent) // specify WS_EX_TOOLWINDOW to remove parentless windows from taskbar exStyle |= WS_EX_TOOLWINDOW; } + jint x = env->GetIntField(target, AwtComponent::xID); + jint y = env->GetIntField(target, AwtComponent::yID); + jint width = env->GetIntField(target, AwtComponent::widthID); + jint height = env->GetIntField(target, AwtComponent::heightID); + window->CreateHWnd(env, L"", style, exStyle, - 0, 0, 0, 0, + x, y, width, height, (awtParent != NULL) ? awtParent->GetHWnd() : NULL, NULL, ::GetSysColor(COLOR_WINDOWTEXT), ::GetSysColor(COLOR_WINDOW), self); - - jint x = env->GetIntField(target, AwtComponent::xID); - jint y = env->GetIntField(target, AwtComponent::yID); - jint width = env->GetIntField(target, AwtComponent::widthID); - jint height = env->GetIntField(target, AwtComponent::heightID); - /* * Initialize icon as inherited from parent if it exists */ @@ -1151,13 +1135,7 @@ AwtWindow* AwtWindow::Create(jobject self, jobject parent) window->m_iconInherited = TRUE; } window->DoUpdateIcon(); - - - /* - * Reshape here instead of during create, so that a WM_NCCALCSIZE - * is sent. - */ - window->Reshape(x, y, width, height); + window->RecalcNonClient(); } } catch (...) { env->DeleteLocalRef(target); @@ -1215,6 +1193,48 @@ void AwtWindow::moveToDefaultLocation() { VERIFY(::SetWindowPos(GetHWnd(), NULL, defLoc.left, defLoc.top, 0, 0, SWP_NOSIZE | SWP_NOZORDER)); } +/** + * Override AwtComponent::Reshape() to handle absolute screen coordinates used + * by the top-level windows. + */ +void AwtWindow::Reshape(int x, int y, int w, int h) { + if (IsEmbeddedFrame()) { + // Not the "real" top level window + return AwtComponent::Reshape(x, y, w, h); + } + // Yes, use x,y in user's space to find the nearest monitor in device space. + POINT pt = {x + w / 2, y + h / 2}; + Devices::InstanceAccess devices; + HMONITOR monitor = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST); + int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(monitor); + AwtWin32GraphicsDevice *device = devices->GetDevice(screen); + // Try to set the correct size and jump to the correct location, even if it is + // on the different monitor. Note that for the "size" we use the current + // monitor, so the WM_DPICHANGED will adjust it for the "target" monitor. + int scaleUpAbsX = device == NULL ? x : device->ScaleUpAbsX(x); + int scaleUpAbsY = device == NULL ? y : device->ScaleUpAbsY(y); + ReshapeNoScale(scaleUpAbsX, scaleUpAbsY, ScaleUpX(w), ScaleUpY(h)); + // The window manager may tweak the size for different reasons, so try + // to make sure our window has the correct size in the user's space. + // NOOP if the size was changed already or changing is in progress. + RECT rc; + ::GetWindowRect(GetHWnd(), &rc); + ReshapeNoScale(rc.left, rc.top, ScaleUpX(w), ScaleUpY(h)); + // the window manager may ignore our "SetWindowPos" request, in this, + // case the WmMove/WmSize will not come and we need to manually resync + // the "java.awt.Window" locations, because "java.awt.Window" already + // uses location ignored by the window manager. + ::GetWindowRect(GetHWnd(), &rc); + if (x != ScaleDownAbsX(rc.left) || y != ScaleDownAbsY(rc.top)) { + WmMove(rc.left, rc.top); + } + int userW = ScaleDownX(rc.right - rc.left); + int userH = ScaleDownY(rc.bottom - rc.top); + if (w != userW || h != userH) { + WmSize(SIZENORMAL, rc.right - rc.left, rc.bottom - rc.top); + } +} + void AwtWindow::Show() { m_visible = true; @@ -1774,6 +1794,15 @@ MsgRouting AwtWindow::WmShowWindow(BOOL show, UINT status) return AwtCanvas::WmShowWindow(show, status); } +void AwtWindow::WmDPIChanged(const LPARAM &lParam) { + // need to update the scales now, otherwise the ReshapeNoScale() will + // calculate the bounds wrongly + AwtWin32GraphicsDevice::ResetAllDesktopScales(); + RECT *r = (RECT *) lParam; + ReshapeNoScale(r->left, r->top, r->right - r->left, r->bottom - r->top); + CheckIfOnNewScreen(true); +} + /* * Override AwtComponent's move handling to first update the * java AWT target's position fields directly, since Windows @@ -1789,30 +1818,21 @@ MsgRouting AwtWindow::WmMove(int x, int y) // NOTE: See also AwtWindow::Reshape return mrDoDefault; } - - if (m_screenNum == -1) { - // Set initial value - m_screenNum = GetScreenImOn(); - } - else { - CheckIfOnNewScreen(); - } + // Check for the new screen and update the java peer + CheckIfOnNewScreen(false); // postpone if different DPI /* Update the java AWT target component's fields directly */ JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); if (env->EnsureLocalCapacity(1) < 0) { return mrConsume; } - jobject peer = GetPeer(env); - jobject target = env->GetObjectField(peer, AwtObject::targetID); + jobject target = GetTarget(env); RECT rect; ::GetWindowRect(GetHWnd(), &rect); - (env)->SetIntField(target, AwtComponent::xID, ScaleDownX(rect.left)); - (env)->SetIntField(target, AwtComponent::yID, ScaleDownY(rect.top)); - (env)->SetIntField(peer, AwtWindow::sysXID, ScaleDownX(rect.left)); - (env)->SetIntField(peer, AwtWindow::sysYID, ScaleDownY(rect.top)); + (env)->SetIntField(target, AwtComponent::xID, ScaleDownAbsX(rect.left)); + (env)->SetIntField(target, AwtComponent::yID, ScaleDownAbsY(rect.top)); SendComponentEvent(java_awt_event_ComponentEvent_COMPONENT_MOVED); env->DeleteLocalRef(target); @@ -1857,13 +1877,22 @@ MsgRouting AwtWindow::WmSizing() MsgRouting AwtWindow::WmEnterSizeMove() { m_winSizeMove = TRUE; + // Below is a workaround, see CheckWindowDPIChange + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* device = devices->GetDevice(m_screenNum); + if (device) { + prevScaleRec.screen = m_screenNum; + prevScaleRec.scaleX = device->GetScaleX(); + prevScaleRec.scaleY = device->GetScaleY(); + } + // Above is a workaround return mrDoDefault; } MsgRouting AwtWindow::WmExitSizeMove() { m_winSizeMove = FALSE; - CheckWindowDPIChange(); + CheckWindowDPIChange(); // workaround return mrDoDefault; } @@ -1880,6 +1909,8 @@ MsgRouting AwtWindow::WmSize(UINT type, int w, int h) UpdateSecurityWarningVisibility(); return mrDoDefault; } + // Check for the new screen and update the java peer + CheckIfOnNewScreen(false); // postpone if different DPI JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); if (env->EnsureLocalCapacity(1) < 0) @@ -1887,15 +1918,8 @@ MsgRouting AwtWindow::WmSize(UINT type, int w, int h) jobject target = GetTarget(env); // fix 4167248 : ensure the insets are up-to-date before using BOOL insetsChanged = UpdateInsets(NULL); - int newWidth = w + m_insets.left + m_insets.right; - int newHeight = h + m_insets.top + m_insets.bottom; - - (env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(newWidth)); - (env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(newHeight)); - - jobject peer = GetPeer(env); - (env)->SetIntField(peer, AwtWindow::sysWID, ScaleDownX(newWidth)); - (env)->SetIntField(peer, AwtWindow::sysHID, ScaleDownY(newHeight)); + (env)->SetIntField(target, AwtComponent::widthID, ScaleDownX(w)); + (env)->SetIntField(target, AwtComponent::heightID, ScaleDownY(h)); if (!AwtWindow::IsResizing()) { WindowResized(); @@ -1977,6 +2001,11 @@ LRESULT AwtWindow::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) LRESULT retValue = 0L; switch(message) { + case WM_DPICHANGED: { + WmDPIChanged(lParam); + mr = mrConsume; + break; + } case WM_GETICON: mr = WmGetIcon(wParam, retValue); break; @@ -2120,14 +2149,28 @@ int AwtWindow::GetScreenImOn() { return scrnNum; } -/* Check to see if we've been moved onto another screen. +/* + * Check to see if we've been moved onto another screen. * If so, update internal data, surfaces, etc. */ - -void AwtWindow::CheckIfOnNewScreen() { +void AwtWindow::CheckIfOnNewScreen(BOOL force) { int curScrn = GetScreenImOn(); if (curScrn != m_screenNum) { // we've been moved + // if moved from one monitor to another with different DPI, we should + // update the m_screenNum only if the size was updated as well in the + // WM_DPICHANGED. + Devices::InstanceAccess devices; + AwtWin32GraphicsDevice* oldDevice = devices->GetDevice(m_screenNum); + AwtWin32GraphicsDevice* newDevice = devices->GetDevice(curScrn); + if (!force && m_winSizeMove && oldDevice && newDevice) { + if (oldDevice->GetScaleX() != newDevice->GetScaleX() + || oldDevice->GetScaleY() != newDevice->GetScaleY()) { + // scales are different, wait for WM_DPICHANGED + return; + } + } + JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); jclass peerCls = env->GetObjectClass(m_peerObject); @@ -2149,65 +2192,37 @@ void AwtWindow::CheckIfOnNewScreen() { } } +// The shared code is not ready to the top-level window which crosses a few +// monitors with different DPI. Popup windows will start to use wrong screen, +// will be placed in the wrong place and will use the wrong size, see 8249164 +// So we will "JUMP TO" the new screen. void AwtWindow::CheckWindowDPIChange() { - - if (prevScaleRec.screen != -1 ) { - float prevScaleX = prevScaleRec.scaleX; - float prevScaleY = prevScaleRec.scaleY; - - if (prevScaleX >= 1 && prevScaleY >= 1) { - Devices::InstanceAccess devices; - AwtWin32GraphicsDevice* device = devices->GetDevice(m_screenNum); - if (device) { - float scaleX = device->GetScaleX(); - float scaleY = device->GetScaleY(); - if (prevScaleX != scaleX || prevScaleY != scaleY) { - WindowDPIChange(prevScaleRec.screen, prevScaleX, prevScaleY, - m_screenNum, scaleX, scaleY); - } - } - } - prevScaleRec.screen = -1; - } -} - -void AwtWindow::WindowDPIChange(int prevScreen, - float prevScaleX, float prevScaleY, - int screen, float scaleX, - float scaleY) -{ - int x; - int y; - int w; - int h; - RECT rect; - - if (prevScaleX == scaleX && prevScaleY == scaleY) { - return; - } - - ::GetWindowRect(GetHWnd(), &rect); - x = rect.left; - y = rect.top; - w = (rect.right - rect.left) * scaleX / prevScaleX; - h = (rect.bottom - rect.top) * scaleY / prevScaleY; - - if (prevScreen != screen) { + if (prevScaleRec.screen != -1 && prevScaleRec.screen != m_screenNum) { Devices::InstanceAccess devices; - AwtWin32GraphicsDevice* device = devices->GetDevice(screen); + AwtWin32GraphicsDevice *device = devices->GetDevice(m_screenNum); if (device) { - RECT bounds; - if (MonitorBounds(device->GetMonitor(), &bounds)) { - x = x < bounds.left ? bounds.left : x; - y = y < bounds.top ? bounds.top : y; - - x = (x + w > bounds.right) ? bounds.right - w : x; - y = (y + h > bounds.bottom) ? bounds.bottom - h : y; + if (prevScaleRec.scaleX != device->GetScaleX() + || prevScaleRec.scaleY != device->GetScaleY()) { + RECT rect; + ::GetWindowRect(GetHWnd(), &rect); + int x = rect.left; + int y = rect.top; + int w = rect.right - rect.left; + int h = rect.bottom - rect.top; + RECT bounds; + if (MonitorBounds(device->GetMonitor(), &bounds)) { + x = x < bounds.left ? bounds.left : x; + y = y < bounds.top ? bounds.top : y; + x = (x + w > bounds.right) ? bounds.right - w : x; + y = (y + h > bounds.bottom) ? bounds.bottom - h : y; + } + ReshapeNoScale(x, y, w, h); } } + prevScaleRec.screen = -1; + prevScaleRec.scaleX = -1.0f; + prevScaleRec.scaleY = -1.0f; } - - ReshapeNoScale(x, y, w, h); } BOOL AwtWindow::IsFocusableWindow() { @@ -2582,15 +2597,11 @@ void AwtWindow::_ReshapeFrame(void *param) { env->SetIntField(target, AwtComponent::widthID, w = minWidth); - env->SetIntField(peer, AwtWindow::sysWID, - w); } if (h < minHeight) { env->SetIntField(target, AwtComponent::heightID, h = minHeight); - env->SetIntField(peer, AwtWindow::sysHID, - h); } } env->DeleteLocalRef(target); @@ -3257,39 +3268,6 @@ void AwtWindow::_GetNativeWindowSize(void* param) { env->DeleteGlobalRef(self); } -void AwtWindow::_WindowDPIChange(void* param) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - ScaleStruct *ss = (ScaleStruct *)param; - jobject self = ss->window; - jint prevScreen = ss->prevScreen; - jfloat prevScaleX = ss->prevScaleX; - jfloat prevScaleY = ss->prevScaleY; - jint screen = ss->screen; - jfloat scaleX = ss->scaleX; - jfloat scaleY = ss->scaleY; - - PDATA pData; - JNI_CHECK_PEER_GOTO(self, ret); - AwtWindow *window = (AwtWindow *)pData; - - if (window->m_winSizeMove) { - if (window->prevScaleRec.screen == -1) { - window->prevScaleRec.screen = prevScreen; - window->prevScaleRec.scaleX = prevScaleX; - window->prevScaleRec.scaleY = prevScaleY; - } - } - else { - window->WindowDPIChange(prevScreen, prevScaleX, prevScaleY, - screen, scaleX, scaleY); - } - -ret: - env->DeleteGlobalRef(self); - delete ss; -} extern "C" int getSystemMetricValue(int msgType); extern "C" { @@ -3347,11 +3325,6 @@ Java_sun_awt_windows_WWindowPeer_initIDs(JNIEnv *env, jclass cls) { TRY; - CHECK_NULL(AwtWindow::sysXID = env->GetFieldID(cls, "sysX", "I")); - CHECK_NULL(AwtWindow::sysYID = env->GetFieldID(cls, "sysY", "I")); - CHECK_NULL(AwtWindow::sysWID = env->GetFieldID(cls, "sysW", "I")); - CHECK_NULL(AwtWindow::sysHID = env->GetFieldID(cls, "sysH", "I")); - AwtWindow::windowTypeID = env->GetFieldID(cls, "windowType", "Ljava/awt/Window$Type;"); @@ -3991,33 +3964,6 @@ Java_sun_awt_windows_WWindowPeer_repositionSecurityWarning(JNIEnv *env, CATCH_BAD_ALLOC; } -/* -* Class: sun_awt_windows_WWindowPeer -* Method: windowDPIChange -* Signature: (IFFIFF)V -*/ -JNIEXPORT void JNICALL -Java_sun_awt_windows_WWindowPeer_windowDPIChange(JNIEnv *env, jobject self, - jint prevScreen, jfloat prevScaleX, jfloat prevScaleY, - jint screen, jfloat scaleX, jfloat scaleY) -{ - TRY; - - ScaleStruct *ss = new ScaleStruct; - ss->window = env->NewGlobalRef(self); - ss->prevScreen = prevScreen; - ss->prevScaleX = prevScaleX; - ss->prevScaleY = prevScaleY; - ss->screen = screen; - ss->scaleX = scaleX; - ss->scaleY = scaleY; - - AwtToolkit::GetInstance().InvokeFunction(AwtWindow::_WindowDPIChange, ss); - // global refs and ss are deleted in _WindowDPIChange - - CATCH_BAD_ALLOC; -} - /* * Class: sun_awt_windows_WLightweightFramePeer * Method: overrideNativeHandle diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Window.h b/src/java.desktop/windows/native/libawt/windows/awt_Window.h index 38f012864df..6e035cc8f38 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Window.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Window.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,12 +58,6 @@ class AwtWindow : public AwtCanvas { static jfieldID securityWarningHeightID; /* sun.awt.windows.WWindowPeer field and method IDs */ - // The coordinates at the peer. - static jfieldID sysXID; - static jfieldID sysYID; - static jfieldID sysWID; - static jfieldID sysHID; - static jfieldID windowTypeID; static jmethodID notifyWindowStateChangedMID; @@ -129,6 +123,7 @@ class AwtWindow : public AwtCanvas { return FALSE; } + virtual void Reshape(int x, int y, int w, int h); virtual void Invalidate(RECT* r); virtual void Show(); virtual void SetResizable(BOOL isResizable); @@ -136,7 +131,7 @@ class AwtWindow : public AwtCanvas { virtual void RecalcNonClient(); virtual void RedrawNonClient(); virtual int GetScreenImOn(); - virtual void CheckIfOnNewScreen(); + virtual void CheckIfOnNewScreen(BOOL force); virtual void Grab(); virtual void Ungrab(); virtual void Ungrab(BOOL doPost); @@ -248,7 +243,6 @@ class AwtWindow : public AwtCanvas { static void _RepositionSecurityWarning(void* param); static void _SetFullScreenExclusiveModeState(void* param); static void _GetNativeWindowSize(void* param); - static void _WindowDPIChange(void* param); static void _OverrideHandle(void *param); inline static BOOL IsResizing() { @@ -409,8 +403,7 @@ class AwtWindow : public AwtCanvas { void InitOwner(AwtWindow *owner); void CheckWindowDPIChange(); - void WindowDPIChange(int prevScreen, float prevScaleX, float prevScaleY, - int newScreen, float scaleX, float scaleY); + void WmDPIChanged(const LPARAM &lParam); Type m_windowType; void InitType(JNIEnv *env, jobject peer); diff --git a/src/java.desktop/windows/native/libawt/windows/awtmsg.h b/src/java.desktop/windows/native/libawt/windows/awtmsg.h index ba8a4492591..c4f85fad41c 100644 --- a/src/java.desktop/windows/native/libawt/windows/awtmsg.h +++ b/src/java.desktop/windows/native/libawt/windows/awtmsg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,6 +41,10 @@ extern const UINT SYSCOMMAND_IMM; * See winuser.h for details. */ +#ifndef WM_DPICHANGED +#define WM_DPICHANGED 0x02E0 +#endif //WM_DPICHANGED + #ifndef WM_MOUSEWHEEL #define WM_MOUSEWHEEL 0x020A #endif //WM_MOUSEWHEEL diff --git a/src/java.logging/share/classes/java/util/logging/LogManager.java b/src/java.logging/share/classes/java/util/logging/LogManager.java index 7c301f8ad7c..a181910e94b 100644 --- a/src/java.logging/share/classes/java/util/logging/LogManager.java +++ b/src/java.logging/share/classes/java/util/logging/LogManager.java @@ -1920,7 +1920,7 @@ public void updateConfiguration(Function *

  • * - * + * * * - * + * * * - * + * * * - * + * * * - * + * *
    {@code .level}{@code .level} *
      *
    • If the resulting configuration defines a level for a logger and @@ -1941,7 +1941,7 @@ public void updateConfiguration(Function *
    {@code .useParentHandlers}{@code .useParentHandlers} *
      *
    • If either the resulting or the old value for the useParentHandlers @@ -1955,7 +1955,7 @@ public void updateConfiguration(Function *
    {@code .handlers}{@code .handlers} *
      *
    • If the resulting configuration defines a list of handlers for a @@ -1979,7 +1979,7 @@ public void updateConfiguration(Function *
    {@code .*}{@code .*} *
      *
    • Properties configured/changed on handler classes will only affect @@ -1991,7 +1991,7 @@ public void updateConfiguration(Function *
    {@code config} and any other property{@code config} and any other property *
      *
    • The resulting value for these property will be stored in the diff --git a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMReference.java b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMReference.java index b2ec7815af0..c44ffd93b45 100644 --- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMReference.java +++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMReference.java @@ -500,38 +500,44 @@ private byte[] transform(Data dereferencedData, } boolean secVal = Utils.secureValidation(context); - xi.setSecureValidation(secVal); - if (context instanceof XMLSignContext && c14n11 - && !xi.isOctetStream() && !xi.isOutputStreamSet()) { - TransformService spi = null; - if (provider == null) { - spi = TransformService.getInstance(c14nalg, "DOM"); - } else { - try { - spi = TransformService.getInstance(c14nalg, "DOM", provider); - } catch (NoSuchAlgorithmException nsae) { + try { + xi.setSecureValidation(secVal); + if (context instanceof XMLSignContext && c14n11 + && !xi.isOctetStream() && !xi.isOutputStreamSet()) { + TransformService spi = null; + if (provider == null) { spi = TransformService.getInstance(c14nalg, "DOM"); + } else { + try { + spi = TransformService.getInstance(c14nalg, "DOM", provider); + } catch (NoSuchAlgorithmException nsae) { + spi = TransformService.getInstance(c14nalg, "DOM"); + } } - } - DOMTransform t = new DOMTransform(spi); - Element transformsElem = null; - String dsPrefix = DOMUtils.getSignaturePrefix(context); - if (allTransforms.isEmpty()) { - transformsElem = DOMUtils.createElement( - refElem.getOwnerDocument(), - "Transforms", XMLSignature.XMLNS, dsPrefix); - refElem.insertBefore(transformsElem, - DOMUtils.getFirstChildElement(refElem)); + DOMTransform t = new DOMTransform(spi); + Element transformsElem = null; + String dsPrefix = DOMUtils.getSignaturePrefix(context); + if (allTransforms.isEmpty()) { + transformsElem = DOMUtils.createElement( + refElem.getOwnerDocument(), + "Transforms", XMLSignature.XMLNS, dsPrefix); + refElem.insertBefore(transformsElem, + DOMUtils.getFirstChildElement(refElem)); + } else { + transformsElem = DOMUtils.getFirstChildElement(refElem); + } + t.marshal(transformsElem, dsPrefix, + (DOMCryptoContext) context); + allTransforms.add(t); + xi.updateOutputStream(os, true); } else { - transformsElem = DOMUtils.getFirstChildElement(refElem); + xi.updateOutputStream(os); + } + } finally { + if(xi.getOctetStreamReal() != null) { + xi.getOctetStreamReal().close(); } - t.marshal(transformsElem, dsPrefix, - (DOMCryptoContext)context); - allTransforms.add(t); - xi.updateOutputStream(os, true); - } else { - xi.updateOutputStream(os); } } os.flush(); diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java index bdd4fb5673d..247e3edc2a3 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/BindingPatternTree.java @@ -25,34 +25,17 @@ package com.sun.source.tree; -import javax.lang.model.element.Name; - /** - * {@preview Associated with pattern matching for instanceof, a preview feature of - * the Java language. - * - * This interface is associated with pattern matching for instanceof, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * A binding pattern tree * - * @since 14 + * @since 16 */ public interface BindingPatternTree extends PatternTree { /** - * Returns the type of the bind variable. - * @return the type + * Returns the binding variable. + * @return the binding variable */ - Tree getType(); - - /** - * A binding variable name. - * @return the name of the binding variable - */ - Name getBinding(); + VariableTree getVariable(); } - diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java index 1d501c5678b..ad255bcc6d0 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/InstanceOfTree.java @@ -49,18 +49,11 @@ public interface InstanceOfTree extends ExpressionTree { /** * Returns the type for which to check. * @return the type + * @see #getPattern() */ Tree getType(); /** - * {@preview Associated with pattern matching for instanceof, a preview feature of - * the Java language. - * - * This method is associated with pattern matching for instanceof, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Returns the tested pattern, or null if this instanceof does not use * a pattern. * @@ -77,7 +70,7 @@ public interface InstanceOfTree extends ExpressionTree { * returns null. * * @return the tested pattern, or null if this instanceof does not use a pattern - * @since 14 + * @since 16 */ PatternTree getPattern(); } diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java index 70ad395cd45..283fa20e63a 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/PatternTree.java @@ -26,17 +26,9 @@ package com.sun.source.tree; /** - * {@preview Associated with pattern matching for instanceof, a preview feature of - * the Java language. - * - * This interface is associated with pattern matching for instanceof, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * A tree node used as the base class for the different kinds of - * statements. + * patterns. * - * @since 14 + * @since 16 */ public interface PatternTree extends Tree {} diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java index 79e552340a7..9b9d00c4202 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java @@ -220,17 +220,9 @@ public enum Kind { PARENTHESIZED(ParenthesizedTree.class), /** - * {@preview Associated with pattern matching for instanceof, a preview feature of - * the Java language. - * - * This enum constant is associated with pattern matching for instanceof, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Used for instances of {@link BindingPatternTree}. * - * @since 14 + * @since 16 */ BINDING_PATTERN(BindingPatternTree.class), diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java index e84687c497f..b238e19812e 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/TreeVisitor.java @@ -258,19 +258,11 @@ public interface TreeVisitor { R visitLiteral(LiteralTree node, P p); /** - * {@preview Associated with pattern matching for instanceof, a preview feature of - * the Java language. - * - * This method is associated with pattern matching for instanceof, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Visits an BindingPattern node. * @param node the node being visited * @param p a parameter value * @return a result value - * @since 14 + * @since 16 */ R visitBindingPattern(BindingPatternTree node, P p); diff --git a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java index 66489b7fa3f..abc47afcefa 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java +++ b/src/jdk.compiler/share/classes/com/sun/source/util/TreeScanner.java @@ -705,7 +705,7 @@ public R visitInstanceOf(InstanceOfTree node, P p) { */ @Override public R visitBindingPattern(BindingPatternTree node, P p) { - return scan(node.getType(), p); + return scan(node.getVariable(), p); } /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index b81adaa7583..24a83c6a953 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -165,9 +165,7 @@ public boolean isEnabled() { * @return true, if given feature is a preview feature. */ public boolean isPreview(Feature feature) { - if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF || - feature == Feature.REIFIABLE_TYPES_INSTANCEOF || - feature == Feature.SEALED_CLASSES) + if (feature == Feature.SEALED_CLASSES) return true; //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing). //When real preview features will be added, this method can be implemented to return 'true' diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java index 8b7bd50a488..3045f21703d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java @@ -1915,6 +1915,8 @@ public static class RecordComponent extends VarSymbol implements RecordComponent */ private final int pos; + private final boolean isVarargs; + /** * Construct a record component, given its flags, name, type and owner. */ @@ -1922,12 +1924,18 @@ public RecordComponent(JCVariableDecl fieldDecl, List annotations) super(PUBLIC, fieldDecl.sym.name, fieldDecl.sym.type, fieldDecl.sym.owner); this.originalAnnos = annotations; this.pos = fieldDecl.pos; + /* it is better to store the original information for this one, instead of relying + * on the info in the type of the symbol. This is because on the presence of APs + * the symbol will be blown out and we won't be able to know if the original + * record component was declared varargs or not. + */ + this.isVarargs = type.hasTag(TypeTag.ARRAY) && ((ArrayType)type).isVarargs(); } public List getOriginalAnnos() { return originalAnnos; } public boolean isVarargs() { - return type.hasTag(TypeTag.ARRAY) && ((ArrayType)type).isVarargs(); + return isVarargs; } @Override @DefinedBy(Api.LANGUAGE_MODEL) @@ -1977,7 +1985,7 @@ public Name getSimpleName() { public static class BindingSymbol extends VarSymbol { public BindingSymbol(Name name, Type type, Symbol owner) { - super(Flags.FINAL | Flags.HASINIT | Flags.MATCH_BINDING, name, type, owner); + super(Flags.HASINIT | Flags.MATCH_BINDING, name, type, owner); } public boolean isAliasFor(BindingSymbol b) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java index 173aa65b611..a3976984824 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java @@ -951,9 +951,8 @@ private Attribute.TypeCompound toTypeCompound(Attribute.Compound a, TypeAnnotati " within frame " + frame); } - case BINDING_PATTERN: case VARIABLE: - VarSymbol v = frame.hasTag(Tag.BINDINGPATTERN) ? ((JCBindingPattern) frame).symbol : ((JCVariableDecl) frame).sym; + VarSymbol v = ((JCVariableDecl) frame).sym; if (v.getKind() != ElementKind.FIELD) { appendTypeAnnotationsToOwner(v, v.getRawTypeAttributes()); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 46387dbed9d..685ffec2f5a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -318,8 +318,6 @@ void checkAssignable(DiagnosticPosition pos, VarSymbol v, JCTree base, Env= firstadr || sym.owner.kind != TYP) && trackable(sym) && - !inits.isMember(sym.adr)) { + !inits.isMember(sym.adr) && + (sym.flags_field & CLASH) == 0) { log.error(pos, errkey); inits.incl(sym.adr); } @@ -2825,6 +2826,12 @@ public void visitIdent(JCIdent tree) { } } + @Override + public void visitBindingPattern(JCBindingPattern tree) { + super.visitBindingPattern(tree); + initParam(tree.var); + } + void referenced(Symbol sym) { unrefdResources.remove(sym); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java index 07e48ff1838..9b389443456 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MatchBindingsComputer.java @@ -148,6 +148,7 @@ private List intersection(DiagnosticPosition pos, List union(DiagnosticPosition pos, List //(let T' N$temp = E; N$temp instanceof T && (N = (T) N$temp == (T) N$temp)) JCBindingPattern patt = (JCBindingPattern)tree.pattern; - VarSymbol pattSym = patt.symbol; + VarSymbol pattSym = patt.var.sym; Type tempType = tree.expr.type.hasTag(BOT) ? syms.objectType : tree.expr.type; VarSymbol temp = new VarSymbol(pattSym.flags() | Flags.SYNTHETIC, names.fromString(pattSym.name.toString() + target.syntheticNameChar() + "temp"), tempType, - patt.symbol.owner); + patt.var.sym.owner); JCExpression translatedExpr = translate(tree.expr); Type castTargetType = types.boxedTypeOrType(pattSym.erasure(types)); result = makeTypeTest(make.Ident(temp), make.Type(castTargetType)); - VarSymbol bindingVar = bindingContext.bindingDeclared(patt.symbol); + VarSymbol bindingVar = bindingContext.bindingDeclared((BindingSymbol) patt.var.sym); if (bindingVar != null) { //TODO: cannot be null here? JCAssign fakeInit = (JCAssign)make.at(tree.pos).Assign( make.Ident(bindingVar), convert(make.Ident(temp), castTargetType)).setType(bindingVar.erasure(types)); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java index dd6461df6c4..504c281c70b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -582,9 +582,7 @@ public void visitCase(JCCase tree) { } public void visitBindingPattern(JCBindingPattern tree) { - if (tree.vartype != null) { - tree.vartype = translate(tree.vartype, null); - } + tree.var = translate(tree.var, null); result = tree; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java index 124fa61f4e8..971abe63a42 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeDiffer.java @@ -257,13 +257,10 @@ && scan(tree.rhs, that.rhs) @Override public void visitBindingPattern(JCBindingPattern tree) { JCBindingPattern that = (JCBindingPattern) parameter; - result = - scan(tree.vartype, that.vartype) - && tree.name == that.name; + result = scan(tree.var, that.var); if (!result) { return; } - equiv.put(tree.symbol, that.symbol); } @Override diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java index 22e49a9d0da..a0eec4ca91d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TreeHasher.java @@ -106,12 +106,6 @@ public void visitSelect(JCFieldAccess tree) { super.visitSelect(tree); } - @Override - public void visitBindingPattern(JCTree.JCBindingPattern tree) { - symbolHashes.computeIfAbsent(tree.symbol, k -> symbolHashes.size()); - super.visitBindingPattern(tree); - } - @Override public void visitVarDef(JCVariableDecl tree) { symbolHashes.computeIfAbsent(tree.sym, k -> symbolHashes.size()); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index d8e4888852e..b5345ec2880 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -2640,10 +2640,12 @@ private void readClassBuffer(ClassSymbol c) throws IOException { majorVersion = nextChar(); int maxMajor = Version.MAX().major; int maxMinor = Version.MAX().minor; + boolean previewClassFile = + minorVersion == ClassFile.PREVIEW_MINOR_VERSION; if (majorVersion > maxMajor || majorVersion * 1000 + minorVersion < Version.MIN().major * 1000 + Version.MIN().minor) { - if (majorVersion == (maxMajor + 1)) + if (majorVersion == (maxMajor + 1) && !previewClassFile) log.warning(Warnings.BigMajorVersion(currentClassFile, majorVersion, maxMajor)); @@ -2655,7 +2657,7 @@ private void readClassBuffer(ClassSymbol c) throws IOException { Integer.toString(maxMinor)); } - if (minorVersion == ClassFile.PREVIEW_MINOR_VERSION) { + if (previewClassFile) { if (!preview.isEnabled()) { log.error(preview.disabledError(currentClassFile, majorVersion)); } else { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index 705446ffa42..c00ece5204f 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -963,10 +963,18 @@ JCExpression term2Rest(JCExpression t, int minprec) { if (token.kind == INSTANCEOF) { int pos = token.pos; nextToken(); - JCTree pattern = parseType(); + int typePos = token.pos; + JCExpression type = parseType(); + JCTree pattern; if (token.kind == IDENTIFIER) { checkSourceLevel(token.pos, Feature.PATTERN_MATCHING_IN_INSTANCEOF); - pattern = toP(F.at(token.pos).BindingPattern(ident(), pattern)); + JCModifiers mods = F.at(Position.NOPOS).Modifiers(0); + JCVariableDecl var = toP(F.at(token.pos).VarDef(mods, ident(), type, null)); + TreeInfo.getStartPos(var); + pattern = toP(F.at(typePos).BindingPattern(var)); + TreeInfo.getStartPos(pattern); + } else { + pattern = type; } odStack[top] = F.at(pos).TypeTest(odStack[top], pattern); } else { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 77d769ac75a..3efd070b62d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -549,10 +549,6 @@ compiler.err.final.parameter.may.not.be.assigned=\ compiler.err.try.resource.may.not.be.assigned=\ auto-closeable resource {0} may not be assigned -# 0: symbol -compiler.err.pattern.binding.may.not.be.assigned=\ - pattern binding {0} may not be assigned - # 0: symbol compiler.err.multicatch.parameter.may.not.be.assigned=\ multi-catch parameter {0} may not be assigned @@ -624,9 +620,6 @@ compiler.err.illegal.self.ref=\ compiler.warn.self.ref=\ self-reference in initializer of variable ''{0}'' -compiler.err.illegal.generic.type.for.instof=\ - illegal generic type for instanceof - # 0: type compiler.err.illegal.initializer.for.type=\ illegal initializer for {0} @@ -1422,6 +1415,10 @@ compiler.misc.varargs.trustme.on.reifiable.varargs=\ compiler.err.instanceof.reifiable.not.safe=\ {0} cannot be safely cast to {1} +# 0: type, 1: type +compiler.err.instanceof.pattern.no.subtype=\ + pattern type {0} is a subtype of expression type {1} + # 0: symbol compiler.misc.varargs.trustme.on.non.varargs.meth=\ Method {0} is not a varargs method. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java index c08bceff469..882ba6abc5e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java @@ -2200,7 +2200,7 @@ protected JCInstanceOf(JCExpression expr, JCTree pattern) { @DefinedBy(Api.COMPILER_TREE) public Kind getKind() { return Kind.INSTANCE_OF; } @DefinedBy(Api.COMPILER_TREE) - public JCTree getType() { return pattern instanceof JCPattern ? pattern.hasTag(BINDINGPATTERN) ? ((JCBindingPattern) pattern).vartype : null : pattern; } + public JCTree getType() { return pattern instanceof JCPattern ? pattern.hasTag(BINDINGPATTERN) ? ((JCBindingPattern) pattern).var.vartype : null : pattern; } @Override @DefinedBy(Api.COMPILER_TREE) public JCPattern getPattern() { @@ -2224,31 +2224,19 @@ public Tag getTag() { */ public static abstract class JCPattern extends JCTree implements PatternTree { - public JCExpression constExpression() { - return null; - } } public static class JCBindingPattern extends JCPattern implements BindingPatternTree { - public Name name; - public BindingSymbol symbol; - public JCTree vartype; - - protected JCBindingPattern(Name name, BindingSymbol symbol, JCTree vartype) { - this.name = name; - this.symbol = symbol; - this.vartype = vartype; - } + public JCVariableDecl var; - @DefinedBy(Api.COMPILER_TREE) - public Name getBinding() { - return name; + protected JCBindingPattern(JCVariableDecl var) { + this.var = var; } @Override @DefinedBy(Api.COMPILER_TREE) - public Tree getType() { - return vartype; + public VariableTree getVariable() { + return var; } @Override @@ -3247,7 +3235,7 @@ JCNewArray NewArray(JCExpression elemtype, JCBinary Binary(Tag opcode, JCExpression lhs, JCExpression rhs); JCTypeCast TypeCast(JCTree expr, JCExpression type); JCInstanceOf TypeTest(JCExpression expr, JCTree clazz); - JCBindingPattern BindingPattern(Name name, JCTree vartype); + JCBindingPattern BindingPattern(JCVariableDecl var); JCArrayAccess Indexed(JCExpression indexed, JCExpression index); JCFieldAccess Select(JCExpression selected, Name selector); JCIdent Ident(Name idname); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java index ea9794054ec..b961e979c2e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -907,9 +907,7 @@ public void visitSwitchExpression(JCSwitchExpression tree) { public void visitBindingPattern(JCBindingPattern patt) { try { - printExpr(patt.vartype); - print(" "); - print(patt.name); + printExpr(patt.var); } catch (IOException e) { throw new UncheckedIOException(e); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java index 7dcf0145ff0..c18b05e046b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeCopier.java @@ -495,8 +495,8 @@ public JCTree visitInstanceOf(InstanceOfTree node, P p) { @DefinedBy(Api.COMPILER_TREE) public JCTree visitBindingPattern(BindingPatternTree node, P p) { JCBindingPattern t = (JCBindingPattern) node; - JCTree vartype = copy(t.vartype, p); - return M.at(t.pos).BindingPattern(t.name, vartype); + JCVariableDecl var = copy(t.var, p); + return M.at(t.pos).BindingPattern(var); } @DefinedBy(Api.COMPILER_TREE) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index 8874a94dfcc..c702b6c91ab 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -39,6 +39,7 @@ import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.Kind.*; +import com.sun.tools.javac.code.Symbol.VarSymbol; import static com.sun.tools.javac.code.TypeTag.BOT; import static com.sun.tools.javac.tree.JCTree.Tag.*; import static com.sun.tools.javac.tree.JCTree.Tag.BLOCK; @@ -538,7 +539,7 @@ public static int getStartPos(JCTree tree) { } case BINDINGPATTERN: { JCBindingPattern node = (JCBindingPattern)tree; - return getStartPos(node.vartype); + return getStartPos(node.var); } case ERRONEOUS: { JCErroneous node = (JCErroneous)tree; @@ -931,8 +932,6 @@ private static Symbol symbolForImpl(JCTree node) { if (node.type != null) return node.type.tsym; return null; - case BINDINGPATTERN: - return ((JCBindingPattern) node).symbol; default: return null; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java index 64740646eef..57fb4a19ba5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeMaker.java @@ -482,8 +482,8 @@ public JCInstanceOf TypeTest(JCExpression expr, JCTree clazz) { return tree; } - public JCBindingPattern BindingPattern(Name name, JCTree vartype) { - JCBindingPattern tree = new JCBindingPattern(name, null, vartype); + public JCBindingPattern BindingPattern(JCVariableDecl var) { + JCBindingPattern tree = new JCBindingPattern(var); tree.pos = pos; return tree; } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java index c0cb1c9aa53..85a3b761788 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeScanner.java @@ -309,8 +309,7 @@ public void visitTypeTest(JCInstanceOf tree) { } public void visitBindingPattern(JCBindingPattern tree) { - if (tree.vartype != null) - scan(tree.vartype); + scan(tree.var); } public void visitIndexed(JCArrayAccess tree) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java index a91b8c45117..7959029eecc 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeTranslator.java @@ -365,7 +365,7 @@ public void visitTypeTest(JCInstanceOf tree) { } public void visitBindingPattern(JCBindingPattern tree) { - tree.vartype = translate(tree.vartype); + tree.var = translate(tree.var); result = tree; } diff --git a/test/langtools/tools/javac/diags/examples/PatternBindingMayNotBeAssigned.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorDeflationThread.java similarity index 66% rename from test/langtools/tools/javac/diags/examples/PatternBindingMayNotBeAssigned.java rename to src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorDeflationThread.java index 01e48518d74..8bd6492f880 100644 --- a/test/langtools/tools/javac/diags/examples/PatternBindingMayNotBeAssigned.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/MonitorDeflationThread.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -19,17 +19,23 @@ * 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. + * */ -// key: compiler.err.pattern.binding.may.not.be.assigned -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} +package sun.jvm.hotspot.runtime; + +import java.io.*; + +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.types.*; + +public class MonitorDeflationThread extends JavaThread { + public MonitorDeflationThread(Address addr) { + super(addr); + } + + public boolean isJavaThread() { return false; } + public boolean isHiddenFromExternalView() { return true; } + public boolean isMonitorDeflationThread() { return true; } -class ResourceMayNotBeAssigned { - void m(Object o) { - if (o instanceof String s) { - s = ""; - } - } } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java index af18075d3b2..43ddf257d04 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ObjectMonitor.java @@ -103,10 +103,6 @@ public int contentions() { return contentionsField.getValue(addr); } - // FIXME - // oop* object_addr(); - // void set_object(oop obj); - // The following four either aren't expressed as typed fields in // vmStructs.cpp because they aren't strongly typed in the VM, or // would confuse the SA's type system. diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java index 2624773e4ca..db42ca8dd2d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Thread.java @@ -121,6 +121,7 @@ public long allocatedBytes() { public boolean isJvmtiAgentThread() { return false; } public boolean isWatcherThread() { return false; } public boolean isServiceThread() { return false; } + public boolean isMonitorDeflationThread() { return false; } /** Memory operations */ public void oopsDo(AddressVisitor oopVisitor) { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java index 80279b3d1c5..49a2a1964b1 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java @@ -149,6 +149,7 @@ private static synchronized void initialize(TypeDataBase db) { } virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class); virtualConstructor.addMapping("ServiceThread", ServiceThread.class); + virtualConstructor.addMapping("MonitorDeflationThread", MonitorDeflationThread.class); virtualConstructor.addMapping("NotificationThread", NotificationThread.class); } @@ -157,7 +158,7 @@ public Threads() { } /** NOTE: this returns objects of type JavaThread, CompilerThread, - JvmtiAgentThread, NotificationThread, and ServiceThread. + JvmtiAgentThread, NotificationThread, MonitorDeflationThread and ServiceThread. The latter four are subclasses of the former. Most operations (fetching the top frame, etc.) are only allowed to be performed on a "pure" JavaThread. For this reason, {@link @@ -188,7 +189,7 @@ public JavaThread createJavaThreadWrapper(Address threadAddr) { return thread; } catch (Exception e) { throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr + - " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread or CodeCacheSweeperThread)", e); + " (expected type JavaThread, CompilerThread, MonitorDeflationThread, ServiceThread, JvmtiAgentThread or CodeCacheSweeperThread)", e); } } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpPrincipal.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpPrincipal.java index 43db2ab0474..c393ce424a4 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpPrincipal.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpPrincipal.java @@ -75,7 +75,7 @@ public boolean equals(Object another) { * @return the contents of this principal in the form realm:username */ public String getName() { - return username; + return String.format("%s:%s", realm, username); } /** diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c b/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c index 2e273137af0..3e186406e18 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,9 +78,12 @@ get_time_stamp(char *tbuf, size_t ltbuf) "%d.%m.%Y %T", localtime(&t)); (void)strftime(timestamp_timezone, TZ_SIZE, "%Z", localtime(&t)); - (void)snprintf(tbuf, ltbuf, - "%s.%.3d %s", timestamp_date_time, - (int)(millisecs), timestamp_timezone); + + // Truncate milliseconds in buffer large enough to hold the + // value which is always < 1000 (and so a maximum of 3 digits for "%.3d") + char tmp[20]; + snprintf(tmp, sizeof(tmp), "%.3d", millisecs); + snprintf(tbuf, ltbuf, "%s.%.3s %s", timestamp_date_time, tmp, timestamp_timezone); } /* Get basename of filename */ diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 96773392fc3..40dd5d1003c 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -84,6 +84,9 @@ typedef struct ThreadNode { struct ThreadNode *prev; jlong frameGeneration; struct ThreadList *list; /* Tells us what list this thread is in */ +#ifdef DEBUG_THREADNAME + char name[256]; +#endif } ThreadNode; static jint suspendAllCount; @@ -349,6 +352,22 @@ insertThread(JNIEnv *env, ThreadList *list, jthread thread) node->eventBag = eventBag; addNode(list, node); +#ifdef DEBUG_THREADNAME + { + /* Set the thread name */ + jvmtiThreadInfo info; + jvmtiError error; + + memset(&info, 0, sizeof(info)); + error = JVMTI_FUNC_PTR(gdata->jvmti,GetThreadInfo) + (gdata->jvmti, node->thread, &info); + if (info.name != NULL) { + strncpy(node->name, info.name, sizeof(node->name) - 1); + jvmtiDeallocate(info.name); + } + } +#endif + /* Set thread local storage for quick thread -> node access. * Some threads may not be in a state that allows setting of TLS, * which is ok, see findThread, it deals with threads without TLS set. diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c index f81bfcfb4b8..3cab42abb7b 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c @@ -1008,16 +1008,9 @@ void debugMonitorEnter(jrawMonitorID monitor) { jvmtiError error; - while (JNI_TRUE) { - error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorEnter) - (gdata->jvmti, monitor); - error = ignore_vm_death(error); - if (error == JVMTI_ERROR_INTERRUPT) { - handleInterrupt(); - } else { - break; - } - } + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorEnter) + (gdata->jvmti, monitor); + error = ignore_vm_death(error); if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "on raw monitor enter"); } diff --git a/src/jdk.jpackage/windows/native/applauncher/WinLauncher.cpp b/src/jdk.jpackage/windows/native/applauncher/WinLauncher.cpp index 9baa1e9178c..eadbf35754d 100644 --- a/src/jdk.jpackage/windows/native/applauncher/WinLauncher.cpp +++ b/src/jdk.jpackage/windows/native/applauncher/WinLauncher.cpp @@ -137,6 +137,8 @@ void launchApp() { const tstring launcherPath = SysInfo::getProcessModulePath(); const tstring appImageRoot = FileUtils::dirname(launcherPath); + const tstring runtimeBinPath = FileUtils::mkpath() + << appImageRoot << _T("runtime") << _T("bin"); std::unique_ptr jvm(AppLauncher() .setImageRoot(appImageRoot) @@ -146,6 +148,10 @@ void launchApp() { << _T("runtime")) .createJvmLauncher()); + // zip.dll may be loaded by java without full path + // make sure it will look in runtime/bin + SetDllDirectory(runtimeBinPath.c_str()); + const DllWrapper jliDll(jvm->getPath()); std::unique_ptr splashDll; if (jvm->isWithSplash()) { diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java index 0d99cc3b0b2..610404b8738 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ConsoleIOContext.java @@ -833,6 +833,7 @@ public void replaceLastHistoryEntry(String source) { } it.remove(); in.getHistory().add(source); + in.getHistory().resetIndex(); } private static final long ESCAPE_TIMEOUT = 100; diff --git a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/Compilation.java b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/Compilation.java index 4fd8c517c65..caf2fe4bbf7 100644 --- a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/Compilation.java +++ b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/Compilation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,8 +221,17 @@ public void print(PrintStream stream, int indent, boolean printID, boolean print stream.print(" " + nmethod.getLevel()); } } + + String codeSize = ""; + if (nmethod != null) { + long nmethodSize = nmethod.getInstSize(); + if (nmethodSize > 0) { + codeSize = "(code size: " + nmethodSize + ")"; + } + } + int bc = isOsr() ? getBCI() : -1; - stream.print(getMethod().decodeFlags(bc) + " " + getCompiler() + " " + getMethod().format(bc)); + stream.print(getMethod().decodeFlags(bc) + " " + getCompiler() + " " + getMethod().format(bc) + codeSize); stream.println(); if (getFailureReason() != null) { stream.println("COMPILE SKIPPED: " + getFailureReason() + " (not retryable)"); diff --git a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogCompilation.java b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogCompilation.java index e6c00fde72f..d042b860cb6 100644 --- a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogCompilation.java +++ b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogCompilation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,6 +95,9 @@ public static void main(String[] args) throws Exception { } else if (a.equals("-s")) { sort = LogParser.sortByStart; index++; + } else if (a.equals("-z")) { + sort = LogParser.sortByNMethodSize; + index++; } else if (a.equals("-t")) { printTimeStamps = true; index++; diff --git a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java index 585cda0a91a..5b9c72fafe2 100644 --- a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java +++ b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/LogParser.java @@ -381,6 +381,55 @@ public int hashCode() { } }; + static Comparator sortByNMethodSize = new Comparator() { + + public int compare(LogEvent a, LogEvent b) { + Compilation c1 = a.getCompilation(); + Compilation c2 = b.getCompilation(); + if ((c1 != null && c2 == null)) { + return -1; + } else if (c1 == null && c2 != null) { + return 1; + } else if (c1 == null && c2 == null) { + return 0; + } + + if (c1.getNMethod() != null && c2.getNMethod() == null) { + return -1; + } else if (c1.getNMethod() == null && c2.getNMethod() != null) { + return 1; + } else if (c1.getNMethod() == null && c2.getNMethod() == null) { + return 0; + } + + assert c1.getNMethod() != null && c2.getNMethod() != null : "Neither should be null here"; + + long c1Size = c1.getNMethod().getInstSize(); + long c2Size = c2.getNMethod().getInstSize(); + + if (c1Size == 0 && c2Size == 0) { + return 0; + } + + if (c1Size > c2Size) { + return -1; + } else if (c1Size < c2Size) { + return 1; + } + + return 0; + } + + public boolean equals(Object other) { + return false; + } + + @Override + public int hashCode() { + return 7; + } + }; + /** * Shrink-wrapped representation of a JVMState (tailored to meet this * tool's needs). It only records a method and bytecode instruction index. @@ -1119,6 +1168,13 @@ public void startElement(String uri, String localName, String qname, Attributes if (level != null) { nm.setLevel(parseLong(level)); } + String iOffset = atts.getValue("insts_offset"); + String sOffset = atts.getValue("stub_offset"); + if (iOffset != null && sOffset != null) { + long insts_offset = parseLong(iOffset); + long stub_offset = parseLong(sOffset); + nm.setInstSize(stub_offset - insts_offset); + } String compiler = search(atts, "compiler", ""); nm.setCompiler(compiler); nmethods.put(id, nm); diff --git a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/NMethod.java b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/NMethod.java index b9b5d281dc4..35c56f8776f 100644 --- a/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/NMethod.java +++ b/src/utils/LogCompilation/src/main/java/com/sun/hotspot/tools/compiler/NMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,6 +42,11 @@ public class NMethod extends BasicLogEvent { */ private long size; + /** + * The nmethod's insts size in bytes. + */ + private long instSize; + /** * The nmethod's compilation level. */ @@ -79,6 +84,14 @@ public void setSize(long size) { this.size = size; } + public long getInstSize() { + return instSize; + } + + public void setInstSize(long size) { + this.instSize = size; + } + /** * @return the level */ diff --git a/src/utils/LogCompilation/src/test/java/com/sun/hotspot/tools/compiler/TestLogCompilation.java b/src/utils/LogCompilation/src/test/java/com/sun/hotspot/tools/compiler/TestLogCompilation.java index 2cb1d0a80cf..83762df16d6 100644 --- a/src/utils/LogCompilation/src/test/java/com/sun/hotspot/tools/compiler/TestLogCompilation.java +++ b/src/utils/LogCompilation/src/test/java/com/sun/hotspot/tools/compiler/TestLogCompilation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -177,4 +177,13 @@ public void testDashn() throws Exception { LogCompilation.main(args); } + + @Test + public void testDashz() throws Exception { + String[] args = {"-z", + logFile + }; + + LogCompilation.main(args); + } } diff --git a/test/hotspot/gtest/runtime/test_objectMonitor.cpp b/test/hotspot/gtest/runtime/test_objectMonitor.cpp index 919c43a6873..33bec3253d1 100644 --- a/test/hotspot/gtest/runtime/test_objectMonitor.cpp +++ b/test/hotspot/gtest/runtime/test_objectMonitor.cpp @@ -27,9 +27,6 @@ #include "unittest.hpp" TEST_VM(ObjectMonitor, sanity) { - - EXPECT_EQ(0, ObjectMonitor::header_offset_in_bytes()) << "Offset for _header must be zero."; - uint cache_line_size = VM_Version::L1_data_cache_line_size(); if (cache_line_size != 0) { diff --git a/test/hotspot/jtreg/compiler/codecache/stress/CodeCacheStressRunner.java b/test/hotspot/jtreg/compiler/codecache/stress/CodeCacheStressRunner.java index 24ec37b89d4..7e9c14b801e 100644 --- a/test/hotspot/jtreg/compiler/codecache/stress/CodeCacheStressRunner.java +++ b/test/hotspot/jtreg/compiler/codecache/stress/CodeCacheStressRunner.java @@ -28,6 +28,7 @@ public class CodeCacheStressRunner { private final Runnable action; + public CodeCacheStressRunner(Runnable action) { this.action = action; } @@ -35,10 +36,8 @@ public CodeCacheStressRunner(Runnable action) { protected final void runTest() { Helper.startInfiniteLoopThread(action); try { - // adjust timeout and substract vm init and exit time - long timeout = Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT); - timeout *= 0.8; - new TimeLimitedRunner(timeout, 2.0d, this::test).call(); + // Adjust timeout and substract vm init and exit time + new TimeLimitedRunner(60 * 1000, 2.0d, this::test).call(); } catch (Exception e) { throw new Error("Exception occurred during test execution", e); } diff --git a/test/hotspot/jtreg/compiler/codecache/stress/UnexpectedDeoptimizationTest.java b/test/hotspot/jtreg/compiler/codecache/stress/UnexpectedDeoptimizationTest.java index e4d2a83bf0b..45974011efe 100644 --- a/test/hotspot/jtreg/compiler/codecache/stress/UnexpectedDeoptimizationTest.java +++ b/test/hotspot/jtreg/compiler/codecache/stress/UnexpectedDeoptimizationTest.java @@ -60,6 +60,13 @@ public static void main(String[] args) { @Override public void run() { Helper.WHITE_BOX.deoptimizeFrames(rng.nextBoolean()); + // Sleep a short while to allow the stacks to grow - otherwise + // we end up running almost all code in the interpreter + try { + Thread.sleep(10); + } catch (Exception e) { + } + } } diff --git a/test/hotspot/jtreg/compiler/conversions/TestMoveConvI2LThroughAddIs.java b/test/hotspot/jtreg/compiler/conversions/TestMoveConvI2LThroughAddIs.java new file mode 100644 index 00000000000..f93677b3754 --- /dev/null +++ b/test/hotspot/jtreg/compiler/conversions/TestMoveConvI2LThroughAddIs.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.conversions; + +import java.util.Random; +import jdk.test.lib.Asserts; + +/* + * @test + * @bug 8254317 + * @requires vm.compiler2.enabled + * @summary Exercises the optimization that moves integer-to-long conversions + * upwards through different shapes of integer addition + * subgraphs. Contains three small functional tests and two stress + * tests that resulted in a compilation time and memory explosion + * before fixing bug 8254317. The stress tests run with -Xbatch to wait + * for C2, so that a timeout or an out-of-memory error is triggered if + * there was an explosion. These tests use a timeout of 30s to catch + * the explosion earlier. + * @library /test/lib / + * @run main/othervm + * compiler.conversions.TestMoveConvI2LThroughAddIs functional + * @run main/othervm/timeout=30 -Xbatch + * compiler.conversions.TestMoveConvI2LThroughAddIs stress1 + * @run main/othervm/timeout=30 -Xbatch + * compiler.conversions.TestMoveConvI2LThroughAddIs stress2 + */ + +public class TestMoveConvI2LThroughAddIs { + + // Number of repetitions of each test. Should be sufficiently large for the + // method under test to be compiled with C2. + static final int N = 100_000; + + // Chain-shaped functional test. + static long testChain(boolean cnd) { + int a = cnd ? 1 : 2; + int b = a + a; + int c = b + b; + int d = c + c; + return d; + } + + // Tree-shaped functional test. + static long testTree(boolean cnd) { + int a0 = cnd ? 1 : 2; + int a1 = cnd ? 1 : 2; + int a2 = cnd ? 1 : 2; + int a3 = cnd ? 1 : 2; + int a4 = cnd ? 1 : 2; + int a5 = cnd ? 1 : 2; + int a6 = cnd ? 1 : 2; + int a7 = cnd ? 1 : 2; + int b0 = a0 + a1; + int b1 = a2 + a3; + int b2 = a4 + a5; + int b3 = a6 + a7; + int c0 = b0 + b1; + int c1 = b2 + b3; + int d = c0 + c1; + return d; + } + + // DAG-shaped functional test. + static long testDAG(boolean cnd) { + int a0 = cnd ? 1 : 2; + int a1 = cnd ? 1 : 2; + int a2 = cnd ? 1 : 2; + int a3 = cnd ? 1 : 2; + int b0 = a0 + a1; + int b1 = a1 + a2; + int b2 = a2 + a3; + int c0 = b0 + b1; + int c1 = b1 + b2; + int d = c0 + c1; + return d; + } + + // Chain-shaped stress test. Before fixing bug 8254317, this test would + // result in an out-of-memory error after minutes running. + static long testStress1(boolean cnd) { + // C2 infers a finite, small value range for a. Note that there are + // different ways to achieve this, for example a might take the value of + // the induction variable in an outer counted loop. + int a = cnd ? 1 : 2; + // C2 fully unrolls this loop, creating a long chain of AddIs. + for (int i = 0; i < 28; i++) { + a = a + a; + } + // C2 places a ConvI2L at the end of the AddI chain. + return a; + } + + // DAG-shaped stress test. Before fixing bug 8254317, this test would result + // in an out-of-memory error after minutes running. + static long testStress2(boolean cnd) { + int a = cnd ? 1 : 2; + int b = a; + int c = a + a; + for (int i = 0; i < 20; i++) { + b = b + c; + c = b + c; + } + int d = b + c; + return d; + } + + public static void main(String[] args) { + // We use a random number generator to avoid constant propagation in C2 + // and produce a variable ("a" in the different tests) with a finite, + // small value range. + Random rnd = new Random(); + switch(args[0]) { + case "functional": + // Small, functional tests. + for (int i = 0; i < N; i++) { + boolean cnd = rnd.nextBoolean(); + Asserts.assertEQ(testChain(cnd), cnd ? 8L : 16L); + Asserts.assertEQ(testTree(cnd), cnd ? 8L : 16L); + Asserts.assertEQ(testDAG(cnd), cnd ? 8L : 16L); + } + break; + case "stress1": + // Chain-shaped stress test. + for (int i = 0; i < N; i++) { + boolean cnd = rnd.nextBoolean(); + Asserts.assertEQ(testStress1(cnd), + cnd ? 268435456L : 536870912L); + } + break; + case "stress2": + // DAG-shaped stress test. + for (int i = 0; i < N; i++) { + boolean cnd = rnd.nextBoolean(); + Asserts.assertEQ(testStress2(cnd), + cnd ? 701408733L : 1402817466L); + } + break; + default: + System.out.println("invalid mode"); + } + } +} diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java index 0a13c97729e..a3a111eaa3a 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestArrays.java @@ -3090,4 +3090,272 @@ public void test134_verifier(boolean warmup) { MyValueEmpty empty = test134(MyValueEmpty.default); Asserts.assertEquals(empty, MyValueEmpty.default); } + + // Test accessing a locked (inline type) array + @Test() + public Object test135(Object[] array, Object val) { + array[0] = val; + return array[1]; + } + + @DontCompile + public void test135_verifier(boolean warmup) { + MyValue1[] array1 = new MyValue1[2]; + array1[1] = MyValue1.createWithFieldsInline(rI, rL); + synchronized (array1) { + Object res = test135(array1, array1[1]); + Asserts.assertEquals(((MyValue1)res).hash(), array1[1].hash()); + Asserts.assertEquals(array1[0].hash(), array1[1].hash()); + } + Integer[] array2 = new Integer[2]; + array2[1] = rI; + synchronized (array2) { + Object res = test135(array2, array2[1]); + Asserts.assertEquals(res, array2[1]); + Asserts.assertEquals(array2[0], array2[1]); + } + } + + // Same as test135 but with locking in compiled method + @Test() + public Object test136(Object[] array, Object val) { + Object res = null; + synchronized (array) { + array[0] = val; + res = array[1]; + } + return res; + } + + @DontCompile + public void test136_verifier(boolean warmup) { + MyValue1[] array1 = new MyValue1[2]; + array1[1] = MyValue1.createWithFieldsInline(rI, rL); + Object res = test136(array1, array1[1]); + Asserts.assertEquals(((MyValue1)res).hash(), array1[1].hash()); + Asserts.assertEquals(array1[0].hash(), array1[1].hash()); + Integer[] array2 = new Integer[2]; + array2[1] = rI; + res = test136(array2, array2[1]); + Asserts.assertEquals(res, array2[1]); + Asserts.assertEquals(array2[0], array2[1]); + } + + Object oFld1, oFld2; + + // Test loop unwswitching with locked (inline type) array accesses + @Test() + public void test137(Object[] array1, Object[] array2) { + for (int i = 0; i < array1.length; i++) { + oFld1 = array1[i]; + oFld2 = array2[i]; + } + } + + @DontCompile + public void test137_verifier(boolean warmup) { + MyValue1[] array1 = new MyValue1[100]; + Arrays.fill(array1, MyValue1.createWithFieldsInline(rI, rL)); + Integer[] array2 = new Integer[100]; + Arrays.fill(array2, rI); + synchronized (array1) { + test137(array1, array1); + Asserts.assertEquals(oFld1, array1[0]); + Asserts.assertEquals(oFld2, array1[0]); + test137(array1, array2); + Asserts.assertEquals(oFld1, array1[0]); + Asserts.assertEquals(oFld2, array2[0]); + test137(array2, array1); + Asserts.assertEquals(oFld1, array2[0]); + Asserts.assertEquals(oFld2, array1[0]); + } + synchronized (array2) { + test137(array2, array2); + Asserts.assertEquals(oFld1, array2[0]); + Asserts.assertEquals(oFld2, array2[0]); + test137(array1, array2); + Asserts.assertEquals(oFld1, array1[0]); + Asserts.assertEquals(oFld2, array2[0]); + test137(array2, array1); + Asserts.assertEquals(oFld1, array2[0]); + Asserts.assertEquals(oFld2, array1[0]); + } + } + + // Same as test137 but with locking in loop + @Test() + public void test138(Object[] array1, Object[] array2) { + for (int i = 0; i < array1.length; i++) { + synchronized (array1) { + oFld1 = array1[i]; + } + synchronized (array2) { + oFld2 = array2[i]; + } + } + } + + @DontCompile + public void test138_verifier(boolean warmup) { + MyValue1[] array1 = new MyValue1[100]; + Arrays.fill(array1, MyValue1.createWithFieldsInline(rI, rL)); + Integer[] array2 = new Integer[100]; + Arrays.fill(array2, rI); + test138(array1, array1); + Asserts.assertEquals(oFld1, array1[0]); + Asserts.assertEquals(oFld2, array1[0]); + test138(array1, array2); + Asserts.assertEquals(oFld1, array1[0]); + Asserts.assertEquals(oFld2, array2[0]); + test138(array2, array1); + Asserts.assertEquals(oFld1, array2[0]); + Asserts.assertEquals(oFld2, array1[0]); + test138(array2, array2); + Asserts.assertEquals(oFld1, array2[0]); + Asserts.assertEquals(oFld2, array2[0]); + Asserts.assertEquals(oFld2, array2[0]); + } + + // Test load from array that is only known to be non-inline after parsing + @Test(failOn = ALLOC + ALLOCA + ALLOC_G + ALLOCA_G + LOOP + LOAD + STORE + TRAP + LOAD_UNKNOWN_INLINE + STORE_UNKNOWN_INLINE + INLINE_ARRAY_NULL_GUARD) + public Object test139() { + Object[] array = null; + Object[] iarray = new Integer[1]; + Object[] varray = new MyValue1[1]; + for (int i = 0; i < 10; i++) { + array = varray; + varray = iarray; + } + return array[0]; + } + + @DontCompile + public void test139_verifier(boolean warmup) { + Object res = test139(); + Asserts.assertEquals(res, null); + } + + // Test store to array that is only known to be non-inline after parsing + @Test(failOn = ALLOC + ALLOCA + ALLOC_G + LOOP + LOAD + STORE + TRAP + LOAD_UNKNOWN_INLINE + STORE_UNKNOWN_INLINE + INLINE_ARRAY_NULL_GUARD) + public Object[] test140(Object val) { + Object[] array = null; + Object[] iarray = new Integer[1]; + Object[] varray = new MyValue1[1]; + for (int i = 0; i < 10; i++) { + array = varray; + varray = iarray; + } + array[0] = val; + return array; + } + + @DontCompile + public void test140_verifier(boolean warmup) { + Object[] res = test140(rI); + Asserts.assertEquals(res[0], rI); + res = test140(null); + Asserts.assertEquals(res[0], null); + } + + // Test load from array that is only known to be inline after parsing + // TODO 8255938 + // @Test(failOn = ALLOC + ALLOCA + ALLOC_G + ALLOCA_G + LOOP + LOAD + STORE + TRAP + LOAD_UNKNOWN_INLINE + STORE_UNKNOWN_INLINE + INLINE_ARRAY_NULL_GUARD) + @Test + public Object test141() { + Object[] array = null; + Object[] iarray = new Integer[1]; + Object[] varray = new MyValue1[1]; + for (int i = 0; i < 10; i++) { + array = iarray; + iarray = varray; + } + return array[0]; + } + + @DontCompile + public void test141_verifier(boolean warmup) { + Object res = test141(); + Asserts.assertEquals(res, MyValue1.default); + } + + // Test store to array that is only known to be inline after parsing + // TODO 8255938 + // @Test(failOn = ALLOC + ALLOCA + ALLOC_G + LOOP + LOAD + STORE + TRAP + LOAD_UNKNOWN_INLINE + STORE_UNKNOWN_INLINE + INLINE_ARRAY_NULL_GUARD) + @Test + public Object[] test142(Object val) { + Object[] array = null; + Object[] iarray = new Integer[1]; + Object[] varray = new MyValue1[1]; + for (int i = 0; i < 10; i++) { + array = iarray; + iarray = varray; + } + array[0] = val; + return array; + } + + @DontCompile + public void test142_verifier(boolean warmup) { + Object[] res = test142(MyValue1.default); + Asserts.assertEquals(res[0], MyValue1.default); + if (!warmup) { + try { + test142(null); + throw new RuntimeException("Should throw NullPointerException"); + } catch (NullPointerException e) { + // Expected + } + } + } + + static interface MyInterface143 { + public int hash(); + } + + static class MyObject143 implements MyInterface143 { + public int hash() { return 42; } + } + + volatile MyInterface143[] array143 = new MyObject143[1]; + int len143 = 0; + + volatile int vf = 0; + + // Test that triggers an anti dependency failure when array mark word is loaded from immutable memory + @Test + @Warmup(0) + public void test143() { + MyInterface143[] arr = array143; + int tmp = arr.length; + for (int i = 0; i < len143; i++) { + if (arr[i].hash() > 0) { + return; + } + } + } + + @DontCompile + public void test143_verifier(boolean warmup) { + test143(); + } + + // Same as test143 but with two flat array checks that are unswitched + @Test + @Warmup(0) + public void test144() { + MyInterface143[] arr1 = array143; + MyInterface143[] arr2 = array143; + int tmp1 = arr1.length; + int tmp2 = arr2.length; + for (int i = 0; i < len143; i++) { + if (arr1[i].hash() > 0 && arr2[i].hash() > 0) { + return; + } + } + } + + @DontCompile + public void test144_verifier(boolean warmup) { + test144(); + } } diff --git a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java index 14b575c4618..38f975cb82f 100644 --- a/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java +++ b/test/hotspot/jtreg/compiler/valhalla/inlinetypes/TestIntrinsics.java @@ -1047,4 +1047,32 @@ public void test55_verifier(boolean warmup) { MyValue2 res = test55(); Asserts.assertEQ(res.hash(), test55_vt.v1.hash()); } + + // Test OptimizePtrCompare part of Escape Analysis + @Test() + public void test56(int idx) { + Object[] va = (Object[])Array.newInstance(MyValue1.val.class, 1); + if (va[idx] == null) { + throw new RuntimeException("Unexpected null"); + } + } + + @DontCompile + public void test56_verifier(boolean warmup) { + test56(0); + } + + // Same as test56 but with load from known array index + @Test() + public void test57() { + Object[] va = (Object[])Array.newInstance(MyValue1.val.class, 1); + if (va[0] == null) { + throw new RuntimeException("Unexpected null"); + } + } + + @DontCompile + public void test57_verifier(boolean warmup) { + test57(); + } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java b/test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java index ae26d96d456..f7671662f12 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java @@ -42,7 +42,8 @@ public static void main(String[] args) throws Exception { OutputAnalyzer out = TestCommon.dump(appJar, TestCommon.list("WrongBSM", - "@lambda-proxy WrongBSM 7")); + "@lambda-proxy WrongBSM 7"), + "-Xlog:cds+lambda=debug"); out.shouldHaveExitValue(0); out.shouldContain( "is_supported_invokedynamic check failed for cp_index 7"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/ClassListFormatBase.java b/test/hotspot/jtreg/runtime/cds/appcds/ClassListFormatBase.java index d7c848bb201..0fd55b4a4a0 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/ClassListFormatBase.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/ClassListFormatBase.java @@ -41,7 +41,7 @@ static void dumpShouldFail(String caseHelp, String appJar, String[] appClasses, System.out.println("------------------------------"); try { - OutputAnalyzer output = TestCommon.dump(appJar, appClasses); + OutputAnalyzer output = TestCommon.dump(appJar, appClasses, "-Xlog:cds+lambda=debug"); output.shouldHaveExitValue(1); for (String s : expected_errors) { output.shouldContain(s); @@ -63,7 +63,7 @@ static void dumpShouldPass(String caseHelp, String appJar, String[] appClasses, System.out.println("------------------------------"); try { - OutputAnalyzer output = TestCommon.dump(appJar, appClasses, "-Xlog:cds"); + OutputAnalyzer output = TestCommon.dump(appJar, appClasses, "-Xlog:cds", "-Xlog:cds+lambda=debug"); output.shouldHaveExitValue(0); output.shouldContain("Dumping"); for (String s : expected_msgs) { diff --git a/test/hotspot/jtreg/runtime/logging/SafepointCleanupTest.java b/test/hotspot/jtreg/runtime/logging/SafepointCleanupTest.java index 5ceaf0160e8..5c445dc4f1c 100644 --- a/test/hotspot/jtreg/runtime/logging/SafepointCleanupTest.java +++ b/test/hotspot/jtreg/runtime/logging/SafepointCleanupTest.java @@ -39,7 +39,6 @@ static void analyzeOutputOn(ProcessBuilder pb) throws Exception { OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain("[safepoint,cleanup]"); output.shouldContain("safepoint cleanup tasks"); - output.shouldContain("deflating idle monitors"); output.shouldContain("updating inline caches"); output.shouldContain("compilation policy safepoint handler"); output.shouldHaveExitValue(0); diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbFlags.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbFlags.java index 0fe44a9980f..1d36795bfdf 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbFlags.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbFlags.java @@ -65,7 +65,6 @@ public static void runBasicTest() throws Exception { "UnlockDiagnosticVMOptions = true", "MaxFDLimit = false", "MaxJavaStackTraceDepth = 1024", - "VerifyMergedCPBytecodes", "ConcGCThreads", "UseThreadPriorities", "ShowHiddenFrames")); expStrMap.put("flags -nd", List.of( diff --git a/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.java b/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.java index 2ebe4647113..eae15ea35e2 100644 --- a/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.java +++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbPrintStatics.java @@ -59,7 +59,6 @@ public static void main(String[] args) throws Exception { "Abstract_VM_Version::_vm_major_version", "ClassLoaderDataGraph::_head", "JNIHandles::_weak_global_handles", "PerfMemory::_top", - "ObjectSynchronizer::g_block_list", "java_lang_Class::_oop_size_offset")); expStrMap.put("printstatics SystemDictionary", List.of( "Static fields of SystemDictionary", diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/Helper.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/Helper.java index 33d0b89b0ec..72b00cf9b40 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/Helper.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/Helper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,17 +22,28 @@ */ package nsk.jvmti.ResourceExhausted; +import jtreg.SkippedException; + public class Helper { - static native boolean gotExhaustedEvent(); + static native int getExhaustedEventFlags(); static native void resetExhaustedEvent(); - static boolean checkResult(String eventName) { - if ( ! gotExhaustedEvent() ) { + static final int JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR = 1; + static final int JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP = 2; + static final int JVMTI_RESOURCE_EXHAUSTED_THREADS = 4; + + static boolean checkResult(int expectedFlag, String eventName) { + int got = getExhaustedEventFlags(); + if (got == 0) { System.err.println("Failure: Expected ResourceExhausted event after " + eventName + " did not occur"); return false; } + if ((got & expectedFlag) == 0) { + System.err.println("Warning: did not get expected flag bit (expected: "+ expectedFlag + ", got: " + got + ")"); + throw new SkippedException("Test did not get expected flag value"); + } System.out.println("Got expected ResourceExhausted event"); return true; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted.cpp index c6e795837e6..b3c6304ee0c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ extern "C" { static jvmtiEnv* gJvmti = NULL; -static volatile jboolean gGotEvent = JNI_FALSE; +static volatile jint gEventFlags = 0; void JNICALL resourceExhausted(jvmtiEnv *jvmti_env, @@ -46,19 +46,19 @@ resourceExhausted(jvmtiEnv *jvmti_env, if (flags & JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR) NSK_DISPLAY0("Agent: JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR\n"); if (flags & JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP) NSK_DISPLAY0("Agent: JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP\n"); if (flags & JVMTI_RESOURCE_EXHAUSTED_THREADS) NSK_DISPLAY0("Agent: JVMTI_RESOURCE_EXHAUSTED_THREADS\n"); - gGotEvent = JNI_TRUE; + gEventFlags = flags; } -JNIEXPORT jboolean JNICALL -Java_nsk_jvmti_ResourceExhausted_Helper_gotExhaustedEvent(JNIEnv* env, jclass cls) +JNIEXPORT jint JNICALL +Java_nsk_jvmti_ResourceExhausted_Helper_getExhaustedEventFlags(JNIEnv* env, jclass cls) { - return gGotEvent; + return gEventFlags; } JNIEXPORT void JNICALL Java_nsk_jvmti_ResourceExhausted_Helper_resetExhaustedEvent(JNIEnv* env, jclass cls) { - gGotEvent = JNI_FALSE; + gEventFlags = 0; } #ifdef STATIC_BUILD diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted001.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted001.java index ac497dfcb0e..b147757f9e0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted001.java @@ -25,6 +25,7 @@ import java.io.PrintStream; import java.util.concurrent.atomic.AtomicInteger; +import jdk.test.lib.Platform; import nsk.share.Consts; import nsk.share.test.Stresser; import jtreg.SkippedException; @@ -42,6 +43,11 @@ public class resexhausted001 { public static int run(String args[], PrintStream out) { + // Check platform here (instead of @requires) as this test is also called from resexhausted004 + if (Platform.isWindows()) { + throw new SkippedException("Cannot get JVMTI_RESOURCE_EXHAUSTED_THREADS on Windows"); + } + Stresser stress = new Stresser(args); int count = 0; @@ -56,14 +62,15 @@ public static int run(String args[], PrintStream out) { makeThread(); } - System.out.println("Can't reproduce OOME due to a limit on iterations/execution time. Test was useless."); + System.out.println("Can't reproduce OOME due to a limit on iterations/execution time. Test was useless." + + " threadCount=" + threadCount.get()); throw new SkippedException("Test did not get an OutOfMemory error"); } catch (OutOfMemoryError e) { count = threadCount.get(); } finally { - threadsDone = true; synchronized (hanger) { + threadsDone = true; hanger.notifyAll(); } stress.finish(); @@ -74,7 +81,8 @@ public static int run(String args[], PrintStream out) { } System.gc(); - if (!Helper.checkResult("creating " + count + " threads")) { + System.out.println("got OOME with threadCount=" + count); + if (!Helper.checkResult(Helper.JVMTI_RESOURCE_EXHAUSTED_THREADS, "creating " + count + " threads")) { return Consts.TEST_FAILED; } @@ -85,16 +93,17 @@ static Thread makeThread() { final Thread thr = new Thread(new Runnable() { public void run() { threadCount.getAndIncrement(); - while (!threadsDone) { - try { - synchronized (hanger) { + synchronized (hanger) { + while (!threadsDone) { + try { hanger.wait(); - } - } catch (InterruptedException ignored) {} + } catch (InterruptedException ignored) {} + } } threadCount.getAndDecrement(); } }, "fleece"); + thr.setDaemon(true); thr.start(); return thr; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted001/TestDescription.java index 57f29ae5173..c86d34c9b2c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted001/TestDescription.java @@ -40,6 +40,8 @@ * @run main/othervm/native/timeout=240 * -agentlib:resexhausted=-waittime=5 * -XX:-UseGCOverheadLimit + * -Xms16m + * -Xmx16m * nsk.jvmti.ResourceExhausted.resexhausted001 * -stressTime 220 */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted002.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted002.java index 6871640833d..46832df7dc3 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted002.java @@ -64,8 +64,9 @@ public static int run(String args[], PrintStream out) { } System.gc(); - if ( ! Helper.checkResult("creating " + count + " objects") ) + if (!Helper.checkResult(Helper.JVMTI_RESOURCE_EXHAUSTED_JAVA_HEAP, "creating " + count + " objects")) { return Consts.TEST_FAILED; + } return Consts.TEST_PASSED; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003.java index 9b5e28e6c8e..f336c1bf3d5 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/ResourceExhausted/resexhausted003.java @@ -125,8 +125,10 @@ public static int run(String args[], PrintStream out) { } System.gc(); - if ( ! Helper.checkResult("loading " + count + " classes of " + bloatBytes.length + " bytes") ) + if (!Helper.checkResult(Helper.JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR, + "loading " + count + " classes of " + bloatBytes.length + " bytes")) { return Consts.TEST_FAILED; + } return Consts.TEST_PASSED; } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index fc16e0f81d0..3cc33d44c61 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -254,13 +254,13 @@ java/awt/image/DrawImage/IncorrectAlphaSurface2SW.java 8056077 generic-all java/awt/image/DrawImage/IncorrectClipXorModeSW2Surface.java 8196025 windows-all java/awt/image/DrawImage/IncorrectClipXorModeSurface2Surface.java 8196025 windows-all java/awt/image/DrawImage/IncorrectSourceOffset.java 8196086 windows-all +java/awt/image/DrawImage/BlitRotateClippedArea.java 8255724 linux-all java/awt/image/MultiResolutionImage/MultiResolutionDrawImageWithTransformTest.java 8198390 generic-all java/awt/image/multiresolution/MultiresolutionIconTest.java 8169187 macosx-all,windows-all java/awt/print/Headless/HeadlessPrinterJob.java 8196088 windows-all java/awt/print/PrinterJob/TestPgfmtSetMPA.java 8198343 generic-all sun/awt/datatransfer/SuplementaryCharactersTransferTest.java 8011371 generic-all sun/awt/shell/ShellFolderMemoryLeak.java 8197794 windows-all -sun/awt/shell/FileSystemViewMemoryLeak.java 8241806 windows-all sun/java2d/DirectX/OnScreenRenderingResizeTest/OnScreenRenderingResizeTest.java 8022403 generic-all sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java 8196102 generic-all sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java 8196180 windows-all,macosx-all @@ -730,7 +730,6 @@ javax/sound/midi/Sequencer/MetaCallback.java 8178698 linux-all javax/swing/plaf/basic/BasicTextUI/8001470/bug8001470.java 8233177 linux-all,windows-all javax/swing/border/TestTitledBorderLeak.java 8213531 linux-all -javax/swing/JComponent/7154030/bug7154030.java 7190978 generic-all javax/swing/JComponent/6683775/bug6683775.java 8172337 generic-all javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedTranslucentPerPixelTranslucentGradient.java 8233582 linux-all javax/swing/JWindow/ShapedAndTranslucentWindows/ShapedPerPixelTranslucentGradient.java 8233582 linux-all diff --git a/test/jdk/com/sun/net/httpserver/HttpPrincipalTest.java b/test/jdk/com/sun/net/httpserver/HttpPrincipalTest.java index 954232441bf..30cf0c4490c 100644 --- a/test/jdk/com/sun/net/httpserver/HttpPrincipalTest.java +++ b/test/jdk/com/sun/net/httpserver/HttpPrincipalTest.java @@ -36,9 +36,13 @@ public class HttpPrincipalTest { @Test - public void TestGetters() { + public void testGetters() { var principal = new HttpPrincipal("test", "123"); + assertEquals(principal.getUsername(), "test"); assertEquals(principal.getRealm(), "123"); + assertEquals(principal.getName(), "123:test"); + assertEquals(principal.toString(), principal.getName()); + assertEquals(("test"+"123").hashCode(), principal.hashCode()); } } diff --git a/test/jdk/java/awt/Component/SetComponentsBounds/SetComponentsBounds.java b/test/jdk/java/awt/Component/SetComponentsBounds/SetComponentsBounds.java new file mode 100644 index 00000000000..2967bc17f27 --- /dev/null +++ b/test/jdk/java/awt/Component/SetComponentsBounds/SetComponentsBounds.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Label; +import java.awt.List; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; + +/** + * @test + * @key headful + * @bug 8211999 + * @run main/othervm SetComponentsBounds + * @run main/othervm -Dsun.java2d.uiScale=1 SetComponentsBounds + * @run main/othervm -Dsun.java2d.uiScale=2.25 SetComponentsBounds + */ +public final class SetComponentsBounds { + + private static final int X = 111; + private static final int Y = 222; + private static final int WIDTH = 321; + private static final int HEIGHT = 123; + + public static void main(String[] args) throws Exception { + var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + for (GraphicsDevice gd : ge.getScreenDevices()) { + test(gd.getDefaultConfiguration(), true); + test(gd.getDefaultConfiguration(), false); + } + } + + private static void test(GraphicsConfiguration gc, boolean visible) throws Exception { + Rectangle screen = gc.getBounds(); + Window frame = new Frame(); + try { + frame.setLayout(null); // trigger use the minimum size of + // the peer + frame.setBounds(screen.x + 100, screen.y + 100, 500, 500); + frame.add(new Button()); + frame.add(new Canvas()); + frame.add(new Checkbox()); + frame.add(new Choice()); + frame.add(new Label()); + frame.add(new List()); + frame.add(new Scrollbar()); + frame.add(new ScrollPane()); + frame.add(new TextArea()); + frame.add(new TextField()); + for (Component comp : frame.getComponents()) { + comp.setBounds(X, Y, WIDTH, HEIGHT); + } + if (visible) { + frame.setVisible(true); + } else { + frame.pack(); + } + Robot robot = new Robot(); + robot.waitForIdle(); + checkGC(gc, frame); + for (Component comp : frame.getComponents()) { + Rectangle bounds = comp.getBounds(); + if (bounds.x != X || bounds.y != Y || bounds.width != WIDTH) { + System.err.println("Screen bounds:" + screen); + System.err.println("Component:" + comp); + throw new RuntimeException("Wrong bounds:" + bounds); + } + if (bounds.height > HEIGHT) { + // different check for HEIGHT, it depends on the font + throw new RuntimeException("Wrong height:" + bounds.height); + } + checkGC(gc, comp); + } + } finally { + frame.dispose(); + } + } + + private static void checkGC(GraphicsConfiguration gc, Component comp) { + GraphicsConfiguration compGC = comp.getGraphicsConfiguration(); + if (compGC != gc) { + System.err.println("Expected GC:" + gc); + System.err.println("Actual GC:" + compGC); + throw new RuntimeException(); + } + } +} diff --git a/test/jdk/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java b/test/jdk/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java index e7fb0b8c6a0..e186e7ac132 100644 --- a/test/jdk/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java +++ b/test/jdk/java/awt/EmbeddedFrame/EmbeddedFrameGrabTest/EmbeddedFrameGrabTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,7 @@ /** * @test * @key headful - * @bug 6345003 8171363 + * @bug 6345003 8171363 8211999 * @summary grab problems with EmbeddedFrame * @requires (os.family == "windows") * @modules java.desktop/java.awt.peer @@ -67,6 +67,7 @@ private void init() throws Exception { final Frame frame = new Frame("AWT Frame"); frame.pack(); frame.setSize(200, 200); + frame.setLocationRelativeTo(null); FramePeer frame_peer = AWTAccessor.getComponentAccessor() .getPeer(frame); Class comp_peer_class @@ -88,6 +89,7 @@ private void init() throws Exception { final Panel p = new Panel(); p.setLayout(new BorderLayout()); embedded_frame.add(p, BorderLayout.CENTER); + embedded_frame.setBounds(0, 0, 150, 150); embedded_frame.validate(); p.add(combo); p.validate(); diff --git a/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenSmall.java b/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenSmall.java index eac72fd0fbb..bd749cc94a9 100644 --- a/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenSmall.java +++ b/test/jdk/java/awt/Frame/MaximizedToOppositeScreen/MaximizedToOppositeScreenSmall.java @@ -21,6 +21,7 @@ * questions. */ +import java.awt.Dimension; import java.awt.Frame; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; @@ -30,7 +31,7 @@ /** * @test - * @bug 8176359 8231564 + * @bug 8176359 8231564 8211999 * @key headful * @requires (os.family == "windows" | os.family == "mac") * @summary setMaximizedBounds() should work if set to the screen other than @@ -58,15 +59,23 @@ public static void main(String[] args) throws Exception { Rectangle framAt = gd1.getDefaultConfiguration().getBounds(); framAt.grow(-framAt.width / 2 + 100, -framAt.height / 2 + 100); for (GraphicsDevice gd2 : gds) { - Rectangle maxTo = gd2.getDefaultConfiguration().getBounds(); - maxTo.grow(-maxTo.width / 2 + 120, -maxTo.height / 2 + 120); Frame frame = new Frame(gd1.getDefaultConfiguration()); try { + frame.setLayout(null); // trigger use the minimum size of + // the peer frame.setBounds(framAt); + frame.setVisible(true); robot.waitForIdle(); robot.delay(1000); + Dimension minimumSize = frame.getMinimumSize(); + minimumSize.width = Math.max(minimumSize.width, 120); + minimumSize.height = Math.max(minimumSize.height, 120); + Rectangle maxTo = gd2.getDefaultConfiguration().getBounds(); + maxTo.grow(-maxTo.width / 2 + minimumSize.width, + -maxTo.height / 2 + minimumSize.height); + frame.setMaximizedBounds(maxTo); frame.setExtendedState(Frame.MAXIMIZED_BOTH); robot.waitForIdle(); diff --git a/test/jdk/java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java b/test/jdk/java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java new file mode 100644 index 00000000000..d444ee5f0f1 --- /dev/null +++ b/test/jdk/java/awt/FullScreen/FullscreenWindowProps/FullscreenWindowProps.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.DisplayMode; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Rectangle; + +/** + * @test + * @bug 8211999 + * @key headful + * @summary verifies the full-screen window bounds and graphics configuration + */ +public final class FullscreenWindowProps { + + public static void main(String[] args) throws Exception { + var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + + if (!gd.isFullScreenSupported()) { + return; + } + + Frame frame = new Frame() { + @Override + public void paint(Graphics g) { + super.paint(g); + g.setColor(Color.GREEN); + g.fillRect(0, 0, getWidth(), getHeight()); + } + }; + try { + frame.setBackground(Color.MAGENTA); + frame.setVisible(true); + gd.setFullScreenWindow(frame); + Thread.sleep(4000); + + for (DisplayMode dm : gd.getDisplayModes()) { + if (dm.getWidth() == 1024 && dm.getHeight() == 768) { + gd.setDisplayMode(dm); + Thread.sleep(4000); + break; + } + } + + GraphicsConfiguration frameGC = frame.getGraphicsConfiguration(); + Rectangle frameBounds = frame.getBounds(); + + GraphicsConfiguration screenGC = gd.getDefaultConfiguration(); + Rectangle screenBounds = screenGC.getBounds(); + + if (frameGC != screenGC) { + System.err.println("Expected: " + screenGC); + System.err.println("Actual: " + frameGC); + throw new RuntimeException(); + } + + checkSize(frameBounds.x, screenBounds.x, "x"); + checkSize(frameBounds.y, screenBounds.y, "Y"); + checkSize(frameBounds.width, screenBounds.width, "width"); + checkSize(frameBounds.height, screenBounds.height, "height"); + } finally { + gd.setFullScreenWindow(null); + frame.dispose(); + Thread.sleep(10000); + } + } + + private static void checkSize(int actual, int expected, String prop) { + if (Math.abs(actual - expected) > 30) { // let's allow size variation, + // the bug is reproduced anyway + System.err.println("Expected: " + expected); + System.err.println("Actual: " + actual); + throw new RuntimeException(prop + " is wrong"); + } + } +} \ No newline at end of file diff --git a/test/jdk/java/awt/List/ListMultipleSelectTest/ListMultipleSelectTest.java b/test/jdk/java/awt/List/ListMultipleSelectTest/ListMultipleSelectTest.java new file mode 100644 index 00000000000..ef8ee7def0d --- /dev/null +++ b/test/jdk/java/awt/List/ListMultipleSelectTest/ListMultipleSelectTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; + +/** + * @test + * @bug 4909485 8211999 + * @key headful + */ +public final class ListMultipleSelectTest { + + private static List aList; + private static Panel panel; + private static Point p; + private static Robot robot; + private static int[] selected; + + public static void main(String[] args) throws Exception { + Frame frame = new Frame(); + try { + panel = new Panel(); + aList = new List(); + aList.add("Test item1"); + aList.add("Test item2"); + aList.add("Test item3"); + aList.add("Test item4"); + + frame.setLayout(new FlowLayout()); //list should fill whole frame's space + panel.add(aList); + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + panel.setVisible(true); + frame.add(panel); + frame.setVisible(true); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + throw new RuntimeException(" InterruptedException. Test failed. "); + } + + Dimension listSize = aList.getSize(); + p = aList.getLocationOnScreen(); + int stepY = listSize.height / aList.getItemCount(); + +// System.out.println("itemCount = "+aList.getItemCount()); +// System.out.println("Size Of aList="+ listSize); +// System.out.println("stepY = "+stepY); +// System.out.println("Point:" +p); + System.out.println("Multiple mode is ON"); + aList.setMultipleMode(true); +//================================================= + robot = new Robot(); + robot.setAutoDelay(0); + robot.setAutoWaitForIdle(false); + robot.delay(10); + robot.waitForIdle(); + +//================================================= + + for (int i = 0; i < aList.getItemCount(); i++) { + //select all items in the List + mousePress(p.x + listSize.width / 2, p.y + stepY / 2 + stepY * i); + } + + selected = aList.getSelectedIndexes(); + System.out.println("Multiple mode is ON"); + aList.setMultipleMode(true); + int[] newSelected = aList.getSelectedIndexes(); + if (!java.util.Arrays.equals(newSelected, selected)) { + throw new RuntimeException(" Incorrect item remains selected " + + "after setMultipleMode(true). "); + } + + aList.setMultipleMode(false); + System.out.println("Multiple mode is OFF"); + selected = aList.getSelectedIndexes(); + if (selected[0] != 3 || selected.length != 1) { + throw new RuntimeException(" Incorrect item remains selected " + + "after setMultipleMode(false) or it is more then one " + + "item remaining.Forward. "); + } + + System.out.println("Multiple mode is ON"); + aList.setMultipleMode(true); + + if (selected[0] != 3 || selected.length != 1) { + throw new RuntimeException(" Incorrect item remains selected " + + "after setMultipleMode(true) or it is more then one " + + "item remaining. "); + } + + deselectAll(); + for (int i = aList.getItemCount() - 1; i >= 0; i--) { + mousePress(p.x + listSize.width / 2, p.y + stepY / 2 + stepY * i); + } + + System.out.println("Multiple mode is OFF"); + aList.setMultipleMode(false); + + selected = aList.getSelectedIndexes(); + if (selected[0] != 0 || selected.length != 1) { + throw new RuntimeException(" Incorrect item remains selected " + + "after setMultipleMode(false) or it is more then one " + + "item remaining.Backward. "); + } + System.out.println("Test succeeded."); + } finally { + frame.dispose(); + } + } + + private static void mousePress(int x, int y) { + robot.mouseMove(x, y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.delay(1000); + } + + private static void deselectAll() { + for (int i = 0; i < selected.length; i++) { + aList.deselect(selected[i]); + } + } +} diff --git a/test/jdk/java/awt/Multiscreen/MouseEventTest/MouseEventTest.java b/test/jdk/java/awt/Multiscreen/MouseEventTest/MouseEventTest.java index 45d9aa5c80b..c6494dc314b 100644 --- a/test/jdk/java/awt/Multiscreen/MouseEventTest/MouseEventTest.java +++ b/test/jdk/java/awt/Multiscreen/MouseEventTest/MouseEventTest.java @@ -24,7 +24,7 @@ /* @test @key headful - @bug 8017472 + @bug 8017472 8211999 @summary MouseEvent has wrong coordinates when using multiple monitors @run main MouseEventTest */ diff --git a/test/jdk/java/awt/Paint/RepaintOnAWTShutdown.java b/test/jdk/java/awt/Paint/RepaintOnAWTShutdown.java new file mode 100644 index 00000000000..6c94ee29a7f --- /dev/null +++ b/test/jdk/java/awt/Paint/RepaintOnAWTShutdown.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Graphics; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import javax.swing.JFrame; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.JTree; +import javax.swing.SwingUtilities; + +/** + * @test + * @bug 6847157 + * @key headful + * @summary the java2D/AWT should die silently without exceptions + * @run main/othervm RepaintOnAWTShutdown + * @run main/othervm -Dsun.java2d.uiScale=1 RepaintOnAWTShutdown + * @run main/othervm -Dsun.java2d.uiScale=1.2 RepaintOnAWTShutdown + * @run main/othervm -Dsun.java2d.uiScale=1.25 RepaintOnAWTShutdown + * @run main/othervm -Dsun.java2d.uiScale=1.5 RepaintOnAWTShutdown + * @run main/othervm -Dsun.java2d.uiScale=1.75 RepaintOnAWTShutdown + * @run main/othervm -Dsun.java2d.uiScale=2 RepaintOnAWTShutdown + * @run main/othervm -Dsun.java2d.uiScale=2.25 RepaintOnAWTShutdown + * @run main/othervm -Dsun.java2d.uiScale=5 RepaintOnAWTShutdown + * @run main/othervm -Dsun.java2d.uiScale=10 RepaintOnAWTShutdown + */ +public final class RepaintOnAWTShutdown implements Runnable { + + private static final CountDownLatch go = new CountDownLatch(1); + + public static void main(String[] args) throws Exception { + SwingUtilities.invokeLater(new RepaintOnAWTShutdown()); + go.await(5, TimeUnit.SECONDS); + // The test will check that no exception is thrown when the jtreg will + // kill this test at the moment the frame will be painted + } + + public void run() { + JFrame frame = new JFrame(); + JPanel panel = new MyPanel(); + panel.setPreferredSize(new Dimension(100, 100)); + panel.setLayout(new FlowLayout()); + panel.add(new JTree()); + panel.add(new JList(new String[]{"one", "two"})); + panel.add(new JTable(new String[][]{{"one", "two"}}, + new String[]{"one", "two"})); + frame.add(panel); + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + // the frame is not disposed intentionally + } + + + private final class MyPanel extends JPanel { + + public void paint(Graphics g) { + super.paint(g); + go.countDown(); + } + } +} diff --git a/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java index 061b8953200..57419b0ac5a 100644 --- a/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java +++ b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java @@ -24,6 +24,8 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; @@ -38,7 +40,7 @@ /** * @test * @key headful - * @bug 8215105 + * @bug 8215105 8211999 * @summary tests that Robot can capture the common colors without artifacts */ public final class CheckCommonColors { @@ -48,16 +50,20 @@ public final class CheckCommonColors { public static void main(final String[] args) throws Exception { robot = new Robot(); - try { - test(); - } finally { - frame.dispose(); + var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + for (GraphicsDevice gd : ge.getScreenDevices()) { + try { + test(gd.getDefaultConfiguration().getBounds()); + } finally { + frame.dispose(); + } } } - private static void test() { + private static void test(Rectangle screen) { frame.setSize(400, 400); - frame.setLocationRelativeTo(null); + frame.setLocation((int)screen.getCenterX() - 200, + (int)screen.getCenterY() - 200); frame.setUndecorated(true); for (final Color color : List.of(Color.WHITE, Color.LIGHT_GRAY, Color.GRAY, Color.DARK_GRAY, @@ -69,16 +75,25 @@ private static void test() { robot.waitForIdle(); frame.setBackground(color); frame.setVisible(true); - checkPixels(color); + checkPixels(color, true); + checkPixels(color, false); } } - private static void checkPixels(final Color color) { + private static void checkPixels(final Color color, boolean useRect) { + System.out.println("color = " + color + ", useRect = " + useRect); int attempt = 0; while (true) { Point p = frame.getLocationOnScreen(); p.translate(frame.getWidth() / 2, frame.getHeight() / 2); - Color pixel = robot.getPixelColor(p.x, p.y); + Color pixel; + Rectangle rect = new Rectangle(p.x, p.y, 1, 1); + if (useRect) { + BufferedImage bi = robot.createScreenCapture(rect); + pixel = new Color(bi.getRGB(0, 0)); + } else { + pixel = robot.getPixelColor(rect.x, rect.y); + } if (color.equals(pixel)) { return; } diff --git a/test/jdk/java/awt/Window/LocationAtScreenCorner/LocationAtScreenCorner.java b/test/jdk/java/awt/Window/LocationAtScreenCorner/LocationAtScreenCorner.java index 5fe2f9b2e5c..b6a18629022 100644 --- a/test/jdk/java/awt/Window/LocationAtScreenCorner/LocationAtScreenCorner.java +++ b/test/jdk/java/awt/Window/LocationAtScreenCorner/LocationAtScreenCorner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,7 @@ /** * @test * @key headful - * @bug 8201364 8232433 + * @bug 8201364 8232433 8211999 * @summary Component.getLocation() should returns correct location if * Component.setBounds() was ignored by the OS */ @@ -64,8 +64,11 @@ private static void test(final boolean undecorated) throws AWTException { Rectangle bounds = device.getDefaultConfiguration().getBounds(); test(robot, frame, bounds.x, bounds.y); test(robot, frame, bounds.width, bounds.y); + test(robot, frame, bounds.x + bounds.width, bounds.y); test(robot, frame, bounds.x, bounds.height); + test(robot, frame, bounds.x, bounds.y + bounds.height); test(robot, frame, bounds.width, bounds.height); + test(robot, frame, bounds.x + bounds.width, bounds.y + bounds.height); } frame.dispose(); } diff --git a/test/jdk/java/awt/Window/SlowMotion/SlowMotion.java b/test/jdk/java/awt/Window/SlowMotion/SlowMotion.java new file mode 100644 index 00000000000..ac6c51ad621 --- /dev/null +++ b/test/jdk/java/awt/Window/SlowMotion/SlowMotion.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.Window; + +/** + * @test + * @key headful + * @bug 8211999 + * @run main/timeout=300 SlowMotion + * @summary places the window on the screen outside of any insets, and waits to + * catch any strange window moving + */ +public final class SlowMotion { + + // some additional space, if getScreenInsets() does not work, say on Linux + private static final int SAFE = 100; + private static final int HEIGHT = 350; + private static final int WIDTH = 279; + private static Robot robot; + + public static void main(final String[] args) throws Exception { + robot = new Robot(); + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice[] sds = ge.getScreenDevices(); + + for (GraphicsDevice sd : sds) { + GraphicsConfiguration gc = sd.getDefaultConfiguration(); + Rectangle bounds = gc.getBounds(); + bounds.translate(SAFE, SAFE); + Point point = new Point(bounds.x, bounds.y); + Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(gc); + while (point.y < bounds.y + bounds.height - insets.bottom - HEIGHT - SAFE * 2) { + while (point.x < bounds.x + bounds.width - insets.right - WIDTH - SAFE * 2) { + test(point, new Frame()); + test(point, new Window(null)); + test(point, new Dialog((Dialog) null)); + point.translate(bounds.width / 6, 0); + } + point.setLocation(bounds.x, point.y + bounds.height / 5); + } + } + } + + private static void test(final Point loc, Window window) { + try { + window.setBounds(loc.x, loc.y, WIDTH, HEIGHT); + window.setVisible(true); + robot.delay(1000); // intentionally very slow, we try to catch + // very very last suspicion event + Rectangle bounds = window.getBounds(); + if (loc.x != bounds.x || loc.y != bounds.y + || bounds.width != WIDTH || bounds.height != HEIGHT) { + System.err.println("Component = " + window); + System.err.println("Actual bounds = " + bounds); + System.err.println("Expected location = " + loc); + System.err.println("Expected width = " + WIDTH); + System.err.println("Expected height = " + HEIGHT); + throw new RuntimeException(); + } + } finally { + window.dispose(); + } + } +} diff --git a/test/jdk/java/awt/Window/WindowSizeDifferentScreens/WindowSizeDifferentScreens.java b/test/jdk/java/awt/Window/WindowSizeDifferentScreens/WindowSizeDifferentScreens.java new file mode 100644 index 00000000000..4ac5aeeac1a --- /dev/null +++ b/test/jdk/java/awt/Window/WindowSizeDifferentScreens/WindowSizeDifferentScreens.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.Window; + +/** + * @test + * @key headful + * @bug 8211999 + * @summary The test creates the packed/unpacked top level components on the + * different screens and compares their bounds + * @run main/othervm WindowSizeDifferentScreens + * @run main/othervm -Dsun.java2d.uiScale=1 WindowSizeDifferentScreens + * @run main/othervm -Dsun.java2d.uiScale=1.25 WindowSizeDifferentScreens + */ +public final class WindowSizeDifferentScreens { + + public static void main(String[] args) throws Exception { + test("window"); + test("dialog"); + test("frame"); + } + + private static void test(String top) throws Exception { + var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + Robot robot = new Robot(); + Window main = getTopLevel(top); + try { + main.setVisible(true); + robot.waitForIdle(); + main.setSize(500, 500); + robot.waitForIdle(); + for (GraphicsDevice gd : ge.getScreenDevices()) { + Rectangle bounds = gd.getDefaultConfiguration().getBounds(); + Point point = bounds.getLocation(); + point.translate(100, 100); + main.setLocation(point); + main.setBackground(Color.RED); + robot.waitForIdle(); + + Window packed = getTopLevel(top); + Window unpacked = getTopLevel(top); + try { + packed.pack(); + robot.waitForIdle(); + packed.setBackground(Color.GREEN); + unpacked.setBackground(Color.BLUE); + packed.setSize(500, 500); + unpacked.setSize(500, 500); + packed.setLocation(point); + unpacked.setLocation(point); + robot.waitForIdle(); + packed.setVisible(true); + unpacked.setVisible(true); + robot.waitForIdle(); + Rectangle mBounds = main.getBounds(); + Rectangle pBounds = packed.getBounds(); + Rectangle uBounds = unpacked.getBounds(); + + if (!mBounds.equals(uBounds) || + !mBounds.equals(pBounds)) { + System.err.println("Expected bounds: " + mBounds); + System.err.println("Actual unpacked: " + uBounds); + System.err.println("Actual packed: " + pBounds); + throw new RuntimeException(); + } + } finally { + packed.dispose(); + unpacked.dispose(); + } + } + } finally { + main.dispose(); + } + } + + private static Window getTopLevel(String top) { + return switch (top) { + case "window" -> new Window(null); + case "dialog" -> new Dialog((Dialog) null); + case "frame" -> new Frame(); + default -> throw new IllegalArgumentException("Unexpected: " + top); + }; + } +} diff --git a/test/jdk/java/awt/color/MTICC_ColorSpaceToFrom.java b/test/jdk/java/awt/color/MTICC_ColorSpaceToFrom.java new file mode 100644 index 00000000000..0a64e026d4e --- /dev/null +++ b/test/jdk/java/awt/color/MTICC_ColorSpaceToFrom.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ICC_Profile; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * @test + * @bug 8254370 + * @summary Verifies MT safety of ICC_ColorSpace#To/From methods + */ +public final class MTICC_ColorSpaceToFrom { + + private enum Method { + FROM_RGB, FROM_XYZ, TO_RGB, TO_XYZ; + } + + static volatile long endtime; + static volatile boolean failed; + + public static void main(String[] args) throws Exception { + ICC_Profile srgb = ICC_Profile.getInstance(ColorSpace.CS_sRGB); + ICC_Profile gray = ICC_Profile.getInstance(ColorSpace.CS_GRAY); + ICC_Profile xyz = ICC_Profile.getInstance(ColorSpace.CS_CIEXYZ); + ICC_Profile lrgb = ICC_Profile.getInstance(ColorSpace.CS_LINEAR_RGB); + ICC_Profile pycc = ICC_Profile.getInstance(ColorSpace.CS_PYCC); + + // Will run the test no more than 15 seconds + endtime = System.nanoTime() + TimeUnit.SECONDS.toNanos(10); + for (int i = 0; i < 1000 && !isComplete(); i++) { + for (Method method : new Method[]{Method.FROM_RGB, Method.FROM_XYZ, + Method.TO_RGB, Method.TO_XYZ}) { + test(new ICC_ColorSpace(srgb), method); + test(new ICC_ColorSpace(gray), method); + test(new ICC_ColorSpace(xyz), method); + test(new ICC_ColorSpace(lrgb), method); + test(new ICC_ColorSpace(pycc), method); + } + } + if (failed) { + throw new RuntimeException(); + } + } + + private static void test(ColorSpace cs, Method method) throws Exception { + Thread[] ts = new Thread[10]; + CountDownLatch latch = new CountDownLatch(ts.length); + for (int i = 0; i < ts.length; i++) { + ts[i] = new Thread(() -> { + latch.countDown(); + try { + latch.await(); + } catch (InterruptedException ex) { + } + try { + switch (method) { + case TO_RGB -> cs.toRGB(new float[3]); + case FROM_RGB -> cs.fromRGB(new float[3]); + case TO_XYZ -> cs.toCIEXYZ(new float[3]); + case FROM_XYZ -> cs.fromCIEXYZ(new float[3]); + } + } catch (Throwable t) { + t.printStackTrace(); + failed = true; + } + }); + } + for (Thread t : ts) { + t.start(); + } + for (Thread t : ts) { + t.join(); + } + } + + private static boolean isComplete() { + return endtime - System.nanoTime() < 0 || failed; + } +} diff --git a/test/jdk/java/awt/dnd/Button2DragTest/Button2DragTest.java b/test/jdk/java/awt/dnd/Button2DragTest/Button2DragTest.java index 9400f854da1..75e32db4ed9 100644 --- a/test/jdk/java/awt/dnd/Button2DragTest/Button2DragTest.java +++ b/test/jdk/java/awt/dnd/Button2DragTest/Button2DragTest.java @@ -23,10 +23,10 @@ import java.awt.Color; import java.awt.Frame; -import java.awt.GraphicsConfiguration; import java.awt.GraphicsDevice; import java.awt.GraphicsEnvironment; import java.awt.Point; +import java.awt.Rectangle; import java.awt.Robot; import java.awt.datatransfer.StringSelection; import java.awt.dnd.DnDConstants; @@ -47,7 +47,7 @@ /** * @test * @key headful - * @bug 4955110 8238575 + * @bug 4955110 8238575 8211999 * @summary tests that DragSourceDragEvent.getDropAction() accords to its new * spec (does not depend on the user drop action) * @library ../../regtesthelpers @@ -57,6 +57,7 @@ */ public final class Button2DragTest { + private static final int SIZE = 200; private volatile boolean dropSuccess; private volatile boolean locationValid = true; @@ -79,8 +80,8 @@ public void run() { final DragSourceListener dragSourceListener = new DragSourceListener() { private void checkLocation(DragSourceEvent dsde) { if (!frame.getBounds().contains(dsde.getLocation())) { - System.err.println("Expected in" + frame.getBounds()); - System.err.println("Actual" + dsde.getLocation()); + System.err.println("Expected in: " + frame.getBounds()); + System.err.println("Actual: " + dsde.getLocation()); locationValid = false; } } @@ -130,8 +131,10 @@ public void drop(DropTargetDropEvent dtde) { frame.setBackground(Color.GREEN); frame.setUndecorated(true); - frame.setSize(200, 200); - frame.setLocationRelativeTo(null); + Rectangle screen = frame.getGraphicsConfiguration().getBounds(); + int x = (int) (screen.getCenterX() - SIZE / 2); + int y = (int) (screen.getCenterY() - SIZE / 2); + frame.setBounds(x, y, SIZE, SIZE); frame.setVisible(true); Robot robot = Util.createRobot(); diff --git a/test/jdk/java/awt/image/DrawImage/BlitRotateClippedArea.java b/test/jdk/java/awt/image/DrawImage/BlitRotateClippedArea.java new file mode 100644 index 00000000000..5db3fca9b60 --- /dev/null +++ b/test/jdk/java/awt/image/DrawImage/BlitRotateClippedArea.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import static java.awt.Transparency.TRANSLUCENT; + +/** + * @test + * @bug 8255722 + * @key headful + */ +public class BlitRotateClippedArea { + + /** + * The test use case: + * 1. The destination image is created of size 1000x1000 + * 2. The source image is created of size 2000x2000 + * 3. The source image is painted by the pattern outsize of 1000x1000 + * 4. If the source image is painted as-is to the destination then the + * pattern in the source will be ignored, but the test sets some + * specific rotation that the pattern will hit the source. + * Note that rotation is used not a scale/translate. + */ + public static void main(String[] args) throws Exception { + // the test check the exact pixels location + System.setProperty("sun.java2d.uiScale", "1"); + var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + var gc = ge.getDefaultScreenDevice().getDefaultConfiguration(); + + var gold = gc.createCompatibleImage(1000, 1000, TRANSLUCENT); + var dstVI2BI = gc.createCompatibleImage(1000, 1000, TRANSLUCENT); + var dstVI2VI = gc.createCompatibleVolatileImage(1000, 1000, TRANSLUCENT); + var dstBI2VI = gc.createCompatibleVolatileImage(1000, 1000, TRANSLUCENT); + + var srcBI = gc.createCompatibleImage(2000, 2000, TRANSLUCENT); + var srcVI = gc.createCompatibleVolatileImage(2000, 2000, TRANSLUCENT); + + int attempt = 0; + BufferedImage snapshotVI2VI; + BufferedImage snapshotBI2VI; + do { + if (++attempt > 10) { + throw new RuntimeException("Too many attempts: " + attempt); + } + dstVI2VI.validate(gc); + dstBI2VI.validate(gc); + srcVI.validate(gc); + + fill(srcBI); + fill(srcVI); + + init(gold); + init(dstVI2BI); + init(dstVI2VI); + init(dstBI2VI); + + draw(gold, srcBI); + draw(dstVI2BI, srcVI); + draw(dstVI2VI, srcVI); + draw(dstBI2VI, srcBI); + + snapshotVI2VI = dstVI2VI.getSnapshot(); + snapshotBI2VI = dstBI2VI.getSnapshot(); + } while (dstVI2VI.contentsLost() || dstBI2VI.contentsLost() + || srcVI.contentsLost()); + + validate(gold, snapshotVI2VI); + validate(gold, snapshotBI2VI); + validate(gold, dstVI2BI); + } + + private static void validate(BufferedImage gold, BufferedImage img) + throws IOException { + for (int x = 0; x < gold.getWidth(); ++x) { + for (int y = 0; y < gold.getHeight(); ++y) { + if (gold.getRGB(x, y) != img.getRGB(x, y)) { + ImageIO.write(gold, "png", new File("gold.png")); + ImageIO.write(img, "png", new File("snapshot.png")); + throw new RuntimeException("Test failed."); + } + } + } + } + + private static void draw(Image dstBI, Image src) { + Graphics2D g = (Graphics2D) dstBI.getGraphics(); + g.rotate(Math.toRadians(180), 1250, 1150); + g.drawImage(src, 0, 0, null); + g.dispose(); + } + + private static void init(Image image) { + Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + graphics.setColor(Color.YELLOW); + graphics.fillRect(0, 0, image.getWidth(null), image.getHeight(null)); + graphics.dispose(); + } + + private static void fill(Image image) { + Graphics2D graphics = (Graphics2D) image.getGraphics(); + graphics.setComposite(AlphaComposite.Src); + for (int x = 1000; x < image.getWidth(null); ++x) { + for (int y = 1000; y < image.getHeight(null); ++y) { + graphics.setColor(new Color(x % 256, 0, y % 256, 125)); + graphics.fillRect(x, y, 1, 1); + } + } + graphics.dispose(); + } +} + diff --git a/test/jdk/java/io/BufferedInputStream/LargeCopyWithMark.java b/test/jdk/java/io/BufferedInputStream/LargeCopyWithMark.java index 0519e1483f0..e3c171c0220 100644 --- a/test/jdk/java/io/BufferedInputStream/LargeCopyWithMark.java +++ b/test/jdk/java/io/BufferedInputStream/LargeCopyWithMark.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,65 +23,42 @@ /* @test * @bug 7129312 + * @requires (sun.arch.data.model == "64" & os.maxMemory > 4g) * @summary BufferedInputStream calculates negative array size with large * streams and mark - * @library /test/lib - * @run main/othervm LargeCopyWithMark + * @run main/othervm -Xmx4G LargeCopyWithMark */ import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import static jdk.test.lib.process.ProcessTools.*; - public class LargeCopyWithMark { - public static void main(String[] args) throws Exception { - if (! System.getProperty("os.arch").contains("64")) { - System.out.println("Test runs on 64 bit platforms"); - return; - } - ProcessBuilder pb = createJavaProcessBuilder("-Xmx4G", - "-ea:LargeCopyWithMark$Child", - "LargeCopyWithMark$Child"); - int res = pb.inheritIO().start().waitFor(); - if (res != 0) { - throw new AssertionError("Test failed: exit code = " + res); - } - } + static final int BUFF_SIZE = 8192; + static final int BIS_BUFF_SIZE = Integer.MAX_VALUE / 2 + 100; + static final long BYTES_TO_COPY = 2L * Integer.MAX_VALUE; - public static class Child { - static final int BUFF_SIZE = 8192; - static final int BIS_BUFF_SIZE = Integer.MAX_VALUE / 2 + 100; - static final long BYTES_TO_COPY = 2L * Integer.MAX_VALUE; - - static { - assert BIS_BUFF_SIZE * 2 < 0 : "doubling must overflow"; - } + static { + assert BIS_BUFF_SIZE * 2 < 0 : "doubling must overflow"; + } - public static void main(String[] args) throws Exception { - byte[] buff = new byte[BUFF_SIZE]; + public static void main(String[] args) throws Exception { + byte[] buff = new byte[BUFF_SIZE]; - try (InputStream myis = new MyInputStream(BYTES_TO_COPY); - InputStream bis = new BufferedInputStream(myis, BIS_BUFF_SIZE); - OutputStream myos = new MyOutputStream()) { + try (InputStream myis = new MyInputStream(BYTES_TO_COPY); + InputStream bis = new BufferedInputStream(myis, BIS_BUFF_SIZE); + OutputStream myos = new MyOutputStream()) { - // will require a buffer bigger than BIS_BUFF_SIZE - bis.mark(BIS_BUFF_SIZE + 100); + // will require a buffer bigger than BIS_BUFF_SIZE + bis.mark(BIS_BUFF_SIZE + 100); - for (;;) { - int count = bis.read(buff, 0, BUFF_SIZE); - if (count == -1) - break; - myos.write(buff, 0, count); - } - } catch (java.lang.NegativeArraySizeException e) { - e.printStackTrace(); - System.exit(11); - } catch (Exception e) { - e.printStackTrace(); + for (;;) { + int count = bis.read(buff, 0, BUFF_SIZE); + if (count == -1) + break; + myos.write(buff, 0, count); } } } diff --git a/test/jdk/java/lang/invoke/ConstantIdentityMHTest.java b/test/jdk/java/lang/invoke/ConstantIdentityMHTest.java index 34c97a955ae..c0db09bb42a 100644 --- a/test/jdk/java/lang/invoke/ConstantIdentityMHTest.java +++ b/test/jdk/java/lang/invoke/ConstantIdentityMHTest.java @@ -59,8 +59,7 @@ public void testZero(Class expectedtype, String expected) throws Throwable { assertEquals(MethodHandles.zero(expectedtype).type().toString(), expected); } - @Test - @ExpectedExceptions(NullPointerException.class) + @Test(expectedExceptions={ NullPointerException.class }) public void testZeroNPE() { MethodHandle mh = MethodHandles.zero(null); } @@ -73,8 +72,7 @@ void testEmpty() throws Throwable { assertEquals((String)mhEmpty.invoke("x","y"), null); } - @Test - @ExpectedExceptions(NullPointerException.class) + @Test(expectedExceptions = { NullPointerException.class }) void testEmptyNPE() { MethodHandle lenEmptyMH = MethodHandles.empty(null); } diff --git a/test/jdk/java/lang/invoke/DropArgumentsTest.java b/test/jdk/java/lang/invoke/DropArgumentsTest.java index be65b39b276..fd36d07767c 100644 --- a/test/jdk/java/lang/invoke/DropArgumentsTest.java +++ b/test/jdk/java/lang/invoke/DropArgumentsTest.java @@ -65,8 +65,7 @@ private Object[][] dropArgumentsToMatchNPEData() }; } - @Test(dataProvider = "dropArgumentsToMatchNPEData") - @ExpectedExceptions(NullPointerException.class) + @Test(dataProvider = "dropArgumentsToMatchNPEData", expectedExceptions = { NullPointerException.class }) public void dropArgumentsToMatchNPE(MethodHandle target, int pos, List> valueType, int skip) { MethodHandles.dropArgumentsToMatch(target, pos, valueType , skip); } @@ -85,14 +84,12 @@ private Object[][] dropArgumentsToMatchIAEData() }; } - @Test(dataProvider = "dropArgumentsToMatchIAEData") - @ExpectedExceptions(IllegalArgumentException.class) + @Test(dataProvider = "dropArgumentsToMatchIAEData", expectedExceptions = { IllegalArgumentException.class }) public void dropArgumentsToMatchIAE(MethodHandle target, int pos, List> valueType, int skip) { MethodHandles.dropArgumentsToMatch(target, pos, valueType , skip); } - @Test - @ExpectedExceptions(IllegalArgumentException.class) + @Test(expectedExceptions = { IllegalArgumentException.class }) public void dropArgumentsToMatchTestWithVoid() throws Throwable { MethodHandle cat = lookup().findVirtual(String.class, "concat", MethodType.methodType(String.class, String.class)); diff --git a/test/jdk/java/lang/invoke/VarArgsTest.java b/test/jdk/java/lang/invoke/VarArgsTest.java index 2fef2cd90b0..23baee3be88 100644 --- a/test/jdk/java/lang/invoke/VarArgsTest.java +++ b/test/jdk/java/lang/invoke/VarArgsTest.java @@ -69,8 +69,7 @@ public void testWithVarargs2() throws Throwable { assertEquals("[two, too]", asListWithVarargs.invoke("two", "too").toString()); } - @Test - @ExpectedExceptions(IllegalArgumentException.class) + @Test(expectedExceptions = { IllegalArgumentException.class }) public void testWithVarargsIAE() throws Throwable { MethodHandle lenMH = publicLookup() .findVirtual(String.class, "length", methodType(int.class)); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java new file mode 100644 index 00000000000..f40885f8cbe --- /dev/null +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestExact.java @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @modules jdk.incubator.foreign + * + * @run testng/othervm -Xverify:all VarHandleTestExact + * @run testng/othervm -Xverify:all -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=true -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestExact + * @run testng/othervm -Xverify:all -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=false VarHandleTestExact + * @run testng/othervm -Xverify:all -Djava.lang.invoke.VarHandle.VAR_HANDLE_GUARDS=false -Djava.lang.invoke.VarHandle.VAR_HANDLE_IDENTITY_ADAPT=true VarHandleTestExact + */ + +import jdk.incubator.foreign.MemoryAddress; +import jdk.incubator.foreign.MemoryHandles; +import jdk.incubator.foreign.MemorySegment; +import org.testng.SkipException; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.lang.invoke.WrongMethodTypeException; +import java.lang.reflect.Array; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +import static org.testng.Assert.*; + +public class VarHandleTestExact { + + private static class Widget { + static Object objectField_SRW; + static long longField_SRW; + static double doubleField_SRW; + static Long aLongField_SRW; + + Object objectField_RW; + long longField_RW; + double doubleField_RW; + Long aLongField_RW; + + final static Object objectField_SRO = new Object(); + final static long longField_SRO = 1234L; + final static double doubleField_SRO = 1234D; + final static Long aLongField_SRO = 1234L; + + final Object objectField_RO = new Object(); + final long longField_RO = 1234L; + final double doubleField_RO = 1234D; + final Long aLongField_RO = 1234L; + } + + @Test(dataProvider = "dataObjectAccess") + public void testExactSet(String fieldBaseName, Class fieldType, boolean ro, Object testValue, + SetX setter, GetX getter, + SetStaticX staticSetter, GetStaticX staticGetter) + throws NoSuchFieldException, IllegalAccessException { + if (ro) throw new SkipException("Can not test setter with read only field"); + VarHandle vh = MethodHandles.lookup().findVarHandle(Widget.class, fieldBaseName + "_RW", fieldType); + assertFalse(vh.hasInvokeExactBehavior()); + Widget w = new Widget(); + + try { + vh.set(w, testValue); + vh.withInvokeBehavior().set(w, testValue); + } catch (WrongMethodTypeException wmte) { + fail("Unexpected exception", wmte); + } + + vh = vh.withInvokeExactBehavior(); + assertTrue(vh.hasInvokeExactBehavior()); + try { + setter.set(vh, w, testValue); // should throw + fail("Exception expected"); + } catch (WrongMethodTypeException wmte) { + assertMatches(wmte.getMessage(),".*\\Qexpected (Widget," + fieldType.getSimpleName() + ")void \\E.*"); + } + } + + @Test(dataProvider = "dataObjectAccess") + public void testExactGet(String fieldBaseName, Class fieldType, boolean ro, Object testValue, + SetX setter, GetX getter, + SetStaticX staticSetter, GetStaticX staticGetter) + throws NoSuchFieldException, IllegalAccessException { + VarHandle vh = MethodHandles.lookup().findVarHandle(Widget.class, fieldBaseName + (ro ? "_RO" : "_RW"), fieldType); + assertFalse(vh.hasInvokeExactBehavior()); + Widget w = new Widget(); + + try { + Object o = vh.get(w); + Object o2 = vh.withInvokeBehavior().get(w); + } catch (WrongMethodTypeException wmte) { + fail("Unexpected exception", wmte); + } + + vh = vh.withInvokeExactBehavior(); + assertTrue(vh.hasInvokeExactBehavior()); + try { + getter.get(vh, w); // should throw + fail("Exception expected"); + } catch (WrongMethodTypeException wmte) { + assertMatches(wmte.getMessage(),".*\\Qexpected (Widget)" + fieldType.getSimpleName() + " \\E.*"); + } + } + + @Test(dataProvider = "dataObjectAccess") + public void testExactSetStatic(String fieldBaseName, Class fieldType, boolean ro, Object testValue, + SetX setter, GetX getter, + SetStaticX staticSetter, GetStaticX staticGetter) + throws NoSuchFieldException, IllegalAccessException { + if (ro) throw new SkipException("Can not test setter with read only field"); + VarHandle vh = MethodHandles.lookup().findStaticVarHandle(Widget.class, fieldBaseName + "_SRW", fieldType); + assertFalse(vh.hasInvokeExactBehavior()); + + try { + vh.set(testValue); + vh.withInvokeBehavior().set(testValue); + } catch (WrongMethodTypeException wmte) { + fail("Unexpected exception", wmte); + } + + vh = vh.withInvokeExactBehavior(); + assertTrue(vh.hasInvokeExactBehavior()); + try { + staticSetter.set(vh, testValue); // should throw + fail("Exception expected"); + } catch (WrongMethodTypeException wmte) { + assertMatches(wmte.getMessage(),".*\\Qexpected (" + fieldType.getSimpleName() + ")void \\E.*"); + } + } + + @Test(dataProvider = "dataObjectAccess") + public void testExactGetStatic(String fieldBaseName, Class fieldType, boolean ro, Object testValue, + SetX setter, GetX getter, + SetStaticX staticSetter, GetStaticX staticGetter) + throws NoSuchFieldException, IllegalAccessException { + VarHandle vh = MethodHandles.lookup().findStaticVarHandle(Widget.class, fieldBaseName + (ro ? "_SRO" : "_SRW"), fieldType); + assertFalse(vh.hasInvokeExactBehavior()); + + try { + Object o = vh.get(); + Object o2 = vh.withInvokeBehavior().get(); + } catch (WrongMethodTypeException wmte) { + fail("Unexpected exception", wmte); + } + + vh = vh.withInvokeExactBehavior(); + assertTrue(vh.hasInvokeExactBehavior()); + try { + staticGetter.get(vh); // should throw + fail("Exception expected"); + } catch (WrongMethodTypeException wmte) { + assertMatches(wmte.getMessage(),".*\\Qexpected ()" + fieldType.getSimpleName() + " \\E.*"); + } + } + + @Test(dataProvider = "dataSetArray") + public void testExactArraySet(Class arrayClass, Object testValue, SetArrayX setter) { + VarHandle vh = MethodHandles.arrayElementVarHandle(arrayClass); + Object arr = Array.newInstance(arrayClass.componentType(), 1); + assertFalse(vh.hasInvokeExactBehavior()); + + try { + vh.set(arr, 0, testValue); + vh.withInvokeBehavior().set(arr, 0, testValue); + } catch (WrongMethodTypeException wmte) { + fail("Unexpected exception", wmte); + } + + vh = vh.withInvokeExactBehavior(); + assertTrue(vh.hasInvokeExactBehavior()); + try { + setter.set(vh, arr, testValue); // should throw + fail("Exception expected"); + } catch (WrongMethodTypeException wmte) { + assertMatches(wmte.getMessage(), + ".*\\Qexpected (" + arrayClass.getSimpleName() + ",int," + arrayClass.componentType().getSimpleName() + ")void \\E.*"); + } + } + + @Test(dataProvider = "dataSetBuffer") + public void testExactBufferSet(Class arrayClass, Object testValue, SetBufferX setter) { + VarHandle vh = MethodHandles.byteBufferViewVarHandle(arrayClass, ByteOrder.nativeOrder()); + assertFalse(vh.hasInvokeExactBehavior()); + ByteBuffer buff = ByteBuffer.allocateDirect(8); + + try { + vh.set(buff, 0, testValue); + vh.withInvokeBehavior().set(buff, 0, testValue); + } catch (WrongMethodTypeException wmte) { + fail("Unexpected exception", wmte); + } + + vh = vh.withInvokeExactBehavior(); + assertTrue(vh.hasInvokeExactBehavior()); + try { + setter.set(vh, buff, testValue); // should throw + fail("Exception expected"); + } catch (WrongMethodTypeException wmte) { + assertMatches(wmte.getMessage(), + ".*\\Qexpected (ByteBuffer,int," + arrayClass.componentType().getSimpleName() + ")void \\E.*"); + } + } + + @Test(dataProvider = "dataSetMemorySegment") + public void testExactSegmentSet(Class carrier, Object testValue, SetSegmentX setter) { + VarHandle vh = MemoryHandles.varHandle(carrier, ByteOrder.nativeOrder()); + assertFalse(vh.hasInvokeExactBehavior()); + try (MemorySegment seg = MemorySegment.allocateNative(8)) { + MemoryAddress base = seg.baseAddress(); + try { + vh.set(base, testValue); + vh.withInvokeBehavior().set(base, testValue); + } catch (WrongMethodTypeException wmte) { + fail("Unexpected exception", wmte); + } + + vh = vh.withInvokeExactBehavior(); + assertTrue(vh.hasInvokeExactBehavior()); + try { + setter.set(vh, base, testValue); // should throw + fail("Exception expected"); + } catch (WrongMethodTypeException wmte) { + assertMatches(wmte.getMessage(), + ".*\\Qexpected (MemoryAddress," + carrier.getSimpleName() + ")void \\E.*"); + } + } + } + + private static void assertMatches(String str, String pattern) { + if (!str.matches(pattern)) { + throw new AssertionError("'" + str + "' did not match the pattern '" + pattern + "'."); + } + } + + private interface SetX { + void set(VarHandle vh, Widget w, Object testValue); + } + + private interface SetStaticX { + void set(VarHandle vh, Object testValue); + } + + private interface GetX { + void get(VarHandle vh, Widget w); + } + + private interface GetStaticX { + void get(VarHandle vh); + } + + private interface SetArrayX { + void set(VarHandle vh, Object array, Object testValue); + } + + private interface SetBufferX { + void set(VarHandle vh, ByteBuffer buff, Object testValue); + } + + private interface SetSegmentX { + void set(VarHandle vh, MemoryAddress addr, Object testValue); + } + + private static void consume(Object o) {} + + private static void testCaseObjectAccess(List cases, String fieldBaseName, Class fieldType, Object testValue, + SetX setter, GetX getter, + SetStaticX staticSetter, GetStaticX staticGetter) { + cases.add(new Object[] { fieldBaseName, fieldType, false, testValue, setter, getter, staticSetter, staticGetter }); + cases.add(new Object[] { fieldBaseName, fieldType, true, testValue, setter, getter, staticSetter, staticGetter }); + } + + private static void testCaseArraySet(List cases, Class arrayType, Object testValue, SetArrayX setter) { + cases.add(new Object[] { arrayType, testValue, setter }); + } + + private static void testCaseBufferSet(List cases, Class arrayType, Object testValue, SetBufferX setter) { + cases.add(new Object[] { arrayType, testValue, setter }); + } + + private static void testCaseSegmentSet(List cases, Class carrier, Object testValue, SetSegmentX setter) { + cases.add(new Object[] { carrier, testValue, setter }); + } + + @DataProvider + public static Object[][] dataObjectAccess() { + List cases = new ArrayList<>(); + + // create a bunch of different sig-poly call sites + testCaseObjectAccess(cases, "objectField", Object.class, "abcd", + (vh, w, tv) -> vh.set(w, (String) tv), + (vh, w) -> consume((String) vh.get(w)), + (vh, tv) -> vh.set((String) tv), + (vh) -> consume((String) vh.get())); + testCaseObjectAccess(cases, "objectField", Object.class, Integer.valueOf(1234), + (vh, w, tv) -> vh.set(w, (Integer) tv), + (vh, w) -> consume((Integer) vh.get(w)), + (vh, tv) -> vh.set((Integer) tv), + (vh) -> consume((Integer) vh.get())); + testCaseObjectAccess(cases, "longField", long.class, 1234, + (vh, w, tv) -> vh.set(w, (int) tv), + (vh, w) -> consume((int) vh.get(w)), + (vh, tv) -> vh.set((int) tv), + (vh) -> consume((int) vh.get())); + testCaseObjectAccess(cases, "longField", long.class, (short) 1234, + (vh, w, tv) -> vh.set(w, (short) tv), + (vh, w) -> consume((short) vh.get(w)), + (vh, tv) -> vh.set((short) tv), + (vh) -> consume((short) vh.get())); + testCaseObjectAccess(cases, "longField", long.class, (char) 1234, + (vh, w, tv) -> vh.set(w, (char) tv), + (vh, w) -> consume((char) vh.get(w)), + (vh, tv) -> vh.set((char) tv), + (vh) -> consume((char) vh.get())); + testCaseObjectAccess(cases, "longField", long.class, (byte) 1234, + (vh, w, tv) -> vh.set(w, (byte) tv), + (vh, w) -> consume((byte) vh.get(w)), + (vh, tv) -> vh.set((byte) tv), + (vh) -> consume((byte) vh.get())); + testCaseObjectAccess(cases, "longField", long.class, Long.valueOf(1234L), + (vh, w, tv) -> vh.set(w, (Long) tv), + (vh, w) -> consume((Long) vh.get(w)), + (vh, tv) -> vh.set((Long) tv), + (vh) -> consume((Long) vh.get())); + testCaseObjectAccess(cases, "doubleField", double.class, 1234F, + (vh, w, tv) -> vh.set(w, (float) tv), + (vh, w) -> consume((float) vh.get(w)), + (vh, tv) -> vh.set((float) tv), + (vh) -> consume((float) vh.get())); + testCaseObjectAccess(cases, "doubleField", double.class, 1234, + (vh, w, tv) -> vh.set(w, (int) tv), + (vh, w) -> consume((int) vh.get(w)), + (vh, tv) -> vh.set((int) tv), + (vh) -> consume((int) vh.get())); + testCaseObjectAccess(cases, "doubleField", double.class, 1234L, + (vh, w, tv) -> vh.set(w, (long) tv), + (vh, w) -> consume((long) vh.get(w)), + (vh, tv) -> vh.set((long) tv), + (vh) -> consume((long) vh.get())); + testCaseObjectAccess(cases, "doubleField", double.class, Double.valueOf(1234D), + (vh, w, tv) -> vh.set(w, (Double) tv), + (vh, w) -> consume((Double) vh.get(w)), + (vh, tv) -> vh.set((Double) tv), + (vh) -> consume((Double) vh.get())); + testCaseObjectAccess(cases, "aLongField", Long.class, 1234L, + (vh, w, tv) -> vh.set(w, (long) tv), + (vh, w) -> consume((long) vh.get(w)), + (vh, tv) -> vh.set((long) tv), + (vh) -> consume((long) vh.get())); + + return cases.toArray(Object[][]::new); + } + + @DataProvider + public static Object[][] dataSetArray() { + List cases = new ArrayList<>(); + + // create a bunch of different sig-poly call sites + testCaseArraySet(cases, Object[].class, "abcd", (vh, arr, tv) -> vh.set((Object[]) arr, 0, (String) tv)); + testCaseArraySet(cases, Object[].class, Integer.valueOf(1234), (vh, arr, tv) -> vh.set((Object[]) arr, (Integer) tv)); + testCaseArraySet(cases, long[].class, 1234, (vh, arr, tv) -> vh.set((long[]) arr, 0, (int) tv)); + testCaseArraySet(cases, long[].class, (short) 1234, (vh, arr, tv) -> vh.set((long[]) arr, 0, (short) tv)); + testCaseArraySet(cases, long[].class, (char) 1234, (vh, arr, tv) -> vh.set((long[]) arr, 0, (char) tv)); + testCaseArraySet(cases, long[].class, (byte) 1234, (vh, arr, tv) -> vh.set((long[]) arr, 0, (byte) tv)); + testCaseArraySet(cases, long[].class, Long.valueOf(1234L), (vh, arr, tv) -> vh.set((long[]) arr, 0, (Long) tv)); + testCaseArraySet(cases, double[].class, 1234F, (vh, arr, tv) -> vh.set((double[]) arr, 0, (float) tv)); + testCaseArraySet(cases, double[].class, 1234, (vh, arr, tv) -> vh.set((double[]) arr, 0, (int) tv)); + testCaseArraySet(cases, double[].class, 1234L, (vh, arr, tv) -> vh.set((double[]) arr, 0, (long) tv)); + testCaseArraySet(cases, double[].class, Double.valueOf(1234D), (vh, arr, tv) -> vh.set((double[]) arr, 0, (Double) tv)); + testCaseArraySet(cases, Long[].class, 1234L, (vh, arr, tv) -> vh.set((Long[]) arr, 0, (long) tv)); + + return cases.toArray(Object[][]::new); + } + + @DataProvider + public static Object[][] dataSetBuffer() { + List cases = new ArrayList<>(); + + // create a bunch of different sig-poly call sites + testCaseBufferSet(cases, long[].class, 1234, (vh, buff, tv) -> vh.set(buff, 0, (int) tv)); + testCaseBufferSet(cases, long[].class, (short) 1234, (vh, buff, tv) -> vh.set(buff, 0, (short) tv)); + testCaseBufferSet(cases, long[].class, (char) 1234, (vh, buff, tv) -> vh.set(buff, 0, (char) tv)); + testCaseBufferSet(cases, long[].class, (byte) 1234, (vh, buff, tv) -> vh.set(buff, 0, (byte) tv)); + testCaseBufferSet(cases, long[].class, Long.valueOf(1234L), (vh, buff, tv) -> vh.set(buff, 0, (Long) tv)); + testCaseBufferSet(cases, double[].class, 1234F, (vh, buff, tv) -> vh.set(buff, 0, (float) tv)); + testCaseBufferSet(cases, double[].class, 1234, (vh, buff, tv) -> vh.set(buff, 0, (int) tv)); + testCaseBufferSet(cases, double[].class, 1234L, (vh, buff, tv) -> vh.set(buff, 0, (long) tv)); + testCaseBufferSet(cases, double[].class, Double.valueOf(1234D), (vh, buff, tv) -> vh.set(buff, 0, (Double) tv)); + + return cases.toArray(Object[][]::new); + } + + @DataProvider + public static Object[][] dataSetMemorySegment() { + List cases = new ArrayList<>(); + + // create a bunch of different sig-poly call sites + testCaseSegmentSet(cases, long.class, 1234, (vh, addr, tv) -> vh.set(addr, (int) tv)); + testCaseSegmentSet(cases, long.class, (char) 1234, (vh, addr, tv) -> vh.set(addr, (char) tv)); + testCaseSegmentSet(cases, long.class, (short) 1234, (vh, addr, tv) -> vh.set(addr, (short) tv)); + testCaseSegmentSet(cases, long.class, (byte) 1234, (vh, addr, tv) -> vh.set(addr, (byte) tv)); + testCaseSegmentSet(cases, double.class, 1234F, (vh, addr, tv) -> vh.set(addr, (float) tv)); + + return cases.toArray(Object[][]::new); + } + +} diff --git a/test/jdk/java/net/NetworkInterface/UniqueMacAddressesTest.java b/test/jdk/java/net/NetworkInterface/UniqueMacAddressesTest.java index 4017c0702ed..a01394831e7 100644 --- a/test/jdk/java/net/NetworkInterface/UniqueMacAddressesTest.java +++ b/test/jdk/java/net/NetworkInterface/UniqueMacAddressesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,87 +21,68 @@ * questions. */ -import java.net.InetAddress; +import java.io.PrintStream; +import java.io.UncheckedIOException; import java.net.NetworkInterface; import java.net.SocketException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Enumeration; import java.util.List; +import java.util.stream.Collectors; +import jdk.test.lib.NetworkConfiguration; /* * @test * @bug 8021372 * @summary Tests that the MAC addresses returned by NetworkInterface.getNetworkInterfaces are unique for each adapter. - * + * @library /test/lib + * @build jdk.test.lib.NetworkConfiguration + * @run main/othervm UniqueMacAddressesTest */ public class UniqueMacAddressesTest { + static PrintStream log = System.err; + + // A record pair (NetworkInterface::name, NetworkInterface::hardwareAddress) + record NetIfPair(String interfaceName, byte[] address) {} + public static void main(String[] args) throws Exception { new UniqueMacAddressesTest().execute(); - System.out.println("UniqueMacAddressesTest: OK"); + log.println("UniqueMacAddressesTest: OK"); } public UniqueMacAddressesTest() { - System.out.println("UniqueMacAddressesTest: start "); + log.println("UniqueMacAddressesTest: start"); } public void execute() throws Exception { - Enumeration networkInterfaces; - boolean areMacAddressesUnique = false; - List networkInterfaceList = new ArrayList(); - networkInterfaces = NetworkInterface.getNetworkInterfaces(); - - // build a list of NetworkInterface objects to test MAC address - // uniqueness - createNetworkInterfaceList(networkInterfaces, networkInterfaceList); - areMacAddressesUnique = checkMacAddressesAreUnique(networkInterfaceList); - if (!areMacAddressesUnique) { + // build a list of NetworkInterface name address pairs + // to test MAC address uniqueness + List netIfList = createNetworkInterfaceList(NetworkConfiguration.probe()); + if (!macAddressesAreUnique(netIfList)) throw new RuntimeException("mac address uniqueness test failed"); - } } - private boolean checkMacAddressesAreUnique ( - List networkInterfaces) throws Exception { - boolean uniqueMacAddresses = true; - for (NetworkInterface networkInterface : networkInterfaces) { - for (NetworkInterface comparisonNetIf : networkInterfaces) { - System.out.println("Comparing netif " - + networkInterface.getName() + " and netif " - + comparisonNetIf.getName()); - if (testMacAddressesEqual(networkInterface, comparisonNetIf)) { - uniqueMacAddresses = false; - break; - } + private boolean macAddressesAreUnique(List netIfPairs) { + for (NetIfPair netIfPair : netIfPairs) { + for (NetIfPair compNetIfPair : netIfPairs) { + if (!netIfPair.interfaceName.equals(compNetIfPair.interfaceName) && + testMacAddressesEqual(netIfPair, compNetIfPair)) + return false; } - if (uniqueMacAddresses != true) - break; } - return uniqueMacAddresses; + return true; } - private boolean testMacAddressesEqual(NetworkInterface netIf1, - NetworkInterface netIf2) throws Exception { - - byte[] rawMacAddress1 = null; - byte[] rawMacAddress2 = null; - boolean macAddressesEqual = false; - if (!netIf1.getName().equals(netIf2.getName())) { - System.out.println("compare hardware addresses " - + createMacAddressString(netIf1) + " and " + createMacAddressString(netIf2)); - rawMacAddress1 = netIf1.getHardwareAddress(); - rawMacAddress2 = netIf2.getHardwareAddress(); - macAddressesEqual = Arrays.equals(rawMacAddress1, rawMacAddress2); - } else { - // same interface - macAddressesEqual = false; - } - return macAddressesEqual; + private boolean testMacAddressesEqual(NetIfPair if1, NetIfPair if2) { + log.println("Compare hardware addresses of " + if1.interfaceName + " (" + + createMacAddressString(if1.address) + ")" + " and " + if2.interfaceName + + " (" + createMacAddressString(if2.address) + ")"); + return (Arrays.equals(if1.address, if2.address)); } - private String createMacAddressString (NetworkInterface netIf) throws Exception { - byte[] macAddr = netIf.getHardwareAddress(); + private String createMacAddressString(byte[] macAddr) { StringBuilder sb = new StringBuilder(); if (macAddr != null) { for (int i = 0; i < macAddr.length; i++) { @@ -112,21 +93,18 @@ private String createMacAddressString (NetworkInterface netIf) throws Exception return sb.toString(); } - private void createNetworkInterfaceList(Enumeration nis, - List networkInterfaceList) throws Exception { - byte[] macAddr = null; - NetworkInterface netIf = null; - while (nis.hasMoreElements()) { - netIf = (NetworkInterface) nis.nextElement(); - if (netIf.isUp()) { - macAddr = netIf.getHardwareAddress(); - if (macAddr != null) { - System.out.println("Adding NetworkInterface " - + netIf.getName() + " with mac address " - + createMacAddressString(netIf)); - networkInterfaceList.add(netIf); - } - } + private byte[] getNetworkInterfaceHardwareAddress(NetworkInterface inf) { + try { + return inf.getHardwareAddress(); + } catch (SocketException se) { + throw new UncheckedIOException(se); } } + + private List createNetworkInterfaceList(NetworkConfiguration netConf) { + return netConf.interfaces() + .map(netIf -> new NetIfPair(netIf.getName(), getNetworkInterfaceHardwareAddress(netIf))) + .collect(Collectors.filtering(netIfPair -> netIfPair.address != null, + Collectors.toCollection(ArrayList::new))); + } } diff --git a/test/jdk/java/nio/Buffer/BulkPutBuffer.java b/test/jdk/java/nio/Buffer/BulkPutBuffer.java index fc3c55b9187..c5c4d0bcd6d 100644 --- a/test/jdk/java/nio/Buffer/BulkPutBuffer.java +++ b/test/jdk/java/nio/Buffer/BulkPutBuffer.java @@ -49,7 +49,7 @@ /* * @test - * @bug 8245121 + * @bug 8219014 8245121 * @summary Ensure that a bulk put of a buffer into another is correct. * @compile --enable-preview -source ${jdk.version} BulkPutBuffer.java * @run testng/othervm --enable-preview BulkPutBuffer @@ -142,9 +142,11 @@ public static class BufferProxy { MethodHandle alloc; MethodHandle allocBB; MethodHandle allocDirect; + MethodHandle asReadOnlyBuffer; MethodHandle asTypeBuffer; MethodHandle putAbs; MethodHandle getAbs; + MethodHandle putBufAbs; MethodHandle putBufRel; MethodHandle equals; @@ -168,6 +170,9 @@ public static class BufferProxy { MethodType.methodType(ByteBuffer.class, int.class)); allocDirect = lookup.findStatic(ByteBuffer.class, "allocateDirect", MethodType.methodType(ByteBuffer.class, int.class)); + + asReadOnlyBuffer = lookup.findVirtual(bufferType, + "asReadOnlyBuffer", MethodType.methodType(bufferType)); if (elementType != byte.class) { asTypeBuffer = lookup.findVirtual(ByteBuffer.class, "as" + name + "Buffer", MethodType.methodType(bufferType)); @@ -177,8 +182,13 @@ public static class BufferProxy { MethodType.methodType(bufferType, int.class, elementType)); getAbs = lookup.findVirtual(bufferType, "get", MethodType.methodType(elementType, int.class)); + + putBufAbs = lookup.findVirtual(bufferType, "put", + MethodType.methodType(bufferType, int.class, bufferType, + int.class, int.class)); putBufRel = lookup.findVirtual(bufferType, "put", MethodType.methodType(bufferType, bufferType)); + equals = lookup.findVirtual(bufferType, "equals", MethodType.methodType(boolean.class, Object.class)); @@ -239,6 +249,25 @@ void copy(Buffer src, int srcOff, Buffer dst, int dstOff, int length) } } + Buffer asReadOnlyBuffer(Buffer buf) throws Throwable { + try { + return (Buffer)asReadOnlyBuffer.invoke(buf); + } catch (Exception e) { + throw new AssertionError(e); + } + } + + void put(Buffer src, int srcOff, Buffer dst, int dstOff, int length) + throws Throwable { + try { + putBufAbs.invoke(dst, dstOff, src, srcOff, length); + } catch (ReadOnlyBufferException ro) { + throw ro; + } catch (Exception e) { + throw new AssertionError(e); + } + } + void put(Buffer src, Buffer dst) throws Throwable { try { putBufRel.invoke(dst, src); @@ -294,6 +323,40 @@ static Object[][] proxyPairs() { return args.toArray(Object[][]::new); } + private static void expectThrows(Class exClass, Assert.ThrowingRunnable r) { + try { + r.run(); + } catch(Throwable e) { + if (e.getClass() != exClass && e.getCause().getClass() != exClass) { + throw new RuntimeException("Expected " + exClass + + "; got " + e.getCause().getClass(), e); + } + } + } + + @Test(dataProvider = "proxies") + public static void testExceptions(BufferProxy bp) throws Throwable { + int cap = 27; + Buffer buf = bp.create(cap); + + expectThrows(IndexOutOfBoundsException.class, + () -> bp.put(buf, -1, buf, 0, 1)); + expectThrows(IndexOutOfBoundsException.class, + () -> bp.put(buf, 0, buf, -1, 1)); + expectThrows(IndexOutOfBoundsException.class, + () -> bp.put(buf, 1, buf, 0, cap)); + expectThrows(IndexOutOfBoundsException.class, + () -> bp.put(buf, 0, buf, 1, cap)); + expectThrows(IndexOutOfBoundsException.class, + () -> bp.put(buf, 0, buf, 0, cap + 1)); + expectThrows(IndexOutOfBoundsException.class, + () -> bp.put(buf, 0, buf, 0, Integer.MAX_VALUE)); + + Buffer rob = buf.isReadOnly() ? buf : bp.asReadOnlyBuffer(buf); + expectThrows(ReadOnlyBufferException.class, + () -> bp.put(buf, 0, rob, 0, cap)); + } + @Test(dataProvider = "proxies") public static void testSelf(BufferProxy bp) throws Throwable { for (int i = 0; i < ITERATIONS; i++) { @@ -311,22 +374,27 @@ public static void testSelf(BufferProxy bp) throws Throwable { Assert.expectThrows(ReadOnlyBufferException.class, () -> bp.copy(lower, 0, lowerCopy, 0, lowerLength)); break; - } else { - bp.copy(lower, 0, lowerCopy, 0, lowerLength); } + bp.copy(lower, 0, lowerCopy, 0, lowerLength); int middleOffset = RND.nextInt(1 + cap/2); Buffer middle = buf.slice(middleOffset, lowerLength); + Buffer middleCopy = bp.create(lowerLength); + bp.copy(middle, 0, middleCopy, 0, lowerLength); - if (middle.isReadOnly()) { - Assert.expectThrows(ReadOnlyBufferException.class, - () -> bp.put(lower, middle)); - break; - } else { - bp.put(lower, middle); - } + bp.put(lower, middle); middle.flip(); + Assert.assertTrue(bp.equals(lowerCopy, middle), + String.format("%d %s %d %d %d %d%n", SEED, + buf.getClass().getName(), cap, + lowerOffset, lowerLength, middleOffset)); + + bp.copy(lowerCopy, 0, buf, lowerOffset, lowerLength); + bp.copy(middleCopy, 0, buf, middleOffset, lowerLength); + + bp.put(buf, lowerOffset, buf, middleOffset, lowerLength); + Assert.assertTrue(bp.equals(lowerCopy, middle), String.format("%d %s %d %d %d %d%n", SEED, buf.getClass().getName(), cap, @@ -361,13 +429,29 @@ public static void testPairs(BufferProxy bp, BufferProxy sbp) throws Throwable { Assert.expectThrows(ReadOnlyBufferException.class, () -> bp.put(src, buf)); break; - } else { - bp.put(src, buf); } + Buffer backup = bp.create(slim - spos); + bp.copy(buf, pos, backup, 0, backup.capacity()); + bp.put(src, buf); + buf.reset(); src.reset(); + Assert.assertTrue(bp.equals(src, buf), + String.format("%d %s %d %d %d %s %d %d %d%n", SEED, + buf.getClass().getName(), cap, pos, lim, + src.getClass().getName(), scap, spos, slim)); + + src.clear(); + buf.clear(); + bp.copy(backup, 0, buf, pos, backup.capacity()); + bp.put(src, spos, buf, pos, backup.capacity()); + src.position(spos); + src.limit(slim); + buf.position(pos); + buf.limit(lim); + Assert.assertTrue(bp.equals(src, buf), String.format("%d %s %d %d %d %s %d %d %d%n", SEED, buf.getClass().getName(), cap, pos, lim, diff --git a/test/jdk/javax/imageio/stream/StreamFlush.java b/test/jdk/javax/imageio/stream/StreamFlush.java index fe0569ee445..cea1baa4a0c 100644 --- a/test/jdk/javax/imageio/stream/StreamFlush.java +++ b/test/jdk/javax/imageio/stream/StreamFlush.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,8 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import javax.imageio.ImageIO; import javax.imageio.stream.ImageOutputStream; @@ -44,14 +46,20 @@ public static void main(String[] args) throws IOException { ImageIO.setUseCache(true); // Create a FileImageOutputStream from a FileOutputStream - File temp1 = File.createTempFile("imageio", ".tmp"); - temp1.deleteOnExit(); - ImageOutputStream fios = ImageIO.createImageOutputStream(temp1); - + File temp1 = File.createTempFile("StreamFlush_fis_", ".tmp"); // Create a FileCacheImageOutputStream from a BufferedOutputStream - File temp2 = File.createTempFile("imageio", ".tmp"); - temp2.deleteOnExit(); - FileOutputStream fos2 = new FileOutputStream(temp2); + File temp2 = File.createTempFile("StreamFlush_bos_", ".tmp"); + try (ImageOutputStream fios = ImageIO.createImageOutputStream(temp1); + FileOutputStream fos2 = new FileOutputStream(temp2)) { + test(temp1, fios, temp2, fos2); + } finally { + Files.delete(Paths.get(temp1.getAbsolutePath())); + Files.delete(Paths.get(temp2.getAbsolutePath())); + } + } + + private static void test(File temp1, ImageOutputStream fios, File temp2, + FileOutputStream fos2) throws IOException { BufferedOutputStream bos = new BufferedOutputStream(fos2); ImageOutputStream fcios1 = ImageIO.createImageOutputStream(bos); diff --git a/test/jdk/javax/sound/midi/SysexMessage/SendRawSysexMessage.java b/test/jdk/javax/sound/midi/SysexMessage/SendRawSysexMessage.java new file mode 100644 index 00000000000..591def651fb --- /dev/null +++ b/test/jdk/javax/sound/midi/SysexMessage/SendRawSysexMessage.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.MidiSystem; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.SysexMessage; + +import static javax.sound.midi.SysexMessage.SPECIAL_SYSTEM_EXCLUSIVE; +import static javax.sound.midi.SysexMessage.SYSTEM_EXCLUSIVE; + +/** + * @test + * @bug 8237495 + * @summary fail with a dereferenced memory error when asked to send a raw 0xF7 + */ +public final class SendRawSysexMessage { + + private static final class RawMidiMessage extends MidiMessage { + @Override + public RawMidiMessage clone() { + return new RawMidiMessage(getMessage()); + } + @Override + public int getStatus() { + return SYSTEM_EXCLUSIVE; // not that this really matters + } + + RawMidiMessage(byte[] data) { + super(data.clone()); + } + } + + public static void main(String[] args) throws Exception { + MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo(); + System.err.println("List of devices to test:"); + for (int i = 0; i < infos.length; i++) { + System.err.printf("\t%d.\t%s%n", i, infos[i]); + } + for (int i = 0; i < infos.length; i++) { + System.err.printf("%d.\t%s%n", i, infos[i]); + try { + test(infos[i]); + } catch (MidiUnavailableException ignored){ + // try next + } + } + } + + private static void test(MidiDevice.Info info) throws Exception { + try (MidiDevice device = MidiSystem.getMidiDevice(info)) { + System.err.println("Sending to " + device + " (" + info + ")"); + if (!device.isOpen()) + device.open(); + try (Receiver r = device.getReceiver()) { + System.err.println("note on"); + r.send(new ShortMessage(ShortMessage.NOTE_ON, 5, 5), -1); + System.err.println("sysex"); + r.send(new SysexMessage(new byte[]{ + (byte) SYSTEM_EXCLUSIVE, 0x0, 0x03, 0x04, + (byte) SPECIAL_SYSTEM_EXCLUSIVE}, 5), -1); + System.err.println("raw 1"); + r.send(new RawMidiMessage(new byte[]{ + (byte) 0x02, 0x02, 0x03, 0x04}), -1); + System.err.println("raw 2"); + r.send(new RawMidiMessage(new byte[]{ + (byte) 0x09, 0x02, 0x03, 0x04}), -1); + System.err.println("raw 3"); + r.send(new RawMidiMessage(new byte[]{ + (byte) SYSTEM_EXCLUSIVE, 0x02, 0x03, 0x04}), -1); + System.err.println("raw 4"); + r.send(new RawMidiMessage(new byte[]{ + (byte) 0x02, 0x02, 0x03, 0x04}), -1); + System.err.println("raw 5"); + r.send(new RawMidiMessage(new byte[]{ + (byte) 0x02, 0x02, 0x03, + (byte) SPECIAL_SYSTEM_EXCLUSIVE}), -1); + System.err.println("raw 6"); + r.send(new RawMidiMessage(new byte[]{ + (byte) SYSTEM_EXCLUSIVE, 0x02, 0x03, 0x04}), -1); + System.err.println("sleep"); + Thread.sleep(1000); + System.err.println("raw 7"); + r.send(new RawMidiMessage(new byte[]{ + (byte) 0x02, 0x02, 0x03, 0x04}), -1); + System.err.println("sleep"); + Thread.sleep(1000); + System.err.println("raw 8"); + r.send(new RawMidiMessage(new byte[]{ + (byte) SPECIAL_SYSTEM_EXCLUSIVE}), -1); + System.err.println("note off"); + r.send(new ShortMessage(ShortMessage.NOTE_OFF, 5, 5), -1); + System.err.println("done, should quit"); + System.err.println(); + } + } + } +} diff --git a/test/jdk/javax/swing/JComponent/7154030/bug7154030.java b/test/jdk/javax/swing/JComponent/7154030/bug7154030.java index 81a3548486d..4835c07bf94 100644 --- a/test/jdk/javax/swing/JComponent/7154030/bug7154030.java +++ b/test/jdk/javax/swing/JComponent/7154030/bug7154030.java @@ -39,6 +39,8 @@ import java.awt.Robot; import java.awt.Toolkit; import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; +import java.io.File; /* * @test @@ -57,6 +59,7 @@ public class bug7154030 { private static JButton button = null; private static JFrame frame; + private static int locx, locy, frw, frh; public static void main(String[] args) throws Exception { try { @@ -86,14 +89,21 @@ public void run() { frame.setContentPane(desktop); frame.setSize(300, 300); - frame.setLocation(0, 0); + frame.setLocationRelativeTo(null); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); } }); - robot.waitForIdle(500); - imageInit = robot.createScreenCapture(new Rectangle(0, 0, 300, 300)); + robot.waitForIdle(1000); + + Rectangle bounds = frame.getBounds(); + locx = bounds.x; + locy = bounds.y; + frw = bounds.width; + frh = bounds.height; + + imageInit = robot.createScreenCapture(new Rectangle(locx, locy, frw, frh)); SwingUtilities.invokeAndWait(new Runnable() { @@ -104,8 +114,10 @@ public void run() { }); robot.waitForIdle(500); - imageShow = robot.createScreenCapture(new Rectangle(0, 0, 300, 300)); + imageShow = robot.createScreenCapture(new Rectangle(locx, locy, frw, frh)); if (Util.compareBufferedImages(imageInit, imageShow)) { + ImageIO.write(imageInit, "png", new File("imageInit.png")); + ImageIO.write(imageShow, "png", new File("imageShow.png")); throw new Exception("Failed to show opaque button"); } @@ -119,9 +131,11 @@ public void run() { }); robot.waitForIdle(500); - imageHide = robot.createScreenCapture(new Rectangle(0, 0, 300, 300)); + imageHide = robot.createScreenCapture(new Rectangle(locx, locy, frw, frh)); if (!Util.compareBufferedImages(imageInit, imageHide)) { + ImageIO.write(imageInit, "png", new File("imageInit.png")); + ImageIO.write(imageHide, "png", new File("imageHide.png")); throw new Exception("Failed to hide opaque button"); } @@ -136,7 +150,7 @@ public void run() { }); robot.waitForIdle(500); - imageInit = robot.createScreenCapture(new Rectangle(0, 0, 300, 300)); + imageInit = robot.createScreenCapture(new Rectangle(locx, locy, frw, frh)); SwingUtilities.invokeAndWait(new Runnable() { @@ -147,7 +161,7 @@ public void run() { }); robot.waitForIdle(500); - imageShow = robot.createScreenCapture(new Rectangle(0, 0, 300, 300)); + imageShow = robot.createScreenCapture(new Rectangle(locx, locy, frw, frh)); SwingUtilities.invokeAndWait(new Runnable() { @@ -158,13 +172,17 @@ public void run() { }); if (Util.compareBufferedImages(imageInit, imageShow)) { + ImageIO.write(imageInit, "png", new File("imageInit.png")); + ImageIO.write(imageShow, "png", new File("imageShow.png")); throw new Exception("Failed to show non-opaque button"); } robot.waitForIdle(500); - imageHide = robot.createScreenCapture(new Rectangle(0, 0, 300, 300)); + imageHide = robot.createScreenCapture(new Rectangle(locx, locy, frw, frh)); if (!Util.compareBufferedImages(imageInit, imageHide)) { + ImageIO.write(imageInit, "png", new File("imageInit.png")); + ImageIO.write(imageHide, "png", new File("imageHide.png")); throw new Exception("Failed to hide non-opaque button"); } } finally { diff --git a/test/jdk/javax/swing/JInternalFrame/6647340/bug6647340.java b/test/jdk/javax/swing/JInternalFrame/6647340/bug6647340.java index e277cc83e10..15972c504fa 100644 --- a/test/jdk/javax/swing/JInternalFrame/6647340/bug6647340.java +++ b/test/jdk/javax/swing/JInternalFrame/6647340/bug6647340.java @@ -26,9 +26,6 @@ * @bug 6647340 * @summary Checks that iconified internal frame follows * the main frame borders properly. - * @author Mikhail Lapshin - * @library /lib/client/ - * @build ExtendedRobot * @run main bug6647340 */ @@ -38,22 +35,22 @@ public class bug6647340 { private JFrame frame; - private Point location; + private volatile Point location; + private volatile Point iconloc; private JInternalFrame jif; - private static ExtendedRobot robot = createRobot(); + private static Robot robot; public static void main(String[] args) throws Exception { + robot = new Robot(); final bug6647340 test = new bug6647340(); try { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - test.setupUI(); - } - }); + SwingUtilities.invokeAndWait(() -> test.setupUI()); + robot.waitForIdle(); + robot.delay(1000); test.test(); } finally { if (test.frame != null) { - test.frame.dispose(); + SwingUtilities.invokeAndWait(() -> test.frame.dispose()); } } } @@ -77,77 +74,69 @@ private void setupUI() { } private void test() throws Exception { - sync(); test1(); - sync(); + + robot.waitForIdle(); + robot.delay(500); check1(); - sync(); + robot.waitForIdle(); + test2(); - sync(); + robot.waitForIdle(); + robot.delay(500); check2(); } private void test1() throws Exception { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - setIcon(true); - location = jif.getDesktopIcon().getLocation(); - Dimension size = frame.getSize(); - frame.setSize(size.width + 100, size.height + 100); - } + SwingUtilities.invokeAndWait(() -> { + setIcon(true); + location = jif.getDesktopIcon().getLocation(); + Dimension size = frame.getSize(); + frame.setSize(size.width + 100, size.height + 100); }); } private void test2() throws Exception { - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - setIcon(false); - } + SwingUtilities.invokeAndWait(() -> { + setIcon(false); }); - sync(); - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - Dimension size = frame.getSize(); - frame.setSize(size.width - 100, size.height - 100); - } + robot.waitForIdle(); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> { + Dimension size = frame.getSize(); + frame.setSize(size.width - 100, size.height - 100); }); - sync(); - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - setIcon(true); - } + robot.waitForIdle(); + robot.delay(500); + + SwingUtilities.invokeAndWait(() -> { + setIcon(true); }); } - private void check1() { - if (!jif.getDesktopIcon().getLocation().equals(location)) { + private void check1() throws Exception { + SwingUtilities.invokeAndWait(() -> { + iconloc = jif.getDesktopIcon().getLocation(); + }); + if (!iconloc.equals(location)) { System.out.println("First test passed"); } else { throw new RuntimeException("Icon isn't shifted with the frame bounds"); } } - private void check2() { - if (jif.getDesktopIcon().getLocation().equals(location)) { + private void check2() throws Exception { + SwingUtilities.invokeAndWait(() -> { + iconloc = jif.getDesktopIcon().getLocation(); + }); + if (iconloc.equals(location)) { System.out.println("Second test passed"); } else { throw new RuntimeException("Icon isn't located near the frame bottom"); } } - private static void sync() { - robot.waitForIdle(); - } - private static ExtendedRobot createRobot() { - try { - ExtendedRobot robot = new ExtendedRobot(); - return robot; - }catch(Exception ex) { - ex.printStackTrace(); - throw new Error("Unexpected Failure"); - } - } - private void setIcon(boolean b) { try { jif.setIcon(b); diff --git a/test/jdk/javax/swing/JMenu/PopupReferenceMemoryLeak.java b/test/jdk/javax/swing/JMenu/PopupReferenceMemoryLeak.java new file mode 100644 index 00000000000..ffc8c28f418 --- /dev/null +++ b/test/jdk/javax/swing/JMenu/PopupReferenceMemoryLeak.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 4907798 + * @key headful + * @summary Check for memory leak in menu subsystem + * @run main/othervm -Xmx8m PopupReferenceMemoryLeak + */ + +import javax.swing.AbstractAction; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import javax.swing.WindowConstants; +import java.awt.BorderLayout; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.lang.ref.WeakReference; +import java.util.ArrayList; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +public class PopupReferenceMemoryLeak { + static volatile WeakReference referenceToFrame1; + static JFrame frame1, frame2; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(200); + for (UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { + String lafName = laf.getName(); + System.out.println("Testing LaF: " + lafName); + if (lafName == null || lafName.startsWith("Mac OS X")) { + // Aqua Look and Feel uses system menus we can't really test it + continue; + } + setLookAndFeel(laf); + PopupReferenceMemoryLeak newTest = new PopupReferenceMemoryLeak(); + SwingUtilities.invokeAndWait(newTest::createUI); + try { + boolean passed = false; + robot.waitForIdle(); + Thread.sleep(2000); + robot.mouseMove(200, 200); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.keyPress(KeyEvent.VK_F10); + robot.keyRelease(KeyEvent.VK_F10); + robot.keyPress(KeyEvent.VK_F); + robot.keyRelease(KeyEvent.VK_F); + robot.keyPress(KeyEvent.VK_C); + robot.keyRelease(KeyEvent.VK_C); + robot.waitForIdle(); + Thread.sleep(2000); + robot.mouseMove(600, 200); + robot.waitForIdle(); + Thread.sleep(2000); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + // Workaround for Linux issues when sometimes there + // is a ref to last opened frame from native code + JFrame frame3 = new JFrame("Workaround"); + frame3.setSize(100, 100); + frame3.setLocation(0,0); + frame3.setVisible(true); + Thread.sleep(1000); + frame3.setVisible(false); + frame3.dispose(); + + // Force GC three times to see if it clears the old frame + for (int i = 0; i < 3; i++) { + try { + ArrayList gc = new ArrayList(); + while (true) { + gc.add(new int[100000]); + } + } catch (Throwable ignore) { + } + robot.waitForIdle(); + Thread.sleep(1000); + if (referenceToFrame1.get() == null) { + // Frame was released + passed = true; + break; + } + } + if (!passed) { + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_F10); + robot.keyRelease(KeyEvent.VK_F10); + robot.keyPress(KeyEvent.VK_T); + robot.keyRelease(KeyEvent.VK_T); + robot.keyPress(KeyEvent.VK_M); + robot.keyRelease(KeyEvent.VK_M); + robot.waitForIdle(); + Thread.sleep(2000); + for (int i = 0; i < 5; i++) { + try { + ArrayList gc = new ArrayList(); + while (true) { + gc.add(new int[100000]); + } + } catch (Throwable ignore) { + } + robot.waitForIdle(); + Thread.sleep(1000); + if (referenceToFrame1.get() == null) { + // Frame was released + throw new RuntimeException("Frame cleared only after menu activated on frame2"); + } + } + throw new RuntimeException("Test finished but menu has not cleared the reference!"); + } + } catch (Exception re) { + throw new RuntimeException(re.getLocalizedMessage()); + } finally { + if (frame2 != null) { + frame2.setVisible(false); + frame2.dispose(); + } + } + } + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported LookAndFeel: " + laf.getClassName()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + + public void createUI() { + frame1 = new JFrame("Main test window"); + JMenuBar menuBar1 = new JMenuBar(); + JMenu file1 = new JMenu("File"); + file1.setMnemonic('f'); + JMenuItem close1 = new JMenuItem("Close"); + close1.setMnemonic('c'); + close1.addActionListener(new FrameCloser(frame1)); + file1.add(close1); + menuBar1.add(file1); + frame1.setJMenuBar(menuBar1); + frame1.setSize(200, 200); + frame1.setLocation(100, 100); + frame1.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); + frame1.setVisible(true); + referenceToFrame1 = new WeakReference(frame1); + frame1 = null; + + frame2 = new JFrame("Secondary"); + JMenuBar menuBar2 = new JMenuBar(); + JMenu test = new JMenu("Test"); + test.setMnemonic('T'); + JMenuItem memoryTest = new JMenuItem("Memory"); + memoryTest.setMnemonic('M'); + test.add(memoryTest); + menuBar2.add(test); + frame2.setJMenuBar(menuBar2); + frame2.setLayout(new BorderLayout()); + frame2.setSize(200, 200); + frame2.setLocation(500, 100); + frame2.setVisible(true); + } + + class FrameCloser extends AbstractAction { + JFrame frame; + public FrameCloser(JFrame f) { + this.frame = f; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (frame != null) { + frame.setVisible(false); + frame.dispose(); + this.frame = null; + } + } + } +} diff --git a/test/jdk/javax/swing/JTextArea/8149849/DNDTextToScaledArea.java b/test/jdk/javax/swing/JTextArea/8149849/DNDTextToScaledArea.java index a68a11c5303..f0c4234b10e 100644 --- a/test/jdk/javax/swing/JTextArea/8149849/DNDTextToScaledArea.java +++ b/test/jdk/javax/swing/JTextArea/8149849/DNDTextToScaledArea.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,7 +24,10 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; import java.awt.Point; +import java.awt.Rectangle; import java.awt.Robot; import java.awt.event.InputEvent; import javax.swing.JFrame; @@ -35,13 +38,15 @@ /** * @test * @key headful - * @bug 8149849 + * @bug 8149849 8211999 * @summary [hidpi] DnD issues (cannot DnD from JFileChooser to JEditorPane or * other text component) when scale > 1 + * @run main/othervm DNDTextToScaledArea * @run main/othervm -Dsun.java2d.uiScale=2 DNDTextToScaledArea */ public class DNDTextToScaledArea { + private static final int SIZE = 300; private static final String TEXT = "ABCDEFGH"; private static JFrame frame; private static JTextArea srcTextArea; @@ -51,10 +56,17 @@ public class DNDTextToScaledArea { private static volatile boolean passed = false; public static void main(String[] args) throws Exception { + var lge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + for (GraphicsDevice device : lge.getScreenDevices()) { + test(device); + } + } + + private static void test(GraphicsDevice device) throws Exception { Robot robot = new Robot(); - robot.setAutoDelay(50); + robot.setAutoDelay(150); - SwingUtilities.invokeAndWait(DNDTextToScaledArea::createAndShowGUI); + SwingUtilities.invokeAndWait(() -> createAndShowGUI(device)); robot.waitForIdle(); SwingUtilities.invokeAndWait(() -> { @@ -62,6 +74,11 @@ public static void main(String[] args) throws Exception { dstPoint = getPoint(dstTextArea, 0.75); }); robot.waitForIdle(); + // check the destination + robot.mouseMove(dstPoint.x, dstPoint.y); + robot.mousePress(InputEvent.BUTTON1_MASK); + robot.mouseRelease(InputEvent.BUTTON1_MASK); + robot.waitForIdle(); dragAndDrop(robot, srcPoint, dstPoint); robot.waitForIdle(); @@ -77,11 +94,12 @@ public static void main(String[] args) throws Exception { } } - private static void createAndShowGUI() { - - frame = new JFrame(); - frame.setSize(300, 300); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + private static void createAndShowGUI(GraphicsDevice device) { + frame = new JFrame(device.getDefaultConfiguration()); + Rectangle screen = device.getDefaultConfiguration().getBounds(); + int x = (int) (screen.getCenterX() - SIZE / 2); + int y = (int) (screen.getCenterY() - SIZE / 2); + frame.setBounds(x, y, SIZE, SIZE); JPanel panel = new JPanel(new BorderLayout()); diff --git a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/dialog/DialogDemo.java b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/dialog/DialogDemo.java index 4ff166cfd65..9a8b92c1e9c 100644 --- a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/dialog/DialogDemo.java +++ b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/dialog/DialogDemo.java @@ -154,6 +154,7 @@ public void run() { frame.add(demo); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); + frame.setLocationRelativeTo(null); frame.setVisible(true); demo.start(); } diff --git a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/frame/FrameDemo.java b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/frame/FrameDemo.java index 518ef207a10..9f86dc2ad54 100644 --- a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/frame/FrameDemo.java +++ b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/frame/FrameDemo.java @@ -264,6 +264,7 @@ public void run() { frame.add(demo); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); +frame.setLocationRelativeTo(null); frame.setVisible(true); demo.start(); } diff --git a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/table/TableDemo.java b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/table/TableDemo.java index 86deeac7974..a2a26cc9bd3 100644 --- a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/table/TableDemo.java +++ b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/table/TableDemo.java @@ -615,6 +615,7 @@ public void run() { TableDemo demo = new TableDemo(); frame.add(demo); frame.setSize(700, 400); + frame.setLocationRelativeTo(null); frame.setVisible(true); demo.start(); } diff --git a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java index bbb06a1182a..5aefeed90c0 100644 --- a/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java +++ b/test/jdk/sanity/client/lib/SwingSet3/src/com/sun/swingset3/demos/window/WindowDemo.java @@ -152,6 +152,7 @@ public static void main(String args[]) throws InterruptedException, InvocationTa WindowDemo demo = new WindowDemo(); frame.add(demo); frame.pack(); + frame.setLocationRelativeTo(null); frame.setVisible(true); demo.start(); }); diff --git a/test/jdk/sun/awt/shell/FileSystemViewMemoryLeak.java b/test/jdk/sun/awt/shell/FileSystemViewMemoryLeak.java index a0f8407f184..96b5cd360b4 100644 --- a/test/jdk/sun/awt/shell/FileSystemViewMemoryLeak.java +++ b/test/jdk/sun/awt/shell/FileSystemViewMemoryLeak.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,10 +27,12 @@ * @summary FileSystemView.isDrive(File) memory leak on "C:\" file reference * @modules java.desktop/sun.awt.shell * @requires (os.family == "windows") - * @run main/othervm -Xmx8m FileSystemViewMemoryLeak + * @run main/othervm/timeout=320 -Xmx8m FileSystemViewMemoryLeak */ import java.io.File; import java.text.NumberFormat; +import java.util.concurrent.TimeUnit; + import javax.swing.filechooser.FileSystemView; public class FileSystemViewMemoryLeak { @@ -39,6 +41,9 @@ public static void main(String[] args) { test(); } + // Will run the test no more than 300 seconds + static long endtime = System.nanoTime() + TimeUnit.SECONDS.toNanos(300); + private static void test() { File root = new File("C:\\"); @@ -52,6 +57,10 @@ private static void test() { int iMax = 50000; long lastPercentFinished = 0L; for (int i = 0; i < iMax; i++) { + if (isComplete()) { + System.out.println("Time is over"); + return; + } long percentFinished = Math.round(((i * 1000d) / (double) iMax)); @@ -77,5 +86,9 @@ private static void test() { boolean drive = fileSystemView.isDrive(root); } } + + private static boolean isComplete() { + return endtime - System.nanoTime() < 0; + } } diff --git a/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java b/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java index 67520f27989..c63ac004be3 100644 --- a/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java +++ b/test/jdk/sun/nio/ch/TestMaxCachedBufferSize.java @@ -54,7 +54,7 @@ * @key randomness */ public class TestMaxCachedBufferSize { - private static final int DEFAULT_ITERS = 10 * 1000; + private static final int DEFAULT_ITERS = 5 * 1000; private static final int DEFAULT_THREAD_NUM = 4; private static final int SMALL_BUFFER_MIN_SIZE = 4 * 1024; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java index bf532274381..53d73412156 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/Executor.java @@ -52,6 +52,7 @@ public static Executor of(String... cmdline) { public Executor() { saveOutputType = new HashSet<>(Set.of(SaveOutputType.NONE)); + removePath = false; } public Executor setExecutable(String v) { @@ -83,6 +84,11 @@ public Executor setExecutable(JavaTool v) { return setExecutable(v.getPath()); } + public Executor setRemovePath(boolean value) { + removePath = value; + return this; + } + /** * Configures this instance to save full output that command will produce. * This function is mutual exclusive with @@ -289,6 +295,11 @@ private Result runExecutable() throws IOException, InterruptedException { builder.directory(directory.toFile()); sb.append(String.format("; in directory [%s]", directory)); } + if (removePath) { + // run this with cleared Path in Environment + TKit.trace("Clearing PATH in environment"); + builder.environment().remove("PATH"); + } trace("Execute " + sb.toString() + "..."); Process process = builder.start(); @@ -414,6 +425,7 @@ private static void trace(String msg) { private Path executable; private Set saveOutputType; private Path directory; + private boolean removePath; private static enum SaveOutputType { NONE, FULL, FIRST_LINE, DUMP diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java index 745922d4111..c7f0bf1cfa3 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/HelloApp.java @@ -34,10 +34,14 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Predicate; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import jdk.jpackage.test.Functional.ThrowingConsumer; import jdk.jpackage.test.Functional.ThrowingFunction; import jdk.jpackage.test.Functional.ThrowingSupplier; @@ -225,7 +229,7 @@ static void verifyOutputFile(Path outputFile, List args, public static Path createBundle(JavaAppDesc appDesc, Path outputDir) { String jmodFileName = appDesc.jmodFileName(); if (jmodFileName != null) { - final Path jmodFilePath = outputDir.resolve(jmodFileName); + final Path jmodPath = outputDir.resolve(jmodFileName); TKit.withTempDirectory("jmod-workdir", jmodWorkDir -> { var jarAppDesc = JavaAppDesc.parse(appDesc.toString()) .setBundleFileName("tmp.jar"); @@ -233,8 +237,7 @@ public static Path createBundle(JavaAppDesc appDesc, Path outputDir) { Executor exec = new Executor() .setToolProvider(JavaTool.JMOD) .addArguments("create", "--class-path") - .addArgument(jarPath) - .addArgument(jmodFilePath); + .addArgument(jarPath); if (appDesc.isWithMainClass()) { exec.addArguments("--main-class", appDesc.className()); @@ -244,11 +247,50 @@ public static Path createBundle(JavaAppDesc appDesc, Path outputDir) { exec.addArguments("--module-version", appDesc.moduleVersion()); } - Files.createDirectories(jmodFilePath.getParent()); + final Path jmodFilePath; + if (appDesc.isExplodedModule()) { + jmodFilePath = jmodWorkDir.resolve("tmp.jmod"); + exec.addArgument(jmodFilePath); + TKit.deleteDirectoryRecursive(jmodPath); + } else { + jmodFilePath = jmodPath; + exec.addArgument(jmodFilePath); + TKit.deleteIfExists(jmodPath); + } + + Files.createDirectories(jmodPath.getParent()); exec.execute(); + + if (appDesc.isExplodedModule()) { + TKit.trace(String.format("Explode [%s] module file...", + jmodFilePath.toAbsolutePath().normalize())); + // Explode contents of the root `classes` directory of + // temporary .jmod file + final Path jmodRootDir = Path.of("classes"); + try (var archive = new ZipFile(jmodFilePath.toFile())) { + archive.stream() + .filter(Predicate.not(ZipEntry::isDirectory)) + .sequential().forEachOrdered(ThrowingConsumer.toConsumer( + entry -> { + try (var in = archive.getInputStream(entry)) { + Path entryName = Path.of(entry.getName()); + if (entryName.startsWith(jmodRootDir)) { + entryName = jmodRootDir.relativize(entryName); + } + final Path fileName = jmodPath.resolve(entryName); + TKit.trace(String.format( + "Save [%s] zip entry in [%s] file...", + entry.getName(), + fileName.toAbsolutePath().normalize())); + Files.createDirectories(fileName.getParent()); + Files.copy(in, fileName); + } + })); + } + } }); - return jmodFilePath; + return jmodPath; } final JavaAppDesc jarAppDesc; @@ -273,14 +315,15 @@ public static void executeLauncherAndVerifyOutput(JPackageCommand cmd, String... args) { AppOutputVerifier av = getVerifier(cmd, args); if (av != null) { - av.executeAndVerifyOutput(args); + // when running app launchers, clear users environment + av.executeAndVerifyOutput(true, args); } } public static Executor.Result executeLauncher(JPackageCommand cmd, String... args) { AppOutputVerifier av = getVerifier(cmd, args); - return av.executeOnly(args); + return av.executeOnly(true, args); } private static AppOutputVerifier getVerifier(JPackageCommand cmd, @@ -351,7 +394,11 @@ public AppOutputVerifier addJavaOptions(Collection v) { } public void executeAndVerifyOutput(String... args) { - getExecutor(args).dumpOutput().execute(); + executeAndVerifyOutput(false, args); + } + + public void executeAndVerifyOutput(boolean removePath, String... args) { + getExecutor(args).dumpOutput().setRemovePath(removePath).execute(); final List launcherArgs = List.of(args); final List appArgs; @@ -365,8 +412,11 @@ public void executeAndVerifyOutput(String... args) { verifyOutputFile(outputFile, appArgs, params); } - public Executor.Result executeOnly(String...args) { - return getExecutor(args).saveOutput().executeWithoutExitCodeCheck(); + public Executor.Result executeOnly(boolean removePath, String...args) { + return getExecutor(args) + .saveOutput() + .setRemovePath(removePath) + .executeWithoutExitCodeCheck(); } private Executor getExecutor(String...args) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java index b9a2451c49f..a5db716faa9 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JavaAppDesc.java @@ -84,6 +84,10 @@ public String jarFileName() { } public String jmodFileName() { + if (isExplodedModule()) { + return bundleFileName; + } + if (bundleFileName != null && bundleFileName.endsWith(".jmod")) { return bundleFileName; } @@ -94,6 +98,10 @@ public boolean isWithBundleFileName() { return bundleFileName != null; } + public boolean isExplodedModule() { + return bundleFileName != null && bundleFileName.endsWith(".ejmod"); + } + public String moduleVersion() { return moduleVersion; } @@ -127,7 +135,7 @@ public String toString() { * Create Java application description form encoded string value. * * Syntax of encoded Java application description is - * [(jar_file|jmods_file):][module_name/]qualified_class_name[!][@module_version]. + * [(jar_file|jmods_file|exploded_jmods_file):][module_name/]qualified_class_name[!][@module_version]. * * E.g.: `duke.jar:com.other/com.other.foo.bar.Buz!@3.7` encodes modular * application. Module name is `com.other`. Main class is @@ -140,6 +148,12 @@ public String toString() { * `com.another.One`. Application will be * compiled and packed in `bar.jmod` jmod file. * + * E.g.: `bar.ejmod:com.another/com.another.One` encodes modular + * application. Module name is `com.another`. Main class is + * `com.another.One`. Application will be + * compiled and packed in temporary jmod file that will be exploded in + * `bar.ejmod` directory. + * * E.g.: `Ciao` encodes non-modular `Ciao` class in the default package. * jar command will not put main class attribute in the jar file. * Default name will be picked for jar file - `hello.jar`. diff --git a/test/jdk/tools/jpackage/share/RuntimeImageTest.java b/test/jdk/tools/jpackage/share/RuntimeImageTest.java new file mode 100644 index 00000000000..3d66a163c07 --- /dev/null +++ b/test/jdk/tools/jpackage/share/RuntimeImageTest.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import jdk.jpackage.test.TKit; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.PackageType; +import jdk.jpackage.test.Functional; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.Annotations.Parameter; +import jdk.jpackage.test.PackageTest; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.JavaTool; +import jdk.jpackage.test.Executor; + +/* + * @test + * @summary jpackage with --runtime-image + * @library ../helpers + * @key jpackagePlatformPackage + * @build jdk.jpackage.test.* + * @modules jdk.incubator.jpackage/jdk.incubator.jpackage.internal + * @compile RuntimeImageTest.java + * @run main/othervm/timeout=1400 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=RuntimeImageTest + */ + +public class RuntimeImageTest { + + @Test + @Parameter("0") + @Parameter("1") + @Parameter("2") + public static void test(String compression) throws Exception { + final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); + final Path jlinkOutputDir = workDir.resolve("temp.runtime"); + Files.createDirectories(jlinkOutputDir.getParent()); + + new Executor() + .setToolProvider(JavaTool.JLINK) + .dumpOutput() + .addArguments( + "--output", jlinkOutputDir.toString(), + "--compress=" + compression, + "--add-modules", "ALL-MODULE-PATH", + "--strip-debug", + "--no-header-files", + "--no-man-pages", + "--strip-native-commands") + .execute(); + + JPackageCommand cmd = JPackageCommand.helloAppImage() + .setArgumentValue("--runtime-image", jlinkOutputDir.toString()); + + cmd.executeAndAssertHelloAppImageCreated(); + } + +} diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java index c93c51ab24b..e8cd0028257 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/BasicTest.java @@ -226,6 +226,8 @@ public void testNoName() { @Parameter("com.other/com.other.Hello") // Modular app in .jmod file @Parameter("hello.jmod:com.other/com.other.Hello") + // Modular app in exploded .jmod file + @Parameter("hello.ejmod:com.other/com.other.Hello") public void testApp(String javaAppDesc) { JavaAppDesc appDesc = JavaAppDesc.parse(javaAppDesc); JPackageCommand cmd = JPackageCommand.helloAppImage(appDesc); diff --git a/test/langtools/jdk/jshell/HistoryUITest.java b/test/langtools/jdk/jshell/HistoryUITest.java index 307c087409b..04b8e825862 100644 --- a/test/langtools/jdk/jshell/HistoryUITest.java +++ b/test/langtools/jdk/jshell/HistoryUITest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8178077 + * @bug 8178077 8232856 * @summary Check the UI behavior of editing history. * @modules * jdk.compiler/com.sun.tools.javac.api @@ -77,4 +77,16 @@ public void testPrevNextSnippet() throws Exception { }); } + public void testReRun() throws Exception { + doRunTest((inputSink, out) -> { + inputSink.write("System.err.println(\"RAN\");\n"); + waitOutput(out, "RAN.*" + PROMPT); + inputSink.write("/!\n"); + waitOutput(out, "RAN.*" + PROMPT); + inputSink.write(UP); + inputSink.write("\n"); + waitOutput(out, "RAN.*" + PROMPT); + }); + } + } diff --git a/src/hotspot/share/adlc/Test/i486.ad b/test/langtools/tools/javac/T4881267-old.out similarity index 100% rename from src/hotspot/share/adlc/Test/i486.ad rename to test/langtools/tools/javac/T4881267-old.out diff --git a/test/langtools/tools/javac/T4881267.out b/test/langtools/tools/javac/T4881267.out index 01a732a612e..ad4e9c84b77 100644 --- a/test/langtools/tools/javac/T4881267.out +++ b/test/langtools/tools/javac/T4881267.out @@ -1,2 +1,2 @@ -T4881267.java:10:34: compiler.err.illegal.generic.type.for.instof +T4881267.java:10:21: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, T 1 error diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java index 9b33abaeabf..bfeac8f8f55 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/classfile/CombinationsTargetTest2.java @@ -399,14 +399,14 @@ String sourceString(String testname, String retentn, String annot2, case src7p: // (repeating) type annotations in use of instanceof with type test pattern /* * class Test10{ - * String data = "test"; + * Object data = "test"; * boolean dataIsString = ( data instanceof @A @B @A @B String str); * } */ source = new String( source + "// " + src.description + "\n" + "class "+ testname + "{\n" + - " String data = \"test\";\n" + + " Object data = \"test\";\n" + " boolean dataIsString = ( data instanceof _As_ _Bs_ String str && str.isEmpty());\n" + "}\n").concat(sourceBase).replace("_OTHER_", annot2).replace("_As_",As).replace("_Bs_",Bs) + "\n\n"; @@ -455,7 +455,7 @@ String sourceString(String testname, String retentn, String annot2, source = new String( source + "// " + src.description + "\n" + "class "+ testname + "{\n" + - " String data = \"test\";\n" + + " Object data = \"test\";\n" + " Boolean isString() { \n" + " if( data instanceof _As_ _Bs_ String str)\n" + " return true;\n" + diff --git a/test/langtools/tools/javac/diags/examples/ReifiableTypesInstanceof.java b/test/langtools/tools/javac/diags/examples/FeatureReifiableTypesInstanceof.java similarity index 74% rename from test/langtools/tools/javac/diags/examples/ReifiableTypesInstanceof.java rename to test/langtools/tools/javac/diags/examples/FeatureReifiableTypesInstanceof.java index 295b3dc3279..6304c890334 100644 --- a/test/langtools/tools/javac/diags/examples/ReifiableTypesInstanceof.java +++ b/test/langtools/tools/javac/diags/examples/FeatureReifiableTypesInstanceof.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,14 +21,13 @@ * questions. */ +// key: compiler.err.feature.not.supported.in.source.plural // key: compiler.misc.feature.reifiable.types.instanceof -// key: compiler.warn.preview.feature.use.plural -// options: --enable-preview -source ${jdk.version} -Xlint:preview +// options: -source 15 -Xlint:-options -class PatternMatchingInstanceof { - boolean m(I i) { - return i instanceof C; - } - interface I {} - class C implements I {} +import java.util.*; + +class FeatureReifiableTypesInstanceof { + List o; + boolean b = (o instanceof List); } diff --git a/test/langtools/tools/javac/diags/examples/InvalidInstanceof.java b/test/langtools/tools/javac/diags/examples/InstanceofPatternNoSubtype.java similarity index 81% rename from test/langtools/tools/javac/diags/examples/InvalidInstanceof.java rename to test/langtools/tools/javac/diags/examples/InstanceofPatternNoSubtype.java index 311af828743..afd4cc92634 100644 --- a/test/langtools/tools/javac/diags/examples/InvalidInstanceof.java +++ b/test/langtools/tools/javac/diags/examples/InstanceofPatternNoSubtype.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,11 +21,10 @@ * questions. */ -// key: compiler.err.illegal.generic.type.for.instof +// key: compiler.err.instanceof.pattern.no.subtype -import java.util.*; - -class IllegalInstanceof { - List o; - boolean b = (o instanceof List); +class InstanceofPatternNoSubtype { + boolean test(Object o) { + return o instanceof Object obj; + } } diff --git a/test/langtools/tools/javac/diags/examples/InstanceofReifiableNotSafe.java b/test/langtools/tools/javac/diags/examples/InstanceofReifiableNotSafe.java index f0c7fb3451f..28c8720aaac 100644 --- a/test/langtools/tools/javac/diags/examples/InstanceofReifiableNotSafe.java +++ b/test/langtools/tools/javac/diags/examples/InstanceofReifiableNotSafe.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,6 @@ */ // key: compiler.err.instanceof.reifiable.not.safe -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} import java.util.List; diff --git a/test/langtools/tools/javac/diags/examples/MatchBindingExists.java b/test/langtools/tools/javac/diags/examples/MatchBindingExists.java index 008db333645..03a5a9ecc87 100644 --- a/test/langtools/tools/javac/diags/examples/MatchBindingExists.java +++ b/test/langtools/tools/javac/diags/examples/MatchBindingExists.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,9 +22,6 @@ */ // key: compiler.err.match.binding.exists -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} class MatchBindingExists { public void test(Object o1, Object o2) { diff --git a/test/langtools/tools/javac/diags/examples/PatternMatchingInstanceof.java b/test/langtools/tools/javac/diags/examples/PatternMatchingInstanceof.java index 9c71e4e49ce..6c276721c2e 100644 --- a/test/langtools/tools/javac/diags/examples/PatternMatchingInstanceof.java +++ b/test/langtools/tools/javac/diags/examples/PatternMatchingInstanceof.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,8 +22,8 @@ */ // key: compiler.misc.feature.pattern.matching.instanceof -// key: compiler.warn.preview.feature.use -// options: --enable-preview -source ${jdk.version} -Xlint:preview +// key: compiler.err.feature.not.supported.in.source +// options: -source 15 -Xlint:-options class PatternMatchingInstanceof { boolean m(Object o) { diff --git a/test/langtools/tools/javac/generics/InstanceOf2.out b/test/langtools/tools/javac/generics/InstanceOf2.out index b6a1886d6bf..5b1e599e81e 100644 --- a/test/langtools/tools/javac/generics/InstanceOf2.out +++ b/test/langtools/tools/javac/generics/InstanceOf2.out @@ -1,2 +1,2 @@ -InstanceOf2.java:12:48: compiler.err.illegal.generic.type.for.instof +InstanceOf2.java:12:29: compiler.err.instanceof.reifiable.not.safe: java.lang.Class, java.lang.Class 1 error diff --git a/test/langtools/tools/javac/generics/InstanceOf3.java b/test/langtools/tools/javac/generics/InstanceOf3.java index 8a3d327fbc1..f4f5529668e 100644 --- a/test/langtools/tools/javac/generics/InstanceOf3.java +++ b/test/langtools/tools/javac/generics/InstanceOf3.java @@ -4,7 +4,7 @@ * @summary the type in an instanceof expression must be reifiable * @author seligman * - * @compile/fail/ref=InstanceOf3.out -XDrawDiagnostics InstanceOf3.java + * @compile/fail/ref=InstanceOf3.out -XDrawDiagnostics -source 15 -Xlint:-options InstanceOf3.java */ public class InstanceOf3 { diff --git a/test/langtools/tools/javac/generics/InstanceOf3.out b/test/langtools/tools/javac/generics/InstanceOf3.out index a31cc15f569..1056423911b 100644 --- a/test/langtools/tools/javac/generics/InstanceOf3.out +++ b/test/langtools/tools/javac/generics/InstanceOf3.out @@ -1,2 +1,2 @@ -InstanceOf3.java:12:48: compiler.err.illegal.generic.type.for.instof +InstanceOf3.java:12:32: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.reifiable.types.instanceof), 15, 16 1 error diff --git a/test/langtools/tools/javac/generics/odersky/BadTest-old.out b/test/langtools/tools/javac/generics/odersky/BadTest-old.out new file mode 100644 index 00000000000..9a3385d0fb0 --- /dev/null +++ b/test/langtools/tools/javac/generics/odersky/BadTest-old.out @@ -0,0 +1,5 @@ +BadTest.java:19:50: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List>) +BadTest.java:23:48: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List) +BadTest.java:24:54: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List>) +BadTest.java:26:38: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.reifiable.types.instanceof), 15, 16 +4 errors diff --git a/test/langtools/tools/javac/generics/odersky/BadTest.java b/test/langtools/tools/javac/generics/odersky/BadTest.java index 3e97080c965..7ab521a2eb4 100644 --- a/test/langtools/tools/javac/generics/odersky/BadTest.java +++ b/test/langtools/tools/javac/generics/odersky/BadTest.java @@ -3,6 +3,7 @@ * @summary Negative regression test from odersky * @author odersky * + * @compile/fail/ref=BadTest-old.out -XDrawDiagnostics -source 15 -Xlint:-options BadTest.java * @compile/fail/ref=BadTest.out -XDrawDiagnostics BadTest.java */ diff --git a/test/langtools/tools/javac/generics/odersky/BadTest.out b/test/langtools/tools/javac/generics/odersky/BadTest.out index bddfb232196..c70a7f81c4e 100644 --- a/test/langtools/tools/javac/generics/odersky/BadTest.out +++ b/test/langtools/tools/javac/generics/odersky/BadTest.out @@ -1,5 +1,5 @@ -BadTest.java:18:50: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List>) -BadTest.java:22:48: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List) -BadTest.java:23:54: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List>) -BadTest.java:25:53: compiler.err.illegal.generic.type.for.instof +BadTest.java:19:50: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List>) +BadTest.java:23:48: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List) +BadTest.java:24:54: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List>) +BadTest.java:26:35: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: List, List) 4 errors diff --git a/test/langtools/tools/javac/patterns/BindingsExistTest.java b/test/langtools/tools/javac/patterns/BindingsExistTest.java index 27aa66d409f..deca70f7344 100644 --- a/test/langtools/tools/javac/patterns/BindingsExistTest.java +++ b/test/langtools/tools/javac/patterns/BindingsExistTest.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8231827 * @summary Clashing bindings are reported correctly - * @compile/fail/ref=BindingsExistTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} BindingsExistTest.java + * @compile/fail/ref=BindingsExistTest.out -XDrawDiagnostics BindingsExistTest.java */ public class BindingsExistTest { public void t(Object o1, Object o2) { diff --git a/test/langtools/tools/javac/patterns/BindingsExistTest.out b/test/langtools/tools/javac/patterns/BindingsExistTest.out index 28ed647f5c5..fa7bff1476e 100644 --- a/test/langtools/tools/javac/patterns/BindingsExistTest.out +++ b/test/langtools/tools/javac/patterns/BindingsExistTest.out @@ -4,6 +4,4 @@ BindingsExistTest.java:16:35: compiler.err.already.defined: kindname.variable, k BindingsExistTest.java:19:34: compiler.err.already.defined: kindname.variable, s2, kindname.method, t(java.lang.Object,java.lang.Object) BindingsExistTest.java:22:20: compiler.err.already.defined: kindname.variable, s3, kindname.method, t(java.lang.Object,java.lang.Object) BindingsExistTest.java:28:16: compiler.err.already.defined: kindname.variable, s4, kindname.method, t(java.lang.Object,java.lang.Object) -- compiler.note.preview.filename: BindingsExistTest.java -- compiler.note.preview.recompile 6 errors diff --git a/test/langtools/tools/javac/patterns/BindingsTest1.java b/test/langtools/tools/javac/patterns/BindingsTest1.java index d34e5cd792c..018084a98e7 100644 --- a/test/langtools/tools/javac/patterns/BindingsTest1.java +++ b/test/langtools/tools/javac/patterns/BindingsTest1.java @@ -25,8 +25,8 @@ * @test * @bug 8231827 * @summary Basic tests for bindings from instanceof - * @compile --enable-preview -source ${jdk.version} BindingsTest1.java - * @run main/othervm --enable-preview BindingsTest1 + * @compile BindingsTest1.java + * @run main BindingsTest1 */ public class BindingsTest1 { diff --git a/test/langtools/tools/javac/patterns/BindingsTest1Merging.java b/test/langtools/tools/javac/patterns/BindingsTest1Merging.java index 5458a1dee80..f6e1f6dd201 100644 --- a/test/langtools/tools/javac/patterns/BindingsTest1Merging.java +++ b/test/langtools/tools/javac/patterns/BindingsTest1Merging.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8231827 * @summary Basic tests for bindings from instanceof - tests for merging pattern variables - * @compile/fail/ref=BindingsTest1Merging.out -XDrawDiagnostics --enable-preview -source ${jdk.version} BindingsTest1Merging.java + * @compile/fail/ref=BindingsTest1Merging.out -XDrawDiagnostics BindingsTest1Merging.java */ public class BindingsTest1Merging { diff --git a/test/langtools/tools/javac/patterns/BindingsTest1Merging.out b/test/langtools/tools/javac/patterns/BindingsTest1Merging.out index 77f01a12367..28374ebc04f 100644 --- a/test/langtools/tools/javac/patterns/BindingsTest1Merging.out +++ b/test/langtools/tools/javac/patterns/BindingsTest1Merging.out @@ -7,6 +7,4 @@ BindingsTest1Merging.java:44:21: compiler.err.match.binding.exists BindingsTest1Merging.java:50:36: compiler.err.match.binding.exists BindingsTest1Merging.java:56:39: compiler.err.match.binding.exists BindingsTest1Merging.java:62:42: compiler.err.match.binding.exists -- compiler.note.preview.filename: BindingsTest1Merging.java -- compiler.note.preview.recompile 9 errors diff --git a/test/langtools/tools/javac/patterns/BindingsTest2.java b/test/langtools/tools/javac/patterns/BindingsTest2.java index be0af3458a9..4bbd5f3f532 100644 --- a/test/langtools/tools/javac/patterns/BindingsTest2.java +++ b/test/langtools/tools/javac/patterns/BindingsTest2.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8231827 * @summary Ensure that scopes arising from conditionalExpressions are handled corrected. - * @compile/fail/ref=BindingsTest2.out -XDrawDiagnostics -XDshould-stop.at=FLOW --enable-preview -source ${jdk.version} BindingsTest2.java + * @compile/fail/ref=BindingsTest2.out -XDrawDiagnostics -XDshould-stop.at=FLOW BindingsTest2.java */ public class BindingsTest2 { public static boolean Ktrue() { return true; } diff --git a/test/langtools/tools/javac/patterns/BindingsTest2.out b/test/langtools/tools/javac/patterns/BindingsTest2.out index c9c179e1f97..e52e9db2342 100644 --- a/test/langtools/tools/javac/patterns/BindingsTest2.out +++ b/test/langtools/tools/javac/patterns/BindingsTest2.out @@ -49,6 +49,4 @@ BindingsTest2.java:241:17: compiler.err.cant.resolve.location: kindname.variable BindingsTest2.java:135:17: compiler.err.unreachable.stmt BindingsTest2.java:160:17: compiler.err.unreachable.stmt BindingsTest2.java:185:17: compiler.err.unreachable.stmt -- compiler.note.preview.filename: BindingsTest2.java -- compiler.note.preview.recompile 51 errors \ No newline at end of file diff --git a/test/langtools/tools/javac/patterns/BreakAndLoops.java b/test/langtools/tools/javac/patterns/BreakAndLoops.java index 01d3bb70540..3d43fb504b2 100644 --- a/test/langtools/tools/javac/patterns/BreakAndLoops.java +++ b/test/langtools/tools/javac/patterns/BreakAndLoops.java @@ -95,10 +95,7 @@ protected void doWork() throws Throwable { case "NESTED" -> brk; case "BODY" -> innerLabel; default -> throw new UnsupportedOperationException(pname); - }) - .withOption("--enable-preview") - .withOption("-source") - .withOption(String.valueOf(Runtime.version().feature())); + }); task.generate(result -> { boolean shouldPass; diff --git a/test/langtools/tools/javac/patterns/CastConversionMatch.java b/test/langtools/tools/javac/patterns/CastConversionMatch.java index 0878d7c6c73..1300bf09d16 100644 --- a/test/langtools/tools/javac/patterns/CastConversionMatch.java +++ b/test/langtools/tools/javac/patterns/CastConversionMatch.java @@ -2,7 +2,7 @@ * @test /nodynamicopyright/ * @bug 8231827 * @summary Match which involves a cast conversion - * @compile/fail/ref=CastConversionMatch.out -XDrawDiagnostics --enable-preview -source ${jdk.version} CastConversionMatch.java + * @compile/fail/ref=CastConversionMatch.out -XDrawDiagnostics CastConversionMatch.java */ public class CastConversionMatch { diff --git a/test/langtools/tools/javac/patterns/CastConversionMatch.out b/test/langtools/tools/javac/patterns/CastConversionMatch.out index 528ef8e817a..8f747810aff 100644 --- a/test/langtools/tools/javac/patterns/CastConversionMatch.out +++ b/test/langtools/tools/javac/patterns/CastConversionMatch.out @@ -1,4 +1,2 @@ CastConversionMatch.java:11:26: compiler.err.type.found.req: int, (compiler.misc.type.req.class.array) -- compiler.note.preview.filename: CastConversionMatch.java -- compiler.note.preview.recompile 1 error diff --git a/test/langtools/tools/javac/patterns/ConditionalTest.java b/test/langtools/tools/javac/patterns/ConditionalTest.java index 828fabfb828..16f2ceb0084 100644 --- a/test/langtools/tools/javac/patterns/ConditionalTest.java +++ b/test/langtools/tools/javac/patterns/ConditionalTest.java @@ -85,10 +85,7 @@ protected void doWork() throws Throwable { case "TRUE" -> trueSec; case "FALSE" -> falseSec; default -> throw new UnsupportedOperationException(pname); - }) - .withOption("--enable-preview") - .withOption("-source") - .withOption(String.valueOf(Runtime.version().feature())); + }); task.analyze(result -> { boolean shouldPass; diff --git a/test/langtools/tools/javac/patterns/DuplicateBindingTest.java b/test/langtools/tools/javac/patterns/DuplicateBindingTest.java index 2f9afff625c..e6112fd1bb4 100644 --- a/test/langtools/tools/javac/patterns/DuplicateBindingTest.java +++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8231827 * @summary Basic pattern bindings scope test - * @compile/fail/ref=DuplicateBindingTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} DuplicateBindingTest.java + * @compile/fail/ref=DuplicateBindingTest.out -XDrawDiagnostics DuplicateBindingTest.java */ public class DuplicateBindingTest { @@ -10,17 +10,17 @@ public class DuplicateBindingTest { int f; public static boolean main(String[] args) { + Object o1 = ""; + Object o2 = ""; if (args != null) { int s; - if (args[0] instanceof String s) { // NOT OK. Redef same scope. + if (o1 instanceof String s) { // NOT OK. Redef same scope. } - if (args[0] instanceof String f) { // OK to redef field. + if (o1 instanceof String f) { // OK to redef field. } } - Object o1 = ""; - Object o2 = ""; if (o1 instanceof String s && o2 instanceof String s) {} //error - already in scope on RHS (in scope due to LHS when true) if (o1 instanceof String s && !(o2 instanceof String s)) {} //error - already in scope on RHS (in scope due to LHS when true) diff --git a/test/langtools/tools/javac/patterns/DuplicateBindingTest.out b/test/langtools/tools/javac/patterns/DuplicateBindingTest.out index 1d41169eb15..cb0d37d9b28 100644 --- a/test/langtools/tools/javac/patterns/DuplicateBindingTest.out +++ b/test/langtools/tools/javac/patterns/DuplicateBindingTest.out @@ -1,4 +1,4 @@ -DuplicateBindingTest.java:16:43: compiler.err.already.defined: kindname.variable, s, kindname.method, main(java.lang.String[]) +DuplicateBindingTest.java:18:38: compiler.err.already.defined: kindname.variable, s, kindname.method, main(java.lang.String[]) DuplicateBindingTest.java:25:60: compiler.err.match.binding.exists DuplicateBindingTest.java:26:62: compiler.err.match.binding.exists DuplicateBindingTest.java:27:39: compiler.err.match.binding.exists @@ -22,6 +22,4 @@ DuplicateBindingTest.java:50:102: compiler.err.match.binding.exists DuplicateBindingTest.java:51:73: compiler.err.match.binding.exists DuplicateBindingTest.java:54:69: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, DuplicateBindingTest, null) DuplicateBindingTest.java:55:44: compiler.err.cant.resolve.location: kindname.variable, s, , , (compiler.misc.location: kindname.class, DuplicateBindingTest, null) -- compiler.note.preview.filename: DuplicateBindingTest.java -- compiler.note.preview.recompile 24 errors diff --git a/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.java b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.java index 14d56b416d4..5c18fd750ca 100644 --- a/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.java +++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8187420 8231827 * @summary Error message mentions relevant types transposed - * @compile/fail/ref=EnsureTypesOrderTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} EnsureTypesOrderTest.java + * @compile/fail/ref=EnsureTypesOrderTest.out -XDrawDiagnostics EnsureTypesOrderTest.java */ public class EnsureTypesOrderTest { public static void main(String [] args) { diff --git a/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.out b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.out index ca05e4638dc..5047b38fe1a 100644 --- a/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.out +++ b/test/langtools/tools/javac/patterns/EnsureTypesOrderTest.out @@ -1,4 +1,2 @@ EnsureTypesOrderTest.java:9:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.String[], java.lang.String) -- compiler.note.preview.filename: EnsureTypesOrderTest.java -- compiler.note.preview.recompile 1 error \ No newline at end of file diff --git a/test/langtools/tools/javac/patterns/ExamplesFromProposal.java b/test/langtools/tools/javac/patterns/ExamplesFromProposal.java index 3612c7e618a..2d1fdf29113 100644 --- a/test/langtools/tools/javac/patterns/ExamplesFromProposal.java +++ b/test/langtools/tools/javac/patterns/ExamplesFromProposal.java @@ -25,8 +25,8 @@ * @test * @bug 8231827 * @summary All example code from "Pattern Matching for Java" document, released April 2017, adjusted to current state (no switches, etc) - * @compile --enable-preview -source ${jdk.version} ExamplesFromProposal.java - * @run main/othervm --enable-preview ExamplesFromProposal + * @compile ExamplesFromProposal.java + * @run main ExamplesFromProposal */ interface Node { diff --git a/test/langtools/tools/javac/patterns/ImpossibleTypeTest.java b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.java index 0e564869362..2c4ba47adeb 100644 --- a/test/langtools/tools/javac/patterns/ImpossibleTypeTest.java +++ b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8231827 * @summary Ensure that in type test patterns, the predicate is not trivially provable false. - * @compile/fail/ref=ImpossibleTypeTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} ImpossibleTypeTest.java + * @compile/fail/ref=ImpossibleTypeTest.out -XDrawDiagnostics ImpossibleTypeTest.java */ public class ImpossibleTypeTest { diff --git a/test/langtools/tools/javac/patterns/ImpossibleTypeTest.out b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.out index 6003b006d91..78331a727dd 100644 --- a/test/langtools/tools/javac/patterns/ImpossibleTypeTest.out +++ b/test/langtools/tools/javac/patterns/ImpossibleTypeTest.out @@ -1,5 +1,3 @@ ImpossibleTypeTest.java:14:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: java.lang.Integer, java.lang.String) ImpossibleTypeTest.java:17:26: compiler.err.cant.resolve.location: kindname.class, Undefined, , , (compiler.misc.location: kindname.class, ImpossibleTypeTest, null) -- compiler.note.preview.filename: ImpossibleTypeTest.java -- compiler.note.preview.recompile 2 errors diff --git a/test/langtools/tools/javac/patterns/LocalVariableTable.java b/test/langtools/tools/javac/patterns/LocalVariableTable.java index ac4bb0cc27a..ee03b16b927 100644 --- a/test/langtools/tools/javac/patterns/LocalVariableTable.java +++ b/test/langtools/tools/javac/patterns/LocalVariableTable.java @@ -26,8 +26,8 @@ * @bug 8231827 * @summary Ensure the LV table entries are generated for bindings * @modules jdk.jdeps/com.sun.tools.classfile - * @compile -g --enable-preview -source ${jdk.version} LocalVariableTable.java - * @run main/othervm --enable-preview LocalVariableTable + * @compile -g LocalVariableTable.java + * @run main LocalVariableTable */ import java.io.*; diff --git a/test/langtools/tools/javac/patterns/MatchBindingScopeTest.java b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.java index 50fbf0a7bfc..2e32428a67d 100644 --- a/test/langtools/tools/javac/patterns/MatchBindingScopeTest.java +++ b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8231827 * @summary Basic pattern bindings scope test - * @compile/fail/ref=MatchBindingScopeTest.out -XDrawDiagnostics --enable-preview -source ${jdk.version} MatchBindingScopeTest.java + * @compile/fail/ref=MatchBindingScopeTest.out -XDrawDiagnostics MatchBindingScopeTest.java */ public class MatchBindingScopeTest { diff --git a/test/langtools/tools/javac/patterns/MatchBindingScopeTest.out b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.out index 6f21aca174e..f4424d36149 100644 --- a/test/langtools/tools/javac/patterns/MatchBindingScopeTest.out +++ b/test/langtools/tools/javac/patterns/MatchBindingScopeTest.out @@ -11,6 +11,4 @@ MatchBindingScopeTest.java:56:48: compiler.err.cant.resolve.location: kindname.v MatchBindingScopeTest.java:57:32: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null) MatchBindingScopeTest.java:62:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null) MatchBindingScopeTest.java:65:23: compiler.err.cant.resolve.location: kindname.variable, j, , , (compiler.misc.location: kindname.class, MatchBindingScopeTest, null) -- compiler.note.preview.filename: MatchBindingScopeTest.java -- compiler.note.preview.recompile 13 errors \ No newline at end of file diff --git a/test/langtools/tools/javac/patterns/NoSubtypeCheck.java b/test/langtools/tools/javac/patterns/NoSubtypeCheck.java new file mode 100644 index 00000000000..973ffb5a6ec --- /dev/null +++ b/test/langtools/tools/javac/patterns/NoSubtypeCheck.java @@ -0,0 +1,22 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8250625 + * @summary Verify pattern matching test which is always true produces an error + * @compile/fail/ref=NoSubtypeCheck.out -XDrawDiagnostics NoSubtypeCheck.java + */ +public class NoSubtypeCheck { + + public static void main(Object o, String s, List l) { + boolean b1 = o instanceof Object v1; + boolean b2 = o instanceof String v2; + boolean b3 = s instanceof Object v3; + boolean b4 = s instanceof String v4; + boolean b5 = l instanceof List v5; + boolean b6 = l instanceof List2 v6; + boolean b7 = undef instanceof String v7; + boolean b8 = o instanceof Undef v7; + } + + public interface List {} + public interface List2 extends List {} +} diff --git a/test/langtools/tools/javac/patterns/NoSubtypeCheck.out b/test/langtools/tools/javac/patterns/NoSubtypeCheck.out new file mode 100644 index 00000000000..fc95883838a --- /dev/null +++ b/test/langtools/tools/javac/patterns/NoSubtypeCheck.out @@ -0,0 +1,7 @@ +NoSubtypeCheck.java:10:24: compiler.err.instanceof.pattern.no.subtype: java.lang.Object, java.lang.Object +NoSubtypeCheck.java:12:24: compiler.err.instanceof.pattern.no.subtype: java.lang.Object, java.lang.String +NoSubtypeCheck.java:13:24: compiler.err.instanceof.pattern.no.subtype: java.lang.String, java.lang.String +NoSubtypeCheck.java:14:24: compiler.err.instanceof.pattern.no.subtype: NoSubtypeCheck.List, NoSubtypeCheck.List +NoSubtypeCheck.java:16:22: compiler.err.cant.resolve.location: kindname.variable, undef, , , (compiler.misc.location: kindname.class, NoSubtypeCheck, null) +NoSubtypeCheck.java:17:35: compiler.err.cant.resolve.location: kindname.class, Undef, , , (compiler.misc.location: kindname.class, NoSubtypeCheck, null) +6 errors diff --git a/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java b/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java index 02527f7a84e..c58e42a8f5e 100644 --- a/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java +++ b/test/langtools/tools/javac/patterns/NoUnnecessaryCast.java @@ -27,8 +27,8 @@ * @summary Verify there are no unnecessary checkcasts and conditions generated * for the pattern matching in instanceof. * @modules jdk.jdeps/com.sun.tools.classfile - * @compile --enable-preview -source ${jdk.version} NoUnnecessaryCast.java - * @run main/othervm --enable-preview NoUnnecessaryCast + * @compile NoUnnecessaryCast.java + * @run main NoUnnecessaryCast */ import java.io.File; diff --git a/test/langtools/tools/javac/patterns/NullsInPatterns.java b/test/langtools/tools/javac/patterns/NullsInPatterns.java index 87f042c96bc..e9f6221d153 100644 --- a/test/langtools/tools/javac/patterns/NullsInPatterns.java +++ b/test/langtools/tools/javac/patterns/NullsInPatterns.java @@ -25,8 +25,7 @@ * @test * @bug 8231827 * @summary Testing pattern matching against the null constant - * @compile --enable-preview -source ${jdk.version} NullsInPatterns.java - * @run main/othervm --enable-preview NullsInPatterns + * @compile/fail/ref=NullsInPatterns.out -XDrawDiagnostics NullsInPatterns.java */ import java.util.List; diff --git a/test/langtools/tools/javac/patterns/NullsInPatterns.out b/test/langtools/tools/javac/patterns/NullsInPatterns.out new file mode 100644 index 00000000000..14b5e56f825 --- /dev/null +++ b/test/langtools/tools/javac/patterns/NullsInPatterns.out @@ -0,0 +1,3 @@ +NullsInPatterns.java:35:18: compiler.err.instanceof.pattern.no.subtype: java.util.List, compiler.misc.type.null +NullsInPatterns.java:46:18: compiler.err.instanceof.pattern.no.subtype: java.util.List, compiler.misc.type.null +2 errors diff --git a/test/langtools/tools/javac/patterns/PatternMatchPosTest.java b/test/langtools/tools/javac/patterns/PatternMatchPosTest.java index 9e532a69f79..4b20ffe948f 100644 --- a/test/langtools/tools/javac/patterns/PatternMatchPosTest.java +++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.java @@ -26,7 +26,7 @@ * @bug 8231827 * @summary Check proper positions. * @build PatternMatchPosTest - * @compile/ref=PatternMatchPosTest.out -processor PatternMatchPosTest -Xlint:unchecked -XDrawDiagnostics --enable-preview -source ${jdk.version} PatternMatchPosTestData.java + * @compile/ref=PatternMatchPosTest.out -processor PatternMatchPosTest -Xlint:unchecked -XDrawDiagnostics PatternMatchPosTestData.java */ import java.io.IOException; @@ -85,8 +85,10 @@ public Void scan(Tree tree, Void p) { if (print) { int start = (int) sp.getStartPosition(dataPath.getCompilationUnit(), tree); int end = (int) sp.getEndPosition(dataPath.getCompilationUnit(), tree); - processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, - text.substring(start, end)); + if (start != (-1) || end != (-1)) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, + text.substring(start, end)); + } } return super.scan(tree, p); } diff --git a/test/langtools/tools/javac/patterns/PatternMatchPosTest.out b/test/langtools/tools/javac/patterns/PatternMatchPosTest.out index 0d5d809ef1e..71eb6d7186d 100644 --- a/test/langtools/tools/javac/patterns/PatternMatchPosTest.out +++ b/test/langtools/tools/javac/patterns/PatternMatchPosTest.out @@ -2,13 +2,13 @@ - compiler.note.proc.messager: o instanceof String s - compiler.note.proc.messager: o - compiler.note.proc.messager: String s +- compiler.note.proc.messager: String s - compiler.note.proc.messager: String - compiler.note.proc.messager: (o instanceof java.lang.String s) - compiler.note.proc.messager: o instanceof java.lang.String s - compiler.note.proc.messager: o - compiler.note.proc.messager: java.lang.String s +- compiler.note.proc.messager: java.lang.String s - compiler.note.proc.messager: java.lang.String - compiler.note.proc.messager: java.lang -- compiler.note.proc.messager: java -- compiler.note.preview.filename: PatternMatchPosTestData.java -- compiler.note.preview.recompile +- compiler.note.proc.messager: java \ No newline at end of file diff --git a/test/langtools/tools/javac/patterns/PatternTypeTest2.java b/test/langtools/tools/javac/patterns/PatternTypeTest2.java index 736396db792..06c1fe6156c 100644 --- a/test/langtools/tools/javac/patterns/PatternTypeTest2.java +++ b/test/langtools/tools/javac/patterns/PatternTypeTest2.java @@ -25,8 +25,8 @@ * @test * @bug 8231827 * @summary Basic pattern test - * @compile --enable-preview -source ${jdk.version} PatternTypeTest2.java - * @run main/othervm --enable-preview PatternTypeTest2 + * @compile PatternTypeTest2.java + * @run main PatternTypeTest2 */ public class PatternTypeTest2 { diff --git a/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.java b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.java deleted file mode 100644 index e5c9f0ca422..00000000000 --- a/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * @test /nodynamiccopyright/ - * @bug 8231827 - * @summary Ensure that in type test patterns, the predicate is not trivially provable false. - * @compile/fail/ref=PatternVariablesAreFinal.out -XDrawDiagnostics --enable-preview -source ${jdk.version} PatternVariablesAreFinal.java - */ -public class PatternVariablesAreFinal { - public static void main(String[] args) { - Object o = 32; - if (o instanceof String s) { - s = "hello again"; - System.out.println(s); - } - System.out.println("test complete"); - } -} diff --git a/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.out b/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.out deleted file mode 100644 index bf266e311f3..00000000000 --- a/test/langtools/tools/javac/patterns/PatternVariablesAreFinal.out +++ /dev/null @@ -1,4 +0,0 @@ -PatternVariablesAreFinal.java:11:13: compiler.err.pattern.binding.may.not.be.assigned: s -- compiler.note.preview.filename: PatternVariablesAreFinal.java -- compiler.note.preview.recompile -1 error diff --git a/test/langtools/tools/javac/patterns/PatternVariablesAreNonFinal.java b/test/langtools/tools/javac/patterns/PatternVariablesAreNonFinal.java new file mode 100644 index 00000000000..6ee3adf30b8 --- /dev/null +++ b/test/langtools/tools/javac/patterns/PatternVariablesAreNonFinal.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8231827 + * @summary Pattern variables are non-final. + * @compile/fail/ref=PatternVariablesAreNonFinal.out -XDrawDiagnostics PatternVariablesAreNonFinal.java + */ +public class PatternVariablesAreNonFinal { + public static void main(String[] args) { + Object o = 32; + if (o instanceof String s) { + s = "hello again"; + new Runnable() { + @Override + public void run() { + System.err.println(s); + } + }; + } + System.out.println("test complete"); + } +} diff --git a/test/langtools/tools/javac/patterns/PatternVariablesAreNonFinal.out b/test/langtools/tools/javac/patterns/PatternVariablesAreNonFinal.out new file mode 100644 index 00000000000..c2f3f410a7f --- /dev/null +++ b/test/langtools/tools/javac/patterns/PatternVariablesAreNonFinal.out @@ -0,0 +1,2 @@ +PatternVariablesAreNonFinal.java:38:40: compiler.err.cant.ref.non.effectively.final.var: s, (compiler.misc.inner.cls) +1 error diff --git a/test/langtools/tools/javac/patterns/PatternVariablesAreFinal2.java b/test/langtools/tools/javac/patterns/PatternVariablesAreNonFinal2.java similarity index 74% rename from test/langtools/tools/javac/patterns/PatternVariablesAreFinal2.java rename to test/langtools/tools/javac/patterns/PatternVariablesAreNonFinal2.java index 4925fbd2dc4..2381d4465bc 100644 --- a/test/langtools/tools/javac/patterns/PatternVariablesAreFinal2.java +++ b/test/langtools/tools/javac/patterns/PatternVariablesAreNonFinal2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,11 +24,11 @@ /* * @test * @bug 8231827 - * @summary Pattern variables are final so should be allowed to be referenced in an inner class - * @compile --enable-preview -source ${jdk.version} PatternVariablesAreFinal2.java - * @run main/othervm --enable-preview PatternVariablesAreFinal2 + * @summary Pattern variables can be effectivelly final so should be allowed to be referenced in an inner class + * @compile PatternVariablesAreNonFinal2.java + * @run main PatternVariablesAreNonFinal2 */ -public class PatternVariablesAreFinal2 { +public class PatternVariablesAreNonFinal2 { public static void main(String[] args) { Object o = "42"; if (o instanceof String s) { @@ -36,5 +36,9 @@ public static void main(String[] args) { void run() { System.err.println(s); } }.run(); } + if (o instanceof String s) { + s = "hello again"; + System.out.println(s); + } } } diff --git a/test/langtools/tools/javac/patterns/PatternsSimpleVisitorTest.java b/test/langtools/tools/javac/patterns/PatternsSimpleVisitorTest.java index dec7610f4bf..9d02f17bd25 100644 --- a/test/langtools/tools/javac/patterns/PatternsSimpleVisitorTest.java +++ b/test/langtools/tools/javac/patterns/PatternsSimpleVisitorTest.java @@ -105,7 +105,7 @@ private CompilationUnitTree parse(String code) throws IOException { StringWriter out = new StringWriter(); JavacTask ct = (JavacTask) tool.getTask(out, null, noErrors, - List.of("--enable-preview", "-source", Integer.toString(Runtime.version().feature())), null, + null, null, Arrays.asList(new MyFileObject(code))); return ct.parse().iterator().next(); } diff --git a/test/langtools/tools/javac/patterns/Reifiable.java b/test/langtools/tools/javac/patterns/Reifiable.java index 968138a0ada..966d8b964f9 100644 --- a/test/langtools/tools/javac/patterns/Reifiable.java +++ b/test/langtools/tools/javac/patterns/Reifiable.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8231827 * @summary Verify behavior w.r.t. non-reifiable types and type test patterns in instanceof - * @compile/fail/ref=Reifiable.out --enable-preview -source ${jdk.version} -XDrawDiagnostics Reifiable.java + * @compile/fail/ref=Reifiable.out -XDrawDiagnostics Reifiable.java */ public class Reifiable implements ReifiableI { diff --git a/test/langtools/tools/javac/patterns/Reifiable.out b/test/langtools/tools/javac/patterns/Reifiable.out index 7d4461c9fc6..03d9688a035 100644 --- a/test/langtools/tools/javac/patterns/Reifiable.out +++ b/test/langtools/tools/javac/patterns/Reifiable.out @@ -2,6 +2,4 @@ Reifiable.java:10:16: compiler.err.instanceof.reifiable.not.safe: java.lang.Obje Reifiable.java:12:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Reifiable.List, Reifiable.ListImpl) Reifiable.java:13:39: compiler.err.not.within.bounds: java.lang.String, T Reifiable.java:14:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: Reifiable.List, Reifiable.Unrelated) -- compiler.note.preview.filename: Reifiable.java -- compiler.note.preview.recompile 4 errors diff --git a/test/langtools/tools/javac/patterns/ReifiableOld-old.out b/test/langtools/tools/javac/patterns/ReifiableOld-old.out index 85ea8714e0a..ac56bfa3e1d 100644 --- a/test/langtools/tools/javac/patterns/ReifiableOld-old.out +++ b/test/langtools/tools/javac/patterns/ReifiableOld-old.out @@ -1,7 +1,5 @@ -ReifiableOld.java:12:37: compiler.err.illegal.generic.type.for.instof -ReifiableOld.java:13:38: compiler.err.illegal.generic.type.for.instof -ReifiableOld.java:14:38: compiler.err.illegal.generic.type.for.instof -ReifiableOld.java:15:38: compiler.err.illegal.generic.type.for.instof -ReifiableOld.java:15:39: compiler.err.not.within.bounds: java.lang.String, T -ReifiableOld.java:16:39: compiler.err.illegal.generic.type.for.instof -6 errors +ReifiableOld.java:11:18: compiler.err.feature.not.supported.in.source.plural: (compiler.misc.feature.reifiable.types.instanceof), 15, 16 +ReifiableOld.java:13:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List, ReifiableOld.ListImpl) +ReifiableOld.java:14:39: compiler.err.not.within.bounds: java.lang.String, T +ReifiableOld.java:15:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List, ReifiableOld.Unrelated) +4 errors diff --git a/test/langtools/tools/javac/patterns/ReifiableOld.java b/test/langtools/tools/javac/patterns/ReifiableOld.java index 4ea4bd17919..1cdbd5a8554 100644 --- a/test/langtools/tools/javac/patterns/ReifiableOld.java +++ b/test/langtools/tools/javac/patterns/ReifiableOld.java @@ -2,9 +2,8 @@ * @test /nodynamiccopyright/ * @bug 8231827 * @summary Verify behavior w.r.t. non-reifiable types in instanceof - * @compile/fail/ref=ReifiableOld-old.out -source 13 -Xlint:-options -XDrawDiagnostics ReifiableOld.java - * @compile/fail/ref=ReifiableOld-old.out -source ${jdk.version} -XDrawDiagnostics ReifiableOld.java - * @compile/fail/ref=ReifiableOld.out --enable-preview -source ${jdk.version} -XDrawDiagnostics ReifiableOld.java + * @compile/fail/ref=ReifiableOld-old.out -source 15 -Xlint:-options -XDrawDiagnostics ReifiableOld.java + * @compile/fail/ref=ReifiableOld.out -XDrawDiagnostics ReifiableOld.java */ public class ReifiableOld implements ReifiableOldI { diff --git a/test/langtools/tools/javac/patterns/ReifiableOld.out b/test/langtools/tools/javac/patterns/ReifiableOld.out index 04d84f10201..d43038027f4 100644 --- a/test/langtools/tools/javac/patterns/ReifiableOld.out +++ b/test/langtools/tools/javac/patterns/ReifiableOld.out @@ -1,7 +1,5 @@ -ReifiableOld.java:12:16: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, ReifiableOld.ListImpl -ReifiableOld.java:14:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List, ReifiableOld.ListImpl) -ReifiableOld.java:15:39: compiler.err.not.within.bounds: java.lang.String, T -ReifiableOld.java:16:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List, ReifiableOld.Unrelated) -- compiler.note.preview.filename: ReifiableOld.java -- compiler.note.preview.recompile +ReifiableOld.java:11:16: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, ReifiableOld.ListImpl +ReifiableOld.java:13:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List, ReifiableOld.ListImpl) +ReifiableOld.java:14:39: compiler.err.not.within.bounds: java.lang.String, T +ReifiableOld.java:15:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: ReifiableOld.List, ReifiableOld.Unrelated) 4 errors diff --git a/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.java b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.java index 5ada0240827..db0a58f5c41 100644 --- a/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.java +++ b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.java @@ -2,7 +2,7 @@ * @test /nodynamiccopyright/ * @bug 8187429 8231827 * @summary Missing unchecked conversion warning - * @compile/fail/ref=UncheckedWarningOnMatchesTest.out -Xlint:unchecked -Werror -XDrawDiagnostics --enable-preview -source ${jdk.version} UncheckedWarningOnMatchesTest.java + * @compile/fail/ref=UncheckedWarningOnMatchesTest.out -Xlint:unchecked -Werror -XDrawDiagnostics UncheckedWarningOnMatchesTest.java */ import java.util.ArrayList; diff --git a/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.out b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.out index 447cfff51b3..179bdcf8883 100644 --- a/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.out +++ b/test/langtools/tools/javac/patterns/UncheckedWarningOnMatchesTest.out @@ -1,4 +1,2 @@ UncheckedWarningOnMatchesTest.java:14:13: compiler.err.instanceof.reifiable.not.safe: java.lang.Object, java.util.ArrayList -- compiler.note.preview.filename: UncheckedWarningOnMatchesTest.java -- compiler.note.preview.recompile 1 error diff --git a/test/langtools/tools/javac/patterns/scope/ScopeTest.java b/test/langtools/tools/javac/patterns/scope/ScopeTest.java index 82548fa62c8..1f10fb7dea5 100644 --- a/test/langtools/tools/javac/patterns/scope/ScopeTest.java +++ b/test/langtools/tools/javac/patterns/scope/ScopeTest.java @@ -98,10 +98,7 @@ private void program(String block) { } private void assertOK(String block) { - String sourceVersion = Integer.toString(Runtime.version().feature()); - reset(); - addCompileOptions("--enable-preview", "-source", sourceVersion); program(block); try { compile(); @@ -113,10 +110,7 @@ private void assertOK(String block) { } private void assertFail(String expectedDiag, String block) { - String sourceVersion = Integer.toString(Runtime.version().feature()); - reset(); - addCompileOptions("--enable-preview", "-source", sourceVersion); program(block); try { compile(); diff --git a/test/langtools/tools/javac/preview/classReaderTest/TooNewMajorVersionTest.java b/test/langtools/tools/javac/preview/classReaderTest/TooNewMajorVersionTest.java new file mode 100644 index 00000000000..c3fd0e1d376 --- /dev/null +++ b/test/langtools/tools/javac/preview/classReaderTest/TooNewMajorVersionTest.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8231599 + * @summary Verify javac does not crash on preview classfiles from the future + Java versions. + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.jvm + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run main TooNewMajorVersionTest + */ + +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.TestRunner; +import toolbox.ToolBox; + +import com.sun.tools.javac.jvm.ClassFile.Version; + +import java.io.RandomAccessFile; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +public class TooNewMajorVersionTest extends TestRunner { + + protected ToolBox tb; + + TooNewMajorVersionTest() { + super(System.err); + tb = new ToolBox(); + } + + public static void main(String... args) throws Exception { + TooNewMajorVersionTest t = new TooNewMajorVersionTest(); + t.runTests(); + } + + protected void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void brokenMajorVersionWithPreview(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + class C { + private Object o = null; + private boolean b = o instanceof String s; + } + """); + Path classes = base.resolve("classes"); + + Files.createDirectories(classes); + + for (int upgrade = 1; upgrade < 3; upgrade++) { + new JavacTask(tb) + .outdir(classes) + .options("-XDforcePreview", + "--enable-preview", + "--release", String.valueOf(Runtime.version().feature())) + .files(tb.findJavaFiles(src)) + .run() + .writeAll(); + + Path classfile = classes.resolve("C.class"); + int wrongMajor; + + try (RandomAccessFile f = new RandomAccessFile(classfile.toFile(), "rw")) { + f.readInt(); + short minor = f.readShort(); + if (minor != (-1)) { + throw new AssertionError("Unexpected minor version: " + minor); + } + long point = f.getFilePointer(); + short major = f.readShort(); + f.seek(point); + f.writeShort(wrongMajor = major + upgrade); + } + + Path test = base.resolve("test"); + tb.writeJavaFiles(test, "class Test extends C {}"); + Path testClasses = base.resolve("classes"); + + Files.createDirectories(testClasses); + + for (String extraOption : new String[] {"-XDignored", "--enable-preview"}) { + List log = new JavacTask(tb) + .outdir(testClasses) + .options("-XDrawDiagnostics", + "-classpath", classes.toString(), + "--release", String.valueOf(Runtime.version().feature()), + extraOption) + .files(tb.findJavaFiles(test)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + List expected = List.of( + "Test.java:1:20: compiler.err.cant.access: C, (compiler.misc.bad.class.file.header: C.class, (compiler.misc.wrong.version: " + wrongMajor + ", 65535, " + Version.MAX().major + ", 0))", + "1 error" + ); + if (!log.equals(expected)) + throw new Exception("expected output not found" + log); + } + } + } +} diff --git a/test/langtools/tools/javac/processing/model/element/TestBindingVariable.java b/test/langtools/tools/javac/processing/model/element/TestBindingVariable.java index 7abbf700518..46eecd6ae2a 100644 --- a/test/langtools/tools/javac/processing/model/element/TestBindingVariable.java +++ b/test/langtools/tools/javac/processing/model/element/TestBindingVariable.java @@ -105,20 +105,20 @@ public BindingVariableScanner(Trees trees) { } @Override public Void visitBindingPattern(BindingPatternTree node, Void p) { - handleCurrentTreeAsBindingVar(); + handleTreeAsBindingVar(new TreePath(getCurrentPath(), node.getVariable())); return super.visitBindingPattern(node, p); } @Override public Void visitIdentifier(IdentifierTree node, Void p) { if (node.getName().contentEquals("bindingVar")) { - handleCurrentTreeAsBindingVar(); + handleTreeAsBindingVar(getCurrentPath()); } return super.visitIdentifier(node, p); } - private void handleCurrentTreeAsBindingVar() { - Element element = trees.getElement(getCurrentPath()); + private void handleTreeAsBindingVar(TreePath tp) { + Element element = trees.getElement(tp); System.out.println("Name: " + element.getSimpleName() + "\tKind: " + element.getKind()); diff --git a/test/langtools/tools/javac/records/RecordCompilationTests.java b/test/langtools/tools/javac/records/RecordCompilationTests.java index ee9c99a8e7b..bc3be98c72d 100644 --- a/test/langtools/tools/javac/records/RecordCompilationTests.java +++ b/test/langtools/tools/javac/records/RecordCompilationTests.java @@ -1672,4 +1672,39 @@ record R() implements java.io.Serializable {} removeLastCompileOptions(2); } } + + public void testAnnotationsOnVarargsRecComp() { + assertOK( + """ + import java.lang.annotation.*; + + @Target({ElementType.TYPE_USE}) + @interface Simple {} + + record R(@Simple int... val) { + static void test() { + R rec = new R(10, 20); + } + } + """ + ); + assertOK( + """ + import java.lang.annotation.*; + + @Target({ElementType.TYPE_USE}) + @interface SimpleContainer{ Simple[] value(); } + + @Repeatable(SimpleContainer.class) + @Target({ElementType.TYPE_USE}) + @interface Simple {} + + record R(@Simple int... val) { + static void test() { + R rec = new R(10, 20); + } + } + """ + ); + } } diff --git a/test/langtools/tools/javac/records/RecordsBinaryCompatibilityTests.java b/test/langtools/tools/javac/records/RecordsBinaryCompatibilityTests.java new file mode 100644 index 00000000000..d526dbc4ef2 --- /dev/null +++ b/test/langtools/tools/javac/records/RecordsBinaryCompatibilityTests.java @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary test binary compatibility rules for record classes + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * jdk.compiler/com.sun.tools.javac.code + * jdk.jdeps/com.sun.tools.classfile + * @build toolbox.ToolBox toolbox.JavacTask + * @run main RecordsBinaryCompatibilityTests + */ + +import java.util.*; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.IntStream; + +import com.sun.tools.classfile.*; +import com.sun.tools.javac.code.Flags; +import com.sun.tools.javac.util.Assert; +import toolbox.TestRunner; +import toolbox.ToolBox; +import toolbox.JavaTask; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.Task.OutputKind; + +public class RecordsBinaryCompatibilityTests extends TestRunner { + ToolBox tb; + + RecordsBinaryCompatibilityTests() { + super(System.err); + tb = new ToolBox(); + } + + protected void runTests() throws Exception { + runTests(m -> new Object[]{Paths.get(m.getName())}); + } + + public static void main(String... args) throws Exception { + RecordsBinaryCompatibilityTests t = new RecordsBinaryCompatibilityTests(); + t.runTests(); + } + + Path[] findJavaFiles(Path... paths) throws IOException { + return tb.findJavaFiles(paths); + } + + @Test + public void testCompatibilityAfterAddingRecordComponent(Path base) throws Exception { + testCompatibilityAfterModifyingRecord( + base, + """ + package pkg; + public record R(String i) {} + """, + """ + package pkg; + public record R(String i, String j) {} + """, + """ + package pkg; + public class Client { + public static void main(String... args) { + R r = new R("Hello World!"); + System.out.println(r.i()); + } + } + """, + true, + NoSuchMethodError.class + ); + } + + @Test + public void testCompatibilityAfterDeletingRecordComponent(Path base) throws Exception { + testCompatibilityAfterModifyingRecord( + base, + """ + package pkg; + public record R(String i, String j) { + public R(String j) { + this("Hello World!", j); + } + } + """, + """ + package pkg; + public record R(String j) {} + """, + """ + package pkg; + public class Client { + public static void main(String... args) { + R r = new R("Hi"); + System.out.println(r.i()); + } + } + """, + true, + NoSuchMethodError.class + ); + } + + @Test + public void testCompatibilityAfterChangingRecordComponent(Path base) throws Exception { + testCompatibilityAfterModifyingRecord( + base, + """ + package pkg; + public record R(String i, double j) {} + """, + """ + package pkg; + public record R(String i, int j) {} + """, + """ + package pkg; + public class Client { + public static void main(String... args) { + R r = new R("Hello World!", 1); + System.out.println(r.i()); + } + } + """, + true, + NoSuchMethodError.class + ); + } + + @Test + public void testCompatibilityAfterReorderingRecordComponents(Path base) throws Exception { + testCompatibilityAfterModifyingRecord( + base, + """ + package pkg; + public record R(String i, int j) {} + """, + """ + package pkg; + public record R(int j, String i) {} + """, + """ + package pkg; + public class Client { + public static void main(String... args) { + R r = new R("Hello World!", 1); + System.out.println(r.i()); + } + } + """, + true, + NoSuchMethodError.class + ); + } + + @Test + public void testCompatibilityAfterChangingRecordComponent2(Path base) throws Exception { + testCompatibilityAfterModifyingRecord( + base, + """ + package pkg; + public record R(String j) { + public static String i() { return "Hello World!"; } + } + """, + """ + package pkg; + public record R(String i) {} + """, + """ + package pkg; + public class Client { + public static void main(String... args) { + R r = new R("Hello World!"); + System.out.println(r.i()); + } + } + """, + true, + IncompatibleClassChangeError.class + ); + } + + @Test + public void testCompatibilityAfterChangingRecordComponent3(Path base) throws Exception { + testCompatibilityAfterModifyingRecord( + base, + """ + package pkg; + public record R(String i) { + } + """, + """ + package pkg; + public record R(String j) {} + """, + """ + package pkg; + public class Client { + public static void main(String... args) { + R r = new R("Hello World!"); + System.out.println(r.i()); + } + } + """, + true, + NoSuchMethodError.class + ); + } + + /* 1- compiles the first version of the record class source code along with the client source code + * 2- executes the client class just to make sure that it works + * 3- compiles the second version of the record class + * 4- executes the client class and makes sure that the VM throws the expected error or not + * depending on the shouldFail argument + */ + private void testCompatibilityAfterModifyingRecord( + Path base, + String recordCode1, + String recordCode2, + String clientCode, + boolean shouldFail, + Class expectedError) throws Exception { + Path src = base.resolve("src"); + Path pkg = src.resolve("pkg"); + Path recordSrc = pkg.resolve("R"); + Path client = pkg.resolve("Client"); + + tb.writeJavaFiles(recordSrc, recordCode1); + tb.writeJavaFiles(client, clientCode); + + Path out = base.resolve("out"); + Files.createDirectories(out); + + new JavacTask(tb) + .outdir(out) + .files(findJavaFiles(pkg)) + .run(); + + // let's execute to check that it's working + String output = new JavaTask(tb) + .classpath(out.toString()) + .classArgs("pkg.Client") + .run() + .writeAll() + .getOutput(Task.OutputKind.STDOUT); + + // let's first check that it runs wo issues + if (!output.contains("Hello World!")) { + throw new AssertionError("execution of Client didn't finish"); + } + + // now lets change the record class + tb.writeJavaFiles(recordSrc, recordCode2); + + new JavacTask(tb) + .outdir(out) + .files(findJavaFiles(recordSrc)) + .run(); + + if (shouldFail) { + // let's now check that we get the expected error + output = new JavaTask(tb) + .classpath(out.toString()) + .classArgs("pkg.Client") + .run(Task.Expect.FAIL) + .writeAll() + .getOutput(Task.OutputKind.STDERR); + if (!output.startsWith("Exception in thread \"main\" " + expectedError.getName())) { + throw new AssertionError(expectedError.getName() + " expected"); + } + } else { + new JavaTask(tb) + .classpath(out.toString()) + .classArgs("pkg.Client") + .run(Task.Expect.SUCCESS); + } + } +} diff --git a/test/micro/org/openjdk/bench/java/io/DataOutputStreamTest.java b/test/micro/org/openjdk/bench/java/io/DataOutputStreamTest.java new file mode 100644 index 00000000000..2e63268f12d --- /dev/null +++ b/test/micro/org/openjdk/bench/java/io/DataOutputStreamTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020, Red Hat Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.java.io; + +import org.openjdk.jmh.annotations.*; + +import java.io.*; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MICROSECONDS) +@Fork(value = 1, warmups = 0) +@Measurement(iterations = 6, time = 1) +@Warmup(iterations=2, time = 2) +@State(Scope.Benchmark) +public class DataOutputStreamTest { + + public enum BasicType {CHAR, SHORT, INT, STRING} + @Param({"CHAR", "SHORT", "INT", /* "STRING"*/}) BasicType basicType; + + @Param({"4096"}) int size; + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(size); + File f; + String outputString; + FileOutputStream fileOutputStream; + DataOutput bufferedFileStream, rawFileStream, byteArrayStream; + + @Setup(Level.Trial) + public void setup() throws Exception { + f = File.createTempFile("DataOutputStreamTest","out"); + fileOutputStream = new FileOutputStream(f); + byteArrayStream = new DataOutputStream(byteArrayOutputStream); + rawFileStream = new DataOutputStream(fileOutputStream); + bufferedFileStream = new DataOutputStream(new BufferedOutputStream(fileOutputStream)); + outputString = new String(new byte[size]); + } + + public void writeChars(DataOutput dataOutput) + throws Exception { + for (int i = 0; i < size; i += 2) { + dataOutput.writeChar(i); + } + } + + public void writeShorts(DataOutput dataOutput) + throws Exception { + for (int i = 0; i < size; i += 2) { + dataOutput.writeShort(i); + } + } + + public void writeInts(DataOutput dataOutput) + throws Exception { + for (int i = 0; i < size; i += 4) { + dataOutput.writeInt(i); + } + } + + public void writeString(DataOutput dataOutput) + throws Exception { + dataOutput.writeChars(outputString); + } + + public void write(DataOutput dataOutput) + throws Exception { + switch (basicType) { + case CHAR: + writeChars(dataOutput); + break; + case SHORT: + writeShorts(dataOutput); + break; + case INT: + writeInts(dataOutput); + break; + case STRING: + writeString(dataOutput); + break; + } + } + + @Benchmark + public void dataOutputStreamOverByteArray() throws Exception { + byteArrayOutputStream.reset(); + write(byteArrayStream); + byteArrayOutputStream.flush(); + } + + @Benchmark + public void dataOutputStreamOverRawFileStream() throws Exception { + fileOutputStream.getChannel().position(0); + write(rawFileStream); + fileOutputStream.flush(); + } + + @Benchmark + public void dataOutputStreamOverBufferedFileStream() throws Exception{ + fileOutputStream.getChannel().position(0); + write(bufferedFileStream); + fileOutputStream.flush(); + } +} diff --git a/test/micro/org/openjdk/bench/java/lang/invoke/VarHandleExact.java b/test/micro/org/openjdk/bench/java/lang/invoke/VarHandleExact.java new file mode 100644 index 00000000000..1b5e4f77601 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/lang/invoke/VarHandleExact.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.lang.invoke; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(org.openjdk.jmh.annotations.Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(3) +public class VarHandleExact { + + static final VarHandle exact; + static final VarHandle generic; + + static { + try { + generic = MethodHandles.lookup().findVarHandle(Data.class, "longField", long.class); + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + exact = generic.withInvokeExactBehavior(); + } + + Data data; + + static class Data { + long longField; + } + + @Setup + public void setup() { + data = new Data(); + } + + @Benchmark + public void exact_exactInvocation() { + exact.set(data, (long) 42); + } + + @Benchmark + public void generic_genericInvocation() { + generic.set(data, 42); + } + + @Benchmark + public void generic_exactInvocation() { + generic.set(data, (long) 42); + } +} diff --git a/test/micro/org/openjdk/bench/java/util/Base64Encode.java b/test/micro/org/openjdk/bench/java/util/Base64Encode.java new file mode 100644 index 00000000000..297f216eb49 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/util/Base64Encode.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020, Huawei Technologies Co. Ltd. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.micro.bench.java.util; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import java.util.Base64; +import java.util.Random; +import java.util.ArrayList; +import java.util.concurrent.TimeUnit; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +public class Base64Encode { + + private Base64.Encoder encoder; + private ArrayList unencoded; + private byte[] encoded; + + private static final int TESTSIZE = 1000; + + @Param({"1", "2", "3", "6", "7", "9", "10", "48", "512", "1000", "20000"}) + private int maxNumBytes; + + @Setup + public void setup() { + Random r = new Random(1123); + + int dstLen = ((maxNumBytes + 16) / 3) * 4; + + encoder = Base64.getEncoder(); + unencoded = new ArrayList (); + encoded = new byte[dstLen]; + + for (int i = 0; i < TESTSIZE; i++) { + int srcLen = 1 + r.nextInt(maxNumBytes); + byte[] src = new byte[srcLen]; + r.nextBytes(src); + unencoded.add(src); + } + } + + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testBase64Encode(Blackhole bh) { + for (byte[] s : unencoded) { + encoder.encode(s, encoded); + bh.consume(encoded); + } + } +} diff --git a/test/micro/org/openjdk/bench/jdk/incubator/foreign/VarHandleExact.java b/test/micro/org/openjdk/bench/jdk/incubator/foreign/VarHandleExact.java new file mode 100644 index 00000000000..ec920b90ae8 --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/incubator/foreign/VarHandleExact.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.jdk.incubator.foreign; + +import jdk.incubator.foreign.MemoryHandles; +import jdk.incubator.foreign.MemorySegment; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.TearDown; +import org.openjdk.jmh.annotations.Warmup; + +import java.lang.invoke.VarHandle; +import java.nio.ByteOrder; +import java.util.concurrent.TimeUnit; + +import static jdk.incubator.foreign.MemoryLayouts.JAVA_INT; + +@BenchmarkMode(Mode.AverageTime) +@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS) +@State(org.openjdk.jmh.annotations.Scope.Thread) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@Fork(value = 3, jvmArgsAppend = { "--add-modules", "jdk.incubator.foreign" }) +public class VarHandleExact { + + static final VarHandle exact; + static final VarHandle generic; + + static { + generic = MemoryHandles.withStride(MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()), 4); + exact = generic.withInvokeExactBehavior(); + } + + MemorySegment data; + + @Setup + public void setup() { + data = MemorySegment.allocateNative(JAVA_INT); + } + + @TearDown + public void tearDown() { + data.close(); + } + + @Benchmark + public void exact_exactInvocation() { + exact.set(data.baseAddress(), (long) 0, 42); + } + + @Benchmark + public void generic_genericInvocation() { + generic.set(data.baseAddress(), 0, 42); + } + + @Benchmark + public void generic_exactInvocation() { + generic.set(data.baseAddress(), (long) 0, 42); + } +} diff --git a/test/micro/org/openjdk/bench/vm/compiler/VectorShiftAccumulate.java b/test/micro/org/openjdk/bench/vm/compiler/VectorShiftAccumulate.java new file mode 100644 index 00000000000..d9c729f56a0 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/VectorShiftAccumulate.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2020, Huawei Technologies Co. Ltd. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; + +import java.util.concurrent.TimeUnit; +import java.util.Random; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.NANOSECONDS) +@State(Scope.Thread) +public class VectorShiftAccumulate { + @Param({"1028"}) + public int count; + + private byte[] bytesA, bytesB, bytesD; + private short[] shortsA, shortsB, shortsD; + private char[] charsA, charsB, charsD; + private int[] intsA, intsB, intsD; + private long[] longsA, longsB, longsD; + + @Param("0") + private int seed; + private Random r = new Random(seed); + + @Setup + public void init() { + bytesA = new byte[count]; + shortsA = new short[count]; + charsA = new char[count]; + intsA = new int[count]; + longsA = new long[count]; + + bytesB = new byte[count]; + shortsB = new short[count]; + charsB = new char[count]; + intsB = new int[count]; + longsB = new long[count]; + + bytesD = new byte[count]; + shortsD = new short[count]; + charsD = new char[count]; + intsD = new int[count]; + longsD = new long[count]; + + for (int i = 0; i < count; i++) { + bytesA[i] = (byte) r.nextInt(); + shortsA[i] = (short) r.nextInt(); + intsA[i] = r.nextInt(); + longsA[i] = r.nextLong(); + + bytesB[i] = (byte) r.nextInt(); + shortsB[i] = (short) r.nextInt(); + intsB[i] = r.nextInt(); + longsB[i] = r.nextLong(); + } + } + + @Benchmark + public void shiftRightAccumulateByte() { + for (int i = 0; i < count; i++) { + bytesD[i] = (byte) (bytesA[i] + (bytesB[i] >> 1)); + } + } + + @Benchmark + public void shiftURightAccumulateByte() { + for (int i = 0; i < count; i++) { + bytesD[i] = (byte) (bytesA[i] + (((byte) (bytesB[i] >>> 3)))); + } + } + + @Benchmark + public void shiftRightAccumulateShort() { + for (int i = 0; i < count; i++) { + shortsD[i] = (short) (shortsA[i] + (shortsB[i] >> 5)); + } + } + + @Benchmark + public void shiftURightAccumulateChar() { + for (int i = 0; i < count; i++) { + charsD[i] = (char) (charsA[i] + (charsB[i] >>> 4)); + } + } + + @Benchmark + public void shiftRightAccumulateInt() { + for (int i = 0; i < count; i++) { + intsD[i] = intsA[i] + (intsB[i] >> 2); + } + } + + @Benchmark + public void shiftURightAccumulateInt() { + for (int i = 0; i < count; i++) { + intsD[i] = (intsB[i] >>> 2) + intsA[i]; + } + } + + @Benchmark + public void shiftRightAccumulateLong() { + for (int i = 0; i < count; i++) { + longsD[i] = longsA[i] + (longsB[i] >> 5); + } + } + + @Benchmark + public void shiftURightAccumulateLong() { + for (int i = 0; i < count; i++) { + longsD[i] = (longsB[i] >>> 2) + longsA[i]; + } + } +} + diff --git a/test/micro/org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.java b/test/micro/org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.java new file mode 100644 index 00000000000..0605050ed2a --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.bench.vm.compiler.overhead; + +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; + +import java.util.concurrent.TimeUnit; +import java.util.Arrays; + +/** + * The purpose of these microbenchmarks is to use RepeatCompilation + * to produce a benchmark that focuses on the overhead of various JIT + * compilations themselves. + */ + +@State(Scope.Benchmark) +@BenchmarkMode(Mode.SingleShotTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@Fork(value = 10, warmups = 1) +public class SimpleRepeatCompilation { + + public static final String MIXHASH_METHOD + = "-XX:CompileCommand=option,org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.mixHashCode,intx,RepeatCompilation,500"; + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch", MIXHASH_METHOD}) + public int mixHashCode_repeat() { + return loop_hashCode(); + } + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch", "-XX:-TieredCompilation", MIXHASH_METHOD}) + public int mixHashCode_repeat_c2() { + return loop_hashCode(); + } + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch", "-XX:TieredStopAtLevel=1", MIXHASH_METHOD}) + public int mixHashCode_repeat_c1() { + return loop_hashCode(); + } + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch"}) + public int mixHashCode_baseline() { + return loop_hashCode(); + } + + public int loop_hashCode() { + int value = 0; + for (int i = 0; i < 1_000_000; i++) { + value += mixHashCode("simple_string"); + } + return value; + } + + public int mixHashCode(String value) { + int h = value.hashCode(); + for (int i = 0; i < value.length(); i++) { + h = value.charAt(i) ^ h; + } + return h; + } + + public static final String TRIVIAL_MATH_METHOD + = "-XX:CompileCommand=option,org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.trivialMath,intx,RepeatCompilation,2000"; + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch",TRIVIAL_MATH_METHOD}) + public int trivialMath_repeat() { + return loop_trivialMath(); + } + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch", "-XX:-TieredCompilation", TRIVIAL_MATH_METHOD}) + public int trivialMath_repeat_c2() { + return loop_trivialMath(); + } + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch", "-XX:TieredStopAtLevel=1", TRIVIAL_MATH_METHOD}) + public int trivialMath_repeat_c1() { + return loop_trivialMath(); + } + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch"}) + public int trivialMath_baseline() { + return loop_trivialMath(); + } + + public int loop_trivialMath() { + int value = 0; + for (int i = 0; i < 1_000_000; i++) { + value += trivialMath(i, i - 1); + } + return value; + } + + public int trivialMath(int a, int b) { + return a * b + a; + } + + + public static final String LARGE_METHOD + = "-XX:CompileCommand=option,org/openjdk/bench/vm/compiler/overhead/SimpleRepeatCompilation.largeMethod,intx,RepeatCompilation,100"; + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch",LARGE_METHOD}) + public int largeMethod_repeat() { + return loop_largeMethod(); + } + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch", "-XX:-TieredCompilation", LARGE_METHOD}) + public int largeMethod_repeat_c2() { + return loop_largeMethod(); + } + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch", "-XX:TieredStopAtLevel=1", LARGE_METHOD}) + public int largeMethod_repeat_c1() { + return loop_largeMethod(); + } + + @Benchmark + @Fork(jvmArgsAppend={"-Xbatch"}) + public int largeMethod_baseline() { + return loop_largeMethod(); + } + + public int loop_largeMethod() { + int value = 0; + for (int i = 0; i < 50_000; i++) { + value += largeMethod(i, i - 1); + } + return value; + } + + // Meaningless but largish method with plenty of locals + // to put more stress on register allocation + public int largeMethod(int a, int b) { + int c = b + 17; + int d = a + b + 6; + int e = c + d + 99; + int f = d + e + 919; + long val = 0; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + a -= b; + b += c; + c -= d; + d += e; + e -= a; + val = a - b + c - d + e - f; + } + } + } + int g = b; + int h = a; + int l = c; + int m = d; + int n = d; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + g += b; + h -= c; + l += d; + m -= e; + e += a; + val = g + h + l + m + n; + } + } + } + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + a -= b; + b += c; + c -= d; + d += e; + e -= a; + val = a - b - c - d - e - f; + } + } + } + int o = b; + int p = a; + int q = c; + int r = d; + int s = d; + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + o += b; + p += c; + q += d; + r += e; + s += a; + val = o + p + q + r + s; + } + } + } + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + g += b; + h -= c; + l += d; + m -= e; + e += a; + val = g + h + l + m + n; + } + } + } + return (int)(val ^ (val >> 32L)); + } +}